Big Note: This document was written for v10.2, and so is now depreciated.

This document aims to clearly describe the configuration of Mac OS X Server and Mac OS X to achieve the following:
  • The server will host a network netinfo domain accessible via ldap.
  • The client will bind to this domain using ldap, and log in with a network user account.
  • The client will automount a network home directory from the server via afp.
  • All the ldap transactions will be through SSL. This includes setting up a demo certificate authority, generating the cert requests, signing them, and properly configuring the client and server to use the new certificate.
These directions assume that you're starting with a freshly configured server. One thing to watch out for is that sometimes the server will come up with a hostname of 'localhost' the first time it's rebooted, after you've gone through the setup assistants. Reboot again so that the hostname as reported in a terminal shell prompt is correct.

Setting up a network netinfo domain with automounts

  1. Launch Open Directory Assistant on the server and proceed with the following options (note: this configuration can also be accomplished using the command line tool NeST):
    • This server your.host.name at 1.2.3.4 is using a permanent IP address and subnet. Choosing the other option here prevents you from continuing. It is useful also prior to a reconfiguration of a Mac OS X Server, in order to remove references to network domains and other values which might change (such as IP address).
    • This server will provide directory information to other computers. This creates a network netinfo database.
    • Enable LDAP support on this server (checked)
    • Password and authentication information will be provided to other systems. This fires up password server and sets the admin account to use the password server.
    • Accept the default set of enabled encrypted authentication protocols
    • Reboot

  2. Launch Workgroup manager, and connect to the server
    • Make sure that you're operating in the network netinfo domain (choose "/Netinfo/root" from the popout menu at the bottom left of the workgroup manager window. If you don't have that option, try step 1 again. Also, you can use sudo NeST -getparentconfig to verify that Open Directory Assistant did its job - if it did, it'll report itself as a netinfo and ldap parent.)
    • Click the Sharing button, select the Users share point, and set it to automount to clients in Netinfo/root dynamically, via afp.
    • Click the Accounts button, and create an account which will be your network user.
    • To provide the network home directory, set the network user's home to Network, select the automounted Users share point (you have to click on it, grey highlight does not mean selected...), and click Save.

  3. Before we can configure the client, we need to find the LDAP search base that the server is using. We can find this in the /machines directory of the parent netinfo domain by executing the following on the server:
    [pimp:/etc] root# nicl / -list /machines
    2          pimp.dreness.com
    [pimp:/etc] root# nicl / -read /machines/pimp.dreness.com
    name: pimp.dreness.com
    ip_address: 216.231.49.47
    serves: ./network pimp.dreness.com/local
    suffix: dc=dreness,dc=com
    
    First we get the exact machine name of the server as it exists in netinfo, then we list the contents of that record. My search base in this example is dc=dreness,dc=com.

  4. Configure Directory Access on the client machine to include the network netinfo domain.
    • Launch Directory access on the client machine, select LDAPv3, and click configure
    • Click the disclosure triangle if necessary, then click "New..." to create a new entry
      • Configuration Name = LDAP
      • Server Name or IP Address = 1.2.3.4, --use your server's IP or hostname
      • LDAP Mappings = Open Directory Server. When prompted for the search base, use the results from the previous step (e.g. dc=dreness,dc=com).
      • Click the Edit button if you have not already to reveal the LDAP timeout settings; change them to something a bit more reasonable. This makes it less frustrating when it doesn't work as expected.
      • Click "Use authentication when connecting", and supply the credientials of your network user as follows: Distinguished Name: uid=username,cn=users,dc=dreness,dc=com (where dc=dreness,dc=com is the search base you found from the previous step, and username is... well... you know ;). In the password field, put the user's regular ol' password.
      • Leave SSL off for now.
    • Click OK until you return to the main Directory Access window
    • Click the Authentication tab, choose "Custom Path" from the Search popout, click the Add... button, and add the LDAP entry you just created to the search path

  5. Use Server Settings to verify that Guest Access is enabled for AFP

  6. At this point you should reboot the client and verify that you can log in as the network user you created earlier with Workgroup Manager. The network user's home directory should be created automatically; alternatively you can use sudo createhomedir -a on the server to pre-create it. Also, though we have configured authenticated LDAP binding on the client, we have not yet disabled anonymous binding on the server

Creating a Certificate Authority, creating certificate requests, and signing the requests

