Lion Server Profile Manager: First Day Experiences

Today I finally had the time to begin experimenting with Profile Manager built into Mac OS X Lion Server. Apple's documentation is extremely poor to say the least, so that has forced me to make some assumptions based solely on discoveries of my own throughout the day. If any of them are wrong, please leave a comment and let me know otherwise.

Here's what I found.

Setup

The setup process for Profile Manager and the MDM server bundled into it is extremely easy.

  1. Ensure proper DNS and then setup the server to be an Open Directory Master. 
  2. Create a new self-signed certificate and use that to generate a CSR for a real CA. We use Entrust here at RMU. 
  3. Submit your CSR, get a real, valid, SSL certificate and then replace the self-signed cert with the one signed by your CA of choice. 
  4. Install any intermediate certificates and then select the new cert to be the primary one for the server. 
  5. Click the "Edit" button next to "Device Management" on the Profile Manager pane of Server.app and go through the steps, one of which being the process of acquiring an Apple Push Notification Sevice (APNS) certificate. 
  6. Check the box for "Sign configuration profiles" and use the self-signed OD CA Code Signing Certificate, or purchase a real code-signing certificate from a CA (not really necessary). 
  7. If you want to change the name of the global settings for everyone profile, do that.
  8. Turn on Profile Manager.

Initial "Oooh Ahh" factor

After Profile Manager lets you know it's fully ready for use, you can access it as an admin at https://server.example.com/profilemanager

After logging in, you're presented with an "oh wow this is pretty" website. But imemdiately after the "wow" factor wears off is when you're left hoping for more detailed documentation. Similarly to Workgroup Manager, it's clear that you can assign profiles at the User, Group, Computer, or Computer Group level. Clicking around the various groups and users shows it's not very difficult to build different profiles for respectively different groups. However, there's no documentation on levels of precidence nor on how conflicting settings will interact. Initial testing by Arek Dreyer shows that Device profiles tend to take precedince over User or User Group profiles. Also gone is the concept of "Always", "Often", "Once", and "Never". Things applied through the use of Profiles essentially are always at the "Always" level of persistency. 

Things that should be documented

  1. By default, everyone is in the "Everyone" group. The "Everyone" group has the option checked to allow members of the group to "Enable Remote Management" under "Portal Access." This means that by default, everyone can enroll their devices into Profile Manager; probably not what you want to have enabled. It also means that trying to turn off the ability to enroll devices is greyed out at the user level. Disabling the option at the group level then of course unlocks the ability to set it per-user.
  2. Only admins can see Enrollment profiles when logged in to the user portal.
  3. You cannot pre-associate a user with a device. Therefore profiles configured for devices and device groups will never show as available for download in the user portal. Only user and user group profiles will show.
  4. Along with number 3, if you set a profile's distribution type to "Manual Download," it will only show in the list in the user portal if it is a user or user group profile, not a device or device group profile.
  5. Along with number 3 and 4, if a device or device group profile distribution method is set to "Manual Download", the only way to get access to these is to download them as an admin through the admin portal and distribute them via some other means. They will never be shown in the user portal.
  6. There is currently no way to lock trust profiles or device management profiles. Only configuration profiles. This means an admin user can easily remove their device from device management.
  7. Why anyone would ever need more than two, a "Restricted" and and an "Unrestricted", enrollment profiles. The only option for enrollment profiles is whether or not the computer is required to be in the devices list prior to enrolling. Maybe I'm not understanding these properly, but here at RMU I imagine I'd only ever use a Restricted Enrollment Profile? Perhaps I'd want more if I want a more granular view of the "Usage" of the particular enrollment profile?

Bugs I found

  1. My trust profile didn't immediately show in the user portal as available for download. In Server.app, even though it was already selected, I had to select the code-signing OD CA self-signed certificate again and profile manager rewrote the settings.  It then became available for download. This happens after every restart of the Profile Manager service.
  2. My trust profile is named "Trust profile for" but is missing the domain or name of the server. Running "sudo serveradmin settings devicemgr:server_organization = fqdn.example.com has no effect.
  3. Using Firefox 7 with the admin web interface presented some problems. Active tasks wouldn't change to completed unless I reloaded manually. Safari also had some issues with this, but less often.
  4. When manually importing a plist to the "Custom Settings" section of a profile, you're unable to delete more than one key out of that plist at a time. Pressing shift or command to select multiple items does not work. For example, if you import the Safari plist but only need the HomePage key, you'll be there for quite awhile clicking "delete" on the unneeded keys. As a workaround, write a plist to your desktop with the same name only containing the keys you need. Then upload that.
  5. There is no way to resize the columns in the "Activity" panes in the admin portal. There is a lot of available screen space but the web app keeps the columns super tiny.

