Houston, we have LaunchAgent

By Erik, Tue, 10/11/2016 - 18:06


So, I went ahead and upgraded to Sierra yesterday. A few folks had attempted to upgrade and had not had too many issues, so I went with it. Very smooth update for the most part, the machine had to reboot a couple of times before I felt like it was done, but that's fine.

One thing that did change, however, was the lack of my Keychain enabled private keys to be loaded into my ssh-agent when the computer rebooted.

$ ssh-add -l
The agent has no identities.

After a bit of googling, I came across some posts that all basically said:

That’s expected. We re-aligned our behavior with the mainstream OpenSSH in this area. You can fix this pretty easily by running ssh-add -A in your rc script if you want your keys to always be loaded.

So, every time you reboot your machine, you need to have the equivalent of ssh-add -A run. You can still store your credentials in the Keychain (ssh-add -K) and load them all automatically (ssh-add -A), but you have to run that last step every time you log in.

At first I simply added the line to my .bash_profile so that it would happen automatically, but that led to ssh-add trying to add them every time I opened a terminal window and started a new bash session. While it doesn't actually hurt, it seemed a little overkill. One or more of the articles mentioned creating a .plist file and storing it in your ~/Library/LaunchAgents directory.


Launch agents are programs that launch for a specific user when the system starts and are run as that user. This is similar to a LaunchDaemon which is run at startup, but as root and not affiliated with any specific logged in user.

The format of a plist file is a simple XML definition that can easily be read on startup. You can read all about them on the launchd Tutorial website. The biggest caveat I came to was that while trying to understand the difference between ProgramArguments and Program key elements. Turns out that for most circumstances, you don't need or actually want Program but need to know that the first element in the ProgramArguments array will be used as the "thing to run". Consider the following plist file:


This seems like it would run touch with the argument of "/tmp/foo", but it actually simply calls /tmp/foo directly and touch is effectively ignored. I found a very nice blog post that explained the intricacies with the various details of execvp(3).

So with that knowledge, I created a plist file that I saved as ~/Library/LaunchAgents/com.openssh.ssh-add.plist with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

This runs as soon as the system reboots and loads all of the keys that are stored in Keychain Access with no problem. So now I have a clean update to Sierra and learned something about launchd.