A Certificate Authority allows us to sign ssl certificate requests, in lieu of paying for a real ssl certificate from one of the various authorities (verisign, etc). Most of the ssl work involves use of the openssl command; however, included with the OpenSSL distribution is a perl script called CA.pl which simplifies the process a little. The following is a condensed version of http://www.post1.com/home/ngps/m2/howto.ca.html:

  1. Create a directory in root's home directory called demoCA. Copy openssl.cnf and CA.pl into this directory:
    [pimp:~] root# mkdir demoCA
    [pimp:~] root# cp /System/Library/OpenSSL/openssl.cnf demoCA/
    [pimp:~] root# cp /System/Library/OpenSSL/misc/CA.pl demoCA/
  2. Create a new Certificate Authority. When prompted, press enter to create a new authority. The PEM pass phrase is required later to sign certificates with this authority. * * * Common Name should be your server's fully qualified domain name * * *(e.g. pimp.dreness.com).
    [pimp:~] root# cd demoCA/
    [pimp:~/demoCA] root# ./CA.pl -newca
    CA certificate filename (or enter to create) [enter]
    
    Making CA certificate ...
    Using configuration from /System/Library/OpenSSL/openssl.cnf
    Generating a 1024 bit RSA private key
    ............................................++++++
    .......++++++
    writing new private key to './demoCA/private/cakey.pem'
    Enter PEM pass phrase: [passphrase]
    Verifying password - Enter PEM pass phrase: [passphrase]
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:US
    State or Province Name (full name) [Some-State]:Washington
    Locality Name (eg, city) []:Seattle
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:EarthGov
    Organizational Unit Name (eg, section) []:dreness
    Common Name (eg, YOUR name) []:pimp.dreness.com
    Email Address []:dre@mac.com
  3. Create a certificate request. We could use CA.pl -newreq, but this generates an encrypted private key, which isn't what we want, since this is intended to be used on an unattended server (I believe this would require manually entering a passphrase to start up the ssl services). Instead, we'll create a new request manually and use the -nodes option to openssl (which I believe is read "no des", as in DES encryption). This means that you must securely store the resulting private key contained in newreq.pem. Also, just press enter on the 'extra' attributes.
    [pimp:~/demoCA] root# openssl req -new -nodes -keyout newreq.pem -out newreq.pem
    Using configuration from /System/Library/OpenSSL/openssl.cnf
    Generating a 1024 bit RSA private key
    .............++++++
    .............................................................................++++++
    writing new private key to 'newreq.pem'
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:US
    State or Province Name (full name) [Some-State]:Washington
    Locality Name (eg, city) []:Seattle
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:EarthGov
    Organizational Unit Name (eg, section) []:dreness
    Common Name (eg, YOUR name) []:pimp.dreness.com
    Email Address []:dre@mac.com
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []: [enter]
    An optional company name []: [enter]
    [pimp:~/demoCA] root# ls
    CA.pl       demoCA      newreq.pem  openssl.cnf

  4. Next we sign the certificate with the demo certificate authority we've created. We will be prompted for the PEM pass phrase; this is the one supplied when we created the certificate authority.
    [pimp:~/demoCA] root# ./CA.pl -sign
    Using configuration from /System/Library/OpenSSL/openssl.cnf
    Enter PEM pass phrase:
    Check that the request matches the signature
    Signature ok
    The Subjects Distinguished Name is as follows
    countryName           :PRINTABLE:'US'
    stateOrProvinceName   :PRINTABLE:'Washington'
    localityName          :PRINTABLE:'Seattle'
    organizationName      :PRINTABLE:'EarthGov'
    organizationalUnitName:PRINTABLE:'dreness'
    commonName            :PRINTABLE:'pimp.dreness.com'
    emailAddress          :IA5STRING:'dre@mac.com'
    Certificate is to be certified until May 20 07:01:48 2004 GMT (365 days)
    Sign the certificate? [y/n]:y
    
    
    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated
    Signed certificate is in newcert.pem
    [pimp:~/demoCA] root# ls
    CA.pl       demoCA      newcert.pem newreq.pem  openssl.cnf

Configuring SSL on the client and server

Okay, almost there. All that's left is to move the various ssl keys / authority files into their proper homes, and tweak a couple config files to add references to the newly placed files.

