Securely storing scriptable credentials in the OSX Keychain

Often I find myself needing to repeatedly access a service that is password protected. A good example would be trying to curl an end point that is behind basic auth, another is dealing with projects that expect global variables with access credentials in them. There are armies of bots out there, scraping Github, just waiting for someone to accidentally commit some credentials to a public repository. There have also been a short list of clients that for one reason or another required me to connect to the root account of some server using password based access. Oh, the things we do for our clients.

My solution to this problem is to never store any credential in a local configuration file. Since I do the majority of my work on OSX machines I’ve begun storing any credentials I need to access programmatically inside the Keychain. We can access the Keychain using the built in security utility.

Store a password in the Keychain

security add-generic-password -U -a <account_name> -s <service_name> -w <password>

Retrieve a password from the Keychain

security find-generic-password -ga <account_name> -w

The security command is very well documented here Security Man Page

As an example, we can see how I might handle a script that needs access to the Openstack API. This is what a generic Openstack RC file looks like.

export OS_USERNAME=username
export OS_TENANT_NAME=projectName
export OS_AUTH_URL=https://identityHost:portNumber/v2.0
export OS_TENANT_ID=tenantIDString
export OS_REGION_NAME=regionName
export OS_CACERT=/path/to/cacertFile
export OS_PASSWORD=password

While most of that information is fairly benign, there is a password hanging out right there at the end. We can normally fix it by doing something like this.

echo "What is your password"
read supersekret
export OS_PASSWORD=$supersekret

But If you are dealing with tons of Openstack tenants across several installations, good luck remembering them all without writing them down somewhere, and you stil have to provide the passowrd the first time you access the api in a particular shell.

So here is an example of the above script using the OSX Keychain instead. It is certanly more verbose, but with a little effort and a helper function or two can whittle this down to a trivial amount of ceremony each time you need to do it.

#get the password from the keychain
supersekret=$(security find-generic-password -ga ${os_account_name} -w)
#if the security command does not run sucessfully, prompt
if [ $? -gt 0 ]; then
  echo "What is your password"
  read supersekret
  security add-generic-password -U -a ${os_account_name} -s    ${os_service_name} -w ${$supersekret}
export OS_PASSWORD=$supersekret

Remember, play safe kids!

Spread the word

twitter icon facebook icon linkedin icon