Overall first day experiences

A lot of bugs. A lot of confusion. Shit poor documentation. The best third-party resource I currently know of is Arek Dreyer's presentation at MacSysAdmin 2011. Listen to his presentation; it has a lot of good sidenotes.

Remote wipe and remote lock are both cool. Note that remote lock immediately reboots the machine; there is no prompt and no opportunity to save.

If this is the tool that Apple wants us to use to replace MCX and Workgroup Manager, it's got a long way to go. MCX is well understood and has extremely detailed documentation. We sys admins don't just want to know how to do something, we want to know WHY it works the way it does and what to do when it doesn't. This was my favorite line from the Apple Profile Manager documentation:

To send the URL of the Profile Manager server to a user so they can log in and download the configuration profiles you assigned to them, click the arrow next to Visit User Portal, then copy the URL from the browser window that opens.

Thank you, Apple, for that extremely helpful lesson on copying and pasting. I could have never figured that out by myself!

I'll leave off with this. Profile Manager's logging isn't so bad. But often it says this:

Oct 19 16:19:54 server.example.com ProfileManager[13678] <Info>: Processing MagicController#do_magic (for ip.ad.dr.ess at 2011-10-19 16:19:54) [POST]

Do Magic through the MagicController, huh? I'd really like to know what that is.

Friends in cupertino...

Profile Manager | Editing a custom imported plist | Deleting Multiple Keys
rdar://problem/10317006

Profile Manager | Activity Panes | Unable to resize/wrongly sized columns
rdar://problem/10317034

Profile Manager | Trust profile unavailable for download after service restart
rdar://problem/10317052

Profile Manager | Trust profile missing organization name
rdar://problem/10317107

Profile Manager | Add ability to lock trust and enrollment profiles
rdar://problem/10317143

Profile Manager | Updates to documentation
rdar://problem/10317170

 

Posted
 

Using The Luggage with Apps that have spaces in their names

Recently when trying to build a package using The Luggage, I noticed that it would choke on apps that had spaces in their names. Doing some searching, I discovered that making it work is as simple as adding a custom stanza to the makefile for each app/file that has a space. The package I was making was a custom installer for RMU's new VMware View remote access system. It included Microsoft's "Remote Desktop Connection", VMware's "VMware View Client", a postflight scipt to write the "view.rmu.edu" entry to a preference file, and a custom welcome message and background for the installer.

Here's my makefile:

include /usr/local/share/luggage/luggage.make

TITLE=RMU_VMware_View
REVERSE_DOMAIN=edu.rmu
PAYLOAD=unbz2-application-Remote_Desktop_Connection.app \
        unbz2-application-VMware_View_Client.app \
        pack-script-postflight \
        pack-resource-Welcome.rtf \
        pack-resource-background.gif
PACKAGE_VERSION=1

unbz2-application-Remote_Desktop_Connection.app: Remote_Desktop_Connection.app.tar.bz2 l_Applications
        @SUDO ${TAR} xjf Remote_Desktop_Connection.app.tar.bz2 -C ${WORK_D}/Applications
        @SUDO chown -R root:admin "${WORK_D}/Applications/Remote Desktop Connection.app"

unbz2-application-VMware_View_Client.app: VMware_View_Client.app.tar.bz2 l_Applications
        @SUDO ${TAR} xjf VMware_View_Client.app.tar.bz2 -C ${WORK_D}/Applications
        @SUDO chown -R root:admin "${WORK_D}/Applications/VMware View Client.app"

Notice that instead of the usual "unbz2-applications-XXXX.app" I used "unbz2-application-xxxx.app" and included those stanzas in the Makefile itself. Note the quotes around the names in the chown lines. The pack-xxx stanzas came from the included luggage.make file; it's not necessary to reproduce these in your makefile, so long as the files don't include spaces in their names.

Hope this helps someone!

Posted
 

Setting Asterisk 1.8 Caller ID from Legacy PBX Systems