On the server:
  • Copy newreq.pem to /etc/openldap, and rename it to serverkey.pem. Also, secure this file
    [pimp:~/demoCA] root# cp newreq.pem /etc/openldap/serverkey.pem
    [pimp:~/demoCA] root# chmod 600 /etc/openldap/serverkey.pem
  • Copy newcert.pem to /etc/openldap, calling it servercert.pem
    [pimp:~/demoCA] root# cp newcert.pem /etc/openldap/servercert.pem
  • Copy cacert.pem (inside the demoCA folder) to /etc/openldap
    [pimp:~/demoCA] root# cp demoCA/cacert.pem /etc/openldap
  • Edit /etc/openldap/slapd.conf to include the following three lines (I put them at the end):
    TLSCACertificateFile /etc/openldap/cacert.pem
    TLSCertificateFile /etc/openldap/servercert.pem
    TLSCertificateKeyFile /etc/openldap/serverkey.pem
    Also, insert the following line at the top of the file to require authenticated binding:
    disallow bind_anon
  • Kill the slapd process and restart it in debug mode so that it listens for secure connections in addition to regular ones.
    [pimp:~/demoCA] root# ps auxww | grep  slap
    root    1264   0.0  0.1    36820    840  ??  Ss   12:49PM   0:00.30 slapd
    root    1815   0.0  0.0     1144    156 std  R+    4:24PM   0:00.00 grep slap
    [pimp:~/demoCA] root# kill 1264
    [pimp:~/demoCA] root# /usr/libexec/slapd -d1 -h "ldap:/// ldaps:///"
    -d1 produces quite a bit of output, most of which is largly unintelligable to me :) You should see 'slapd starting' at the very bottom - this is a good sign. We'll leave it running in debug mode for now.

On the client:
  • Copy the cacert.pem file from the server, and place it in /etc/openldap
    andre@bish[~]sudo scp admin@pimp:/etc/openldap/cacert.pem /etc/openldap
    Password:
    admin@pimp's password: 
    cacert.pem           100% |************************************************************|  1289       00:00
  • Edit /etc/openldap/ldap.conf to add the following:
    TLS_CACERT /etc/openldap/cacert.pem
  • Launch Directory Access again, and configure the LDAPv3 plugin
  • Check the SSL checkbox for the LDAP configuration we created previously

That should do it :) Reboot the client and log in as the network user. You should see a whole bunch of scrolling debug output from slapd as the login occurs. If you see any errors, that might be okay.. I have noticed some lines which are apparently non-fatal errors. I've included a dump of the debug output from a functional LDAP / ssl login, so that you may compare to mine (865 KB).

The last thing to do is edit the LDAP startup item so that it starts up able to service ldaps requests. This is accomplished by editing the LDAP startup item, in /System/Library/StartupItems/LDAP. In the LDAP script, below the line that contains "Startup LDAP Server", change slapd to slapd -h "ldap:/// ldaps:///". The StartService block should appear as follows:
StartService ()
{
    ##
    # Start up LDAP server
    ##
    if [ "${LDAPSERVER:=-NO-}" = "-YES-" ]; then
        if ! pid=$(GetPID slapd); then
            ConsoleMessage "Starting LDAP server"
            slapd -h "ldap:/// ldaps:///"
        fi
    fi
}
If you want to force SSL binding, then it should be
slapd -h "ldaps:///"
Shutdown the client, reboot the server, boot the client, and log in as the network user to double-check everything. That's it!

Footnotes

I should mention that I really don't know a whole lot about the inner workings of either LDAP or SSL (or cryptography for that matter). These steps have been carefully crafted from my experience delivering Apple's Mac OS X Server Administration & Integration course, and also from information I gathered about creating a certificate authority. Anybody looking to incorporate this kind of stuff into a production environment would do well to test it heavily first. My testing setup is:
  • Powermac G4 Dual 800 running Mac OS X Server, developed and tested in 10.2.4, tested from scratch in 10.2.6
  • iBook G3 500, running Mac OS X 10.2.6
  • Airport networking for the iBook
Some highly unscientific numbers: it takes around 30 seconds to log in as a network user from the iBook for the first time after a boot (the time from pressing return at the login screen until the finder is finished loading). Subsequent logins in the same boot session take a little over 10 seconds. I'd like to say this might be faster if the iBook were hardwired instead of on Airport, but when watching server bandwidth during login, the highest burst seems to be only about 8 KB/s... (it's just challenge / response type stuff, so there shouldn't be a heavy network hit).

References:
http://www.bayour.com/LDAPv3-HOWTO.html
http://www.post1.com/home/ngps/m2/howto.ca.html

Comments or questions can be sent to me at dre@mac.com.