I use Open Directory a lot, I can’t think of many times when I don’t use it at least once a day in some way whether that be direct or indirect. It’s not the best directory system out there – hell, it’s not even very good but it’s what the fine people at Apple have supplied us with and it’s what I use. Although I have long had a pet peeve with the way OD is built if you just run through the setup wizard. The certificate expires in one year. Almost every time I encounter an OD server in the wild nine times out of ten the certs are a mess. They’re either expired or about to expire and all the services that depend on them are freaking out. The clients are constantly being prompted to accept an invalid cert and OD fail-over tends to stop working. My solution has been to build a certificate authority for all my OD installs and to build my own certs that are valid for ten years, that way I won’t have to worry about them expiring and let’s be honest there’s no Mac server on the planet that’s going to last ten years lol (sense the cynicism yet?)
Create the Root Key
First we’re going to hop into a terminal on any Mac OS X box and navigate to somewhere safe in the file system and build the master key, make sure the password you use for this is kept secret and safe.
mkdir -p myCA/cert myCA/key
openssl genrsa -aes256 -out key/ca.key.pem 4096
chmod 400 key/ca.key.pem
That OpenSSL command is going to ask you a bunch of questions, answer them to the best way you see fit and for the common name put the organization that you’re building this certificate authority for. Do not put an actual domain. Record what you wrote for Common Name because we’re going to need it later. Whitespaces are allowed. Oh and one more pro tip, make sure the value of the certificate common is unique and can’t be half-matched. For example I made a root cert called “Client Name” but when it came to do deploy the certificate via munki, the check install script found a cert called “Client Name Open Directory” and thus the command matched and wouldn’t deploy the new root cert.
Create the Root Cert
openssl req -key key/ca.key.pem -new -x509 -days 3650 -sha256 -extensions v3_ca -out cert/cert.pem
chmod 444 cert/cert.pem
Now we have two files.
cert/cert.pem – This is your CA’s certificate and can be publicly available and of course world readable. You will need to load this certificate into all the clients in your network.
key/ca.key.pem – This is your CA’s private key. Although it is protected with a passphrase you should restrict access to it, so that only root can read it.
Create the First Server key/cert combo
We can now start creating SSL certificates for our various servers and services. Create a directory named a hostname corresponding to the hostname for the computer or service you are creating the certificate for.
Create the first key
openssl genrsa -aes256 -out hostname/hostname.domainname.key 4096
While answering the questions for this make sure you type in the FQDN for server or service you want to secure into Common Name.
Create the server cert
openssl req -new -key hostname/hostname.domainname.key -out hostname/hostname.domainname.csr
Sign the cert
openssl x509 -req -days 3650 -in hostname/hostname.domainname.csr -CA cert/cert.pem -CAkey key/ca.key.pem -set_serial 01 -out hostname/hostname.domainname.crt
Now before we continue I have to drill into you that it’s imperative that you document these certs as you make them, which hosts they’re deployed on to, and what the serial number is. It will help you in the long run.
Finally we’re going to make a passwordless version of the server key, this is the key that we’ll ultimately use on our server. We need a passwordless key so that the Mac OS X services do not need human intervention when trying to use the certs. Otherwise you’ll have to type the cert password in every time you restart the service.
openssl rsa -in hostname/hostname.domainname.key -out hostname/hostname.domainname.key.insecure
mv hostname/hostname.domainname.key hostname/hostname.domainname.key.secure
mv hostname/hostname.domainname.key.insecure hostname/hostname.domainname.key
Import the CA and Cert
Copy the myCA/cert.pem, hostname/hostname.domainname.key, and hostname/hostname.domainname.crt files to your Mac OS X server. Double click on the myCA/cert.pem, this should open the file with Keychain Access which will ask you which keychain to import the cert to. Select the system keychain and then double click on the entry in Keychain Access and set the trust setting to Always Trust.
Next open Server.app and click on Certificates. Click on the gear menu and select Import Certificate Identity. Drag in the hostname/hostname.domainname.key, and hostname/hostname.domainname.crt files, when you do this you should see that the files are signed by the organization that you entered in step one. Finally select the cert from the list of certs in server.app and give it time to switch over.
Finally fire up the wiki service in server.app, whip open your browser of choice and connect to the FQDN that you create the SSL cert for. Remember, if your cert common name doesn’t match the way you address the wiki in the URL bar you will get a hostname mismatch error. You MUST make sure the names match from what you type into the certificate’s common name and how you connect to the wiki.
Root Cert Deployment
So now maybe you want to be able to use this cert with some of your clients right? You can do this a multitude of ways. Such as:
Copy the file to /tmp across your network and run the following command as root
security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "/tmp/cert.pem"; srm "/tmp/cert.pem"
Or if you’re cool you’ll use some sort of package deployment system. I use munki because it’s not backed by some money hungry corporation. Here’s looking at you Cohen. 😉 To do this I made a new package with Composer dropped my root cert into /tmp and then wrapped then finished the Composer wizard. Import this package into munki using munkiimport and then drop aforementioned command into post-install script.
For extra bonus points it would be cool to see if the root cert is installed before we go pushing this package to all the workstations in the network. To do this I added a little check install script to munki. Note that you have change the -c flag to match whatever you wrote for the root cert common name way back in step one.
security find-certificate -c "Root Cert Common Name" /Library/Keychains/System.keychain
if [ $? != 0 ]; then
You’ll note that the exit codes are reversed here, it’s because Munki will only install if the check install script exits on 0 which is how our security check command will exit if it finds the cert installed. So we flip the exit code to make munki do our bidding.
At this point you should be feeling like a rock star for the following reasons:
- You haven’t given Go Daddy any money
- You’ve successfully built and deployed your own cert authority
- You won’t have to worry about onboarding new machines with the cert cause you’ve got in munki