Unfortunately we still have numbers registered to our old Nortel PBX. After many trials, we have been unsuccesful at passing the caller ID name from the Nortel PBX to our Asterisk systems.  We implemented the following solution/workaround into the [stdexten] subroutine.

After
exten => _X.,n,Set(LOCAL(mbx)="${ext}"$["${cntx}" ? "@${cntx}" :: ""])
but before
exten => _X.,n,Dial(${dev},20)                  ; Ring the interface, 20 seconds maximum
we added this line:

exten => _X.,n,Set(CALLERID(name)=${IF(${DB_EXISTS(cidname/${CALLERID(num)})}?${DB(cidname/${CALLERID(num)})}:${CALLERID(name)})})

That line checks to see if there is an Asterisk database entry for the caller ID number in the database family "cidname". We've loaded all of our Nortel users' names and extensions into astdb. If there is an entry in the databse, that line overrides whatever is in sip.conf or whatever, if anything, is coming over the wire.

Here's an example. Let's say I have a phone registered at extension 1000 with the caller ID line set to "Mike Boylan" <1000> in sip.conf. If I do the following, the caller ID will be changed when I dial (to any number that uses stdexten) to "Legacy PBX CID".

asterisk7*CLI> database put cidname 1000 "Legacy PBX CID"
Updated database successfully

asterisk7*CLI> database show cidname
/cidname/1000                                     : Legacy PBX CID 

You can see in the console that when I dial, the CID Name was changed:

asterisk7*CLI>
  == Using UDPTL CoS mark 5
  == Using SIP RTP CoS mark 5
    -- Executing [4805@rmuld:1] Gosub("SIP/1000-00000085", "4805,stdexten(SIP/4805)") in new stack
    -- Executing [4805@rmuld:50000] NoOp("SIP/1000-00000085", "Start stdexten") in new stack
    -- Executing [4805@rmuld:50001] Set("SIP/1000-00000085", "LOCAL(ext)=4805") in new stack
    -- Executing [4805@rmuld:50002] Set("SIP/1000-00000085", "LOCAL(dev)=SIP/4805") in new stack
    -- Executing [4805@rmuld:50003] Set("SIP/1000-00000085", "LOCAL(cntx)=") in new stack
    -- Executing [4805@rmuld:50004] Set("SIP/1000-00000085", "LOCAL(mbx)="4805"""") in new stack
    -- Executing [4805@rmuld:50005] Set("SIP/1000-00000085", "CALLERID(name)=Legacy PBX CID") in new stack
    -- Executing [4805@rmuld:50006] Dial("SIP/1000-00000085", "SIP/4805,20") in new stack
  == Using UDPTL CoS mark 5
  == Using SIP RTP CoS mark 5
    -- Called SIP/4805
    -- SIP/4805-00000086 is ringing
  == Spawn extension (rmuld, 4805, 50006) exited non-zero on 'SIP/1000-00000085'

If you can get your legacy PBX systems to send Caller ID information, including the name, to Asterisk, great. But if you're like us and struggle to do so, this is a very reasonable workaround. Your users will never know, nor do they care, how the CID information is being set.

Posted
 

Inception Style Installation of CS 5.5 Master Collection

Adobe Application Manager Enterprise Edition is a great tool for sys admins that need to manage Creative Suite installations. It allows sys admins to disable EULA and registration reminders, kill off Adobe Air, turn off updates, etc. The only problem with the tool is that the packages it produces, although technically native Apple PKGs, really are not. There's no feedback given during install time as the package is essentially just a massive script copying files. The other problem is that AAMEE packages are extremely slow to install. Using Munki for my images this year, I noticed the initial bootstrapping of a machine was taking upwards of an hour to complete, with more than a half an hour of that time dedicated to the Creative Suite installation. I wanted to fix that.

Problem: Installing Creative Suite (CS) 5.5, all of the additional content, and all of the current CS 5.5 updates was taking, cumulatively, 31 minutes. That was accounting for more than half of the bootstrapping time of a new machine being configured with Munki.

What I did: I launched Composer on a machine that was freshly imaged. I pointed Munki to a manifest file that only included the Creative Suite installation (including the extra content and updates) and allowed it to do its thing. For 31 minutes or so. After Creative Suite was finished installing, I created a package in Composer based on what was installed.

Essentially, I made a Composer package of a Munki installation of an AAMEE generated Creative Suite Package. Inception much?

The results: The Composer built package, which includes the entire Creative Suite, all of the extra content, and all of the updates takes only 13 minutes to install using Munki. That's almost 60% faster than having Munki install the AAMEE packages.

Was the extra time spent repackaging the Munki installation of an AAMEE generated Creative Suite Package worth it? Absolutely. It will significantly cut the time required to bootstrap a new machine.

EDIT: Everyone should also read the comment below by Greg Neagle. Fortunately what he describes does not affect my environment at Robert Morris, but it may very well affect yours. 

Posted
 

Snow Leopard Static Mapper - Version 1.0

In response to a thread on the Mac OS X Server mailing list, I took it upon myself to write a small application that can assist Mac OS X Server administrators in creating static DHCP mappings to be imported into Server Admin.

 

This application was written to be a Snow Leopard compatible replacement for Scott Finney's "Leopard Static Map Importer". The functionality is the same with the only difference being the exported plist is able to be imported into a Snow Leopard server. The code base is my own. Scott had nothing to do with this project nor does this imply any endorsement from Scott as a replacement for his application.

 

Screen_shot_2011-07-03_at_5

 

The application is lightweight and was written in AppleScript Objective-C.

Version 1.0 can be downloaded here:

http://mboylan.me/2X1r0U2o2d1y2w0w102Z

 

Please read the included Read Me file for more information and for how to contact me to report bugs.

 

Feedback is heavily welcomed. If this helps you, please let me know!

 

If you came here from the mailing lists... the build I posted to the lists was actually static "Mappper" with three P's! An extra feature! It works the same, but if the extra P annoys you, download the new build above.

 

Posted
 

Installing Universal Type Client 3.0 with Munki

Edit the file Universal\ Type\ Client\ 3.0.mpkg/Contents/Packages/universalTypeClient.pkg/Contents/Resources/postflight

Change it to look like this:

#!/bin/bash

#set the permissions on the application bundle
sudo chmod -R 775 "$2/Universal Type Client.app"

#set the ownership of the application bundle
sudo chown -R "root:admin" "$2/Universal Type Client.app"

#create UTC directory...
if [ ! -d "/Library/Extensis" ]; then
        sudo mkdir "/Library/Extensis"        
fi

sudo chmod -R 777  "/Library/Extensis"

#create UTC directory...
if [ ! -d "/Library/Extensis/UTC" ]; then
        sudo mkdir "/Library/Extensis/UTC"        
fi

sudo chmod -R 777  "/Library/Extensis/UTC"

#copy the corecli app to the /usr/bin directory and change the permissions on it to: 755
#Doing this instead of adding it to the PackageMaker project because editing the project can cause "bad" stuff like the "relocatable bundle" issue.
if [ -e "$2/Universal Type Client.app/Contents/Resources/corecli" ]; then
        if [ -e "/usr/bin/corecli" ]; then
                sudo ditto --rsrc "$2/Universal Type Client.app/Contents/Resources/corecli" "/usr/bin/corecli"
                sudo chmod 755 "/usr/bin/corecli"
        fi
fi

Same thing as before. Just removing all the code that makes assumptions that shouldn't be made.

Posted
 

Simplifying Frequently Changing IVR Menus in Asterisk 1.8

Many organizations use IVR menus in their phone systems. Certainly we've all heard something like "Thank you for calling Robert Morris University. Please press...". One inherent problem with these menus is that they're generally not easy to maintain -- especially the ones that change frequently. The people that have "control" over these menus generally are able to record new files, but the replacement of the sound files is often a manual process.

Using astdb (or any other database engine asterisk can talk to), the process of managing frequently changing sound files can be simplified.

Using some code snippets I found on the web, along with some of my own brain power, I've put together this early working version of a simple IVR menu changing application. Essentially how it works is each sound file in the menus are assigned an ID and passcode. Every user who can record new sound files also is given a username and password in the "ariusers" context in Voicemail.conf. After authenticating as an allowed user, they then must enter the ID and password of the sound file they'd like to change. When recording is finished, the user is able to listen back at the new sound file, accept it, or rerecord it. After that, they're prompted whether or not they'd like to change another file. If not, the system says thank you and hangs up. On hangup it moves the temp audio file into the right place with the right name that is already referenced in the dialplan.

You'll want to insert two kinds of values into the Asterisk database. Auth values and name values. Example:

asterisk -r -x 'database put recname 64101 isc_64101_thankyou'; sleep 1;
asterisk -r -x 'database put recauth 64101 1234'; sleep 1;

Once your values are inserted and matched to sound files, here's the dialplan code to make this work. Any questions or comments, please post them.

[globals]
; Must be writable by the user running the asterisk process... usually "asterisk"
CUSTOM_RECORDINGS=/var/lib/asterisk/sounds/en/custom

; Somewhere in the dialplan
exten => 5000,1,Gosub(RecordPrompt,${EXTEN},1)

; The special subroutine that makes this all work
[RecordPrompt]
; Handles extension changes over time
exten => _[A-Za-z0-9].,1,NoOp()

; Can this user even use this feature?
same => n,Read(UserID,custom/welcome-user-id);
same => n,VMAuthenticate(${UserID}@ariusers,s);

; Get which message they want to change
same => n(getmessage),Read(MessageID,custom/enter-message-id,5,,,1)
same => n,Read(MessagePWD,custom/enter-message-pwd,4)
same => n,Set(ValidMessagePWD=${DB(recauth/${MessageID})})
same => n,GotoIf($['${MessagePWD}' = '${ValidMessagePWD}']?prerec)
same => n,Playback(option-is-invalid)
same => n,Goto(getmessage)

; This will be our filename
same => n(prerec),Set(RecordedFilename=${DB(recname/${MessageID})})
same => n,Set(RandomNumber=${RAND()})

; Record the prompt
same => n(record),Playback(custom/say-message)
same => n,Wait(1)
same => n,Record(${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav)

; Ask how we want to handle the recording
same => n(handle_recording),Read(ActionItem,vm-review,1)

; Verify we got values we expect
same => n,GotoIf($['${ActionItem}' = '1' | '${ActionItem}' = '2' | '${ActionItem}' = '3']?valid_action)
same => n,Playback(option-is-invalid)
same => n,Goto(handle_recording)

same => n(valid_action),NoOp()
; Handle the recording
; 1 accept, 2 review, 3 re-record
same => n,GotoIf($['${ActionItem}' = '1']?accept) ; keep this recording
same => n,GotoIf($['${ActionItem}' = '3']?record)   ; re-record it

; If we get here they pressed 2
same => n,Playback(${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber})
same => n,Goto(handle_recording)

; Recording accepted, move from tmp to permanent
same => n(accept),Verbose(2,Recording accepted!)
same => n,System(mv ${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav ${GLOBAL(CUSTOM_RECORDINGS)}/${RecordedFilename}.wav)
same => n,Playback(custom/message-updated)

; Do they want to rerecord another message?
same => n(recordanother),Read(RecordAnother,custom/record-another,1)
same => n,GotoIf($['${RecordAnother}' = '1']?getmessage)
same => n,Playback(option-is-invalid)
same => n,Goto(recordanother)

; On hangup remove the tmp file
exten => h,1,Verbose(2,Cleanup the file)
same => n,System(rm -f ${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav)
Posted
 

Installing Extensis Universal Type Client 2.1 with Munki

The postflight script for the UTC Preference Pane references environment variables not present when using Munki.

If you're planning to use the UTC installer with Munki, you'll need to modify the postflight script inside the following folder:

Universal\ Type\ Client\ 2.1.mpkg/Contents/Packages/utcoreprefpane.pkg/Contents/Resources

Here's my replacement:

--------------------
#!/bin/bash
#set proper permissions on the prefpane
sudo chmod -R 555 "/Library/PreferencePanes/utcore-prefpane.prefPane"

#This USED to set something in the /L/P domain to the user who installed it first.
#We're using root:admin as that's how things in the /L/P domain should normally be set
#set ownership of the prefpane

sudo chown -R root:admin "/Library/PreferencePanes/utcore-prefpane.prefPane"
---------------------

Notice the removals of the environment variables at the top as well as the addition of the login item at the end of the script. You'll need to add the UTC Helper App as a login item for your users some other way. I recommend using MCX. 

Posted
 

Video - Configuring DNS in Mac OS X Server 10.6

This is a follow up to my previous post. I had some requests for a screencast, so I made one.

(download)

Posted
 

DNS Doesn't Have to be WTF

This post is going to be tailored more towards Mac OS X system admins, but a good foundational understanding of DNS is something that is good for all system admins to have. Mac OS X admins especially need to have a good understanding of DNS as most problems they'll encounter will stem from improperly configured DNS. DNS is something that is often misconstrued as something enormously complex. Sure, DNS can get complicated, there's no denying that. But the basics are relatively easy. Understanding DNS to the point where you can make your OS X server(s) happy doesn't have to, and shouldn't leave you, saying "WTF?"

DNS at 30,000'

DNS stands for Domain Name System. I like to think of it as the phonebook for the internet. When you look in a phonebook, you generally look for someone's name to find their phone number. DNS forward lookups do essentially the same thing. DNS forward lookups translate names, such as rmu.edu, into IP addresses (rmu.edu has IP 66.206.178.109). When you type http://www.rmu.edu into your browser, it's DNS that's telling your browser what rmu.edu translates to. DNS reverse lookups translate IP addresses into hostnames (66.206.178.109 translates into ww2.rmu.edu). Mac OS X Server services such as Open Directory, Server Admin, Mail, iCal, iChat, and more rely heavily upon having both proper forward and reverse DNS. When OS X admins report DNS problems to their Windows colleagues or network admins, they generally get the response, "Well it's working for our Windows servers." In that situation, generally the problem is that reverse DNS is broken. Windows doesn't rely much at all on reverse DNS so problems in that area tend to hide themselves. On the contrary, again, Mac OS X Server heavily relies on having both proper forward and reverse DNS.

DNS is structured in that each domain has a set of authoritative name servers. Those name servers host the "zone files" for the domain that contain the record information. Those authoritative servers can then in turn assign other authoritative name servers for their subdomains. There can be secondary, or slave, name servers for each domain and subdomain as well. The distributed nature of DNS provides fault tolerance and scalability. Allowing each domain to have its own authoritative servers has also removed the need for there to be a central DNS registrar continuously updating with everyone's records. Imagine that nightmare.... It's not incredibly important to understand how the structure of DNS works starting all the way from the top (the root), but do know that there is a DNS root zone which is the top level DNS zone in the DNS hierarchy. The zone is managed by IANA which is managed by ICANN. From there, there are zone servers for the top level domains such as edu, org, com, etc.

DNS has two main types of queries -- Recursive Queries and Iterative Queries. Recursive queries are usually made by a client host/resolver (such as your machine). The queried name server (most often provided through DHCP by an ISP) is asked to respond with the requested data or with an error stating that data of the requested type or the domain name asked for doesn't exist. The name server cannot just refer the querier to a different name server. Forwarders sort of aleviate that problem by allowing DNS requests to "pass" from one DNS server onto another. If a DNS server is configured to use a forwarder, the request from the queried DNS server to the forwarder is also a recursive query. In an iterative query, the queried name server gives the best answer it currently has back to the querier. This type of query is typically done by a DNS server to other DNS servers after it has received a recursive query from a client host/resolver.

DNS queries are essentially read right to left starting with the right-most (top-level) domain label. A common misconception is that http://www.rmu.edu is a fully-qualified domain name, or FQDN. It's not. http://www.rmu.edu. is. Notice the trailing dot, indicating the root zone. Try typing any of your favorite websites into your browser with a trailing dot. Notice they'll still load. This trailing dot is implied. DNS caching is used these days to lighten, and almost completely alleviate, the load on the root servers. But essentially, a DNS query for http://www.rmu.edu. works like this: 

- A query is made to one of the root servers (.) to find the server authoritative for the top-level domain (TLD) (edu).
- A query then is made to the obtained TLD server (for edu) for the IP address of the DNS server(s) authoritative for the second-level domain (rmu).
- The previous step repeats for each domain name label in sequence until the final step. The final step returns the IP address of the website or host originally queried for.

DNS has something called records, the most common of which are A (address) records. There are tons of different kinds of records, but the most commonly used records by Mac OS X system admins are A records, PTR records, and CNAME records. 'A' records are what define your hosts/machines/devices. For example, if test.example.com had IP address 10.1.1.11 and was in DNS, there'd be an A record for a host called "test" with an IP address 10.1.1.11. PTR records are used for reverse DNS (which remember are crucial for OS X Server). In the 1.1.10.in-addr.arpa. zone, there'd be a PTR record that translated test back to 10.1.1.11. The actual PTR record for test would be 11.1.1.10.in-addr.arpa. (notice it's backwards). The in-addr.arpa. domain is a special domain used for reverse DNS. CNAME records are canonical names which are essentially aliases. For example, you could have a CNAME record for test2.example.com that pointed to test.example.com.

With that high level overview of DNS, now we can start exploring how it works in Mac OS X 10.6 Snow Leopard, and how to configure it properly in Snow Leopard Server. For more information about the information discussed above, see Wikipedia's entry on DNS and don't be afraid to traverse some of the links. It's fascinating stuff. The DNS and BIND book from O'Reilly is also excellent. For the serious nerds, check out the RFCs.

DNS Changes in Snow Leopard

Before talking about how to configure DNS in Snow Leopard Server, there's some important DNS architectural changes to mention that were made in Mac OS X Snow Leopard. Mac OS X Snow Leopard uses a process called mDNSResponder to do both unicast and multicast DNS queries. There's an excellent article on afp548.com about all of the changes made in Snow Leopard, but here's the most important:

- Your search order in system preferences doesn't actually matter. You're telling the system where to look, but it doesn't necessarily look in the order you specify.
Manually specifying a DNS server in system preferences will cause the system to ignore any DNS servers supplied via DHCP
-  
dig, host and nslookup all do direct DNS queries and have their own resolvers. dig, host, and nslookup output could possibly show different results from what you're seeing in applications and through behavior.
- Related to the previous, be sure to use dscacheutil in addition to the tools above when troubleshooting DNS. The syntax is: dscacheutil -q host -a name <name here> or dscacheutil -q host -a ip_address <ip here> to test reverse.
- sudo dscacheutil -flushcache isn't always enough to clear the DNS cache in Snow Leopard. Send a HUP to mDNSresponder: sudo killall -HUP mDNSResponder 

Configuring DNS in Mac OS X Server 10.6.x Snow Leopard

When you go through the setup assistant of Snow Leopard Server, one of the screens asks you for the hostname and name of the server you're configuring. If your institution already has DNS in place, just have your network admin(s) create an A record and a PTR record for your server. The PTR record is important!! Assuming they did that for you, after having put in the address information on the previous screen (manually configured, of course), it should automatically populate these fields and you should be set to go. Nothing more is required. You don't need to run DNS yourself if it's already running properly on your network. If they can't do that for you, ask them if you can become authoritative for a new subdomain in your organization. 

The following assumes that a, either your network team is unable to give you proper DNS, or b, you want to become authoritative over your own subdomain, such as mac.example.com so you have more control over the hosts under your level of management. At Robert Morris University, I made myself authoritative over the mactest.rmu.edu and mac.rmu.edu domains. Doing so has helped things immensely as we have a DNS spaghetti of both BIND and Active Directory provided DNS.

At the screen shown below, enter the hostname you'd like your machine to have such as testserver.mac.example.com. If you have no FQDN for your organization (say you're doing this at home, for example), you can always use something like testserver.private. Just please... please... do not use .local. Whether you're going the subdomain.example.com route or the .private route, all of the following steps are essentially the same.

Initial Setup Screen

Setupscreen
On the following screen, I always choose Configure Manually. If you choose Create Users and Groups you will get a premade OD master that may or may not have proper DNS settings. This guide assumes you choose configure manually. Choosing "Create Users and Groups" is essentially the same thing as Configuring Manually, setting up DNS properly, and then turning on Open Directory to the Master role.

Configure Manually

Configuremanually
If you configure manually and want to set up Open Directory, I suggest skipping the option that says "Setup an Open Directory Master." You can always do that later.

Go through the rest of the setup as normal. When finished, launch Server Admin and go to the DNS pane. It should be the only one there and it should be on. If for some reason it's not on or there, you can go to the Services pane of Server Admin and choose to show it from there. When you click on DNS, you'll see the following screen.

Warning -- Don't Touch Me

Serveradmininitialdns

You'll see that Server Admin is warning you that touching the DNS settings could cause problems. Let's ignore that message. 

What Server Admin has done is made self resolving zones just for your particular host. It's also set the DNS server in System Preferences to 127.0.0.1. This essentially ensures that from the start, there can be no DNS problems. At this point in time, your server is authoritative for a zone named after itself and has a record for itself in the in-addr.arpa. domain for reverse. 

Initial Server Admin Zones

Initialzones

I'm going to change these zones to become authoritative for the entire mac.example.com domain. If you're using .private, you'll simply become authoritative over the entire private domain. As that's an internal use only domain, there's no problem there.

Be absolutely certain that you're not trying to take authority over a domain in your organization that already exists. You need to make sure from your networking team that you're a, allowed to run DNS on your network, and b, assuming you can, for what domain/subdomain can you be authoritative.

For my example, I'm going to become authoritative over the entire mac.example.com domain. To do this, I need to modify the zone files. First I'll remove the reverse zone by highlighting it and pressing the (-) button.

Reverse Zone Removed

Reverseremoved

I'll then remove the primary zone. 

IMPORTANT -- DO NOT PRESS SAVE AT THIS POINT

Primary Zone Removed

Bothzonesremoved
Now I need to remake my primary zone. This will be mac.example.com.. Note the trailing dot. If you're doing private, your zone would be named private..

Remaking the Primary Zone

Remakingprimaryzone
Where it says "Nameservers:" click the plus button. It should automatically populate with the correct values.

The final step in configuring the new zones is to add the A record for your machine. Click on the zone and click "Add Record>>Add Machine (A)."

Adding the new A Record

Addingnewarecord
Notice that Server Admin automatically created a Reverse Zone for my machine. Expanded, the new zones look like this.

New Zones, Expanded

Newzonesexpanded

If you click on the reverse record, you'll see how it maps back.

Reverse Record

Reverserecord

At this stage, it's time to verify that everything looks correct. You should have a new Primary Zone named what you chose to be authoritative over. For my example it was mac.example.com.. For you, it might be private.. Within that Primary Zone you should have an A record matching your statically assigned IP address. You should have a Server Admin auto generated reverse zone and reverse record pointing to your machine.

Almost Done...

Newfinishedzones
At this point, when you're sure everything looks correct, go ahead and press Save.

In System Preferences, make sure your current DNS server is set to either 127.0.0.1 or your static IP address, or both separated by a comma. If you want to be able to do DNS lookups against just hostnames and not FQDNs of your machines, also add your domain to your search path.

System Preferences

Systempreferences

Note that I'm working in a VM with host-only networking. In production, I'd have the interface set to full Manual mode.

Now it's time to verify everything is correct!

The following commands should be used to test:
dscacheutil -q host -a name <host name>
dscacheutil -q host -a ip_address <ip address>
dig <host name>
dig -x <ip address>
nslookup <host name>
nslookup <ip address> 

(download)

And finally, last but not least, the most important and powerful Mac OS X Server command there is, sudo changeip -checkhostname. It should say "The names match. There is nothing to change." If it doesn't, something is misconfigured. Go back and check.

sudo changeip -checkhostname

Changeip
If everything looks good, you're all set! (For some reason the OS X install didn't give my VM a hardware UUID. I can safely ignore the top part of that message.)

On Your Way...

At this point you should have a general understanding of how DNS works and you should have successfully configured the DNS service using Mac OS X Server 10.6 Snow Leopard.

The DNS service runs under the process 'named' and uses the following files/directories:
/etc/resolv.conf
/etc/named
/etc/dns
/var/named/
/var/named/zones

If you explore the /var/named/zones directory, you'll notice zone files that correspond to your zones in Server Admin ending with a .zone.apple suffix. If you look in /var/named you'll see zone files that correspond to your zones without the .zone.apple suffix. These zone files in /var/named are the real zone files. Examining one shows that it includes the ones generated by Server Admin. If you need to make manual changes to DNS that are more complex than what Server Admin can offer, put the changes in the /var/named zone files. These won't get overwritten and won't make Server Admin unhappy. Note however, that your changes will not be displayed in Server Admin.

At this point, your server most likely can't resolve anything in the outside world. You can either add your institution's other DNS servers to the Forwarder IP Addresses list on the Settings tab of the DNS pane in Server Admin, or if this is your only DNS server, use something like Google's DNS servers 8.8.8.8 and 8.8.4.4 as forwarders. They accept recursive queries and should work.

That's all, folks!

Thanks for reading! Hopefully this post was helpful. If there's any questions, please post them below and I'll do my best to answer them in a timely fashion.

Posted