Last year, Venda released a project to create and manage a simple x509
PKI using Chef and Chris Andrews introduced it with his blog post,
“Deploying a PKI With Chef”.
A few people tried out it out after the initial release
(and submitted patches or bug reports – thankyou!), and it has since
been renamed to become the x509 cookbook, which you can find
on the community site
or on github.
I’ve found it useful of late, so let’s take another look.
What’s The Problem?
You’ve decided to SSL-enable one of your internal services, and that
means you need an x509 certificate. The cheapest and easiest option
generate a self-signed certificate,
but this option is not without drawbacks.
When you connect to a service using a self-signed certificate, you can
be confident that your communication is encrypted, but you can’t be
sure who you’re communicating with. You are protected from attackers
“sniffing” data from an insecure network, but not from attackers
creating a fake service in front of the one you expect to connect to (a
It’s also annoying to users, as most software will (rightly!) warn you
that self-signed certificates are not to be trusted.
A better option is to run an internal Certificate Authority, and use
that to sign the certificates for your SSL-enabled services. You can
import your CA’s certificate into your browser (or OS), which will
then trust services using certificates that it has signed.
It’s not hard to make your own CA, but getting a signed certificate
for your service necessarily involves a number of steps:
On the host, generate a secret key and a certificate signing request (CSR)
Get the CSR to the internal CA
Create a signed certificate using the CSR and the internal CA
Get the signed certificate to the host
Install the signed certificate
Venda wanted to automate this process and the result is the x509
cookbook, and the chef-ssl-client gem.
Note: these tools work with chef-client and the Chef server –
chef-solo is not supported.
To create and manage a CA, we will be using the chef-ssl utility.
It loads your knife configuration to determine how to connect to the
Chef server, so you’ll have to install it somewhere you can already
The chef-ssl utility is provided by the chef-ssl-client gem.
$ gem install chef-ssl-client --no-rdoc --no-ri
Fetching: chef-ssl-client-1.0.5.gem (100%)
Successfully installed chef-ssl-client-1.0.5
$ chef-ssl --help
Chef-automated SSL certificate signing tool
autosign Search for CSRs and sign them with the given CA
help Display global or [command] help documentation.
issue Issue an ad hoc certificate
makeca Creates a new CA
search Searches for outstanding CSRs
sign Search for the given CSR by name and provide a signed certificate
-h, --help Display help documentation
-v, --version Display version information
-t, --trace Display backtrace when an error occurs
To create certificates, we’ll need the x509 cookbook on our Chef
server. Some of this cookbook’s functionality relies on the vt-gpg
cookbook, which is listed as a dependency. We won’t be using that
functionality today, but Chef will insist that we upload both.
Both cookbooks are available on the community site, so downloading
and installing them using Knife might look like this:
$ knife cookbook site install x509
Installing x509 to /Users/zts/code/chef-repo/cookbooks
Checking out the master branch.
Creating pristine copy branch chef-vendor-x509
Cookbook x509 version 1.0.3 successfully installed
Installing vt-gpg to /Users/zts/code/chef-repo/cookbooks
Checking out the master branch.
Creating pristine copy branch chef-vendor-vt-gpg
Cookbook vt-gpg version 1.0.0 successfully installed
$ knife cookbook upload x509 vt-gpg
Uploading vt-gpg [1.0.0]
Uploading x509 [1.0.3]
Uploaded 2 cookbooks.
Creating a Certificate Authority
To sign certificates, we’re going to need a CA. This is accomplished
using the chef-ssl makeca command on the host where you installed
chef-ssl-client. The required arguments are --dn (the
Distinguished Name of the CA), and --ca-path, the place where the
CA’s files will be stored. The DN will be visible in the CA
certificate, and any certificates it signs.
$ chef-ssl makeca --dn '/CN=My Test CA' --ca-path ./testCA
New CA DN: /CN=My Test CA
Enter new CA passphrase:
Re-enter new CA passphrase:
Creating new CA: done
Defining a certificate
To create a certificate on one of our Chef nodes, we use the
x509_certificate LWRP provided by the x509 cookbook. This LWRP
has some dependencies, which are installed by the default recipe – but
this means that recipe[x509::default] needs to be applied. It
doesn’t matter whether you put it on the run_list or load it using
include_recipe, but listing it as a dependency in another cookbook’s
metadata.rb is not enough.
In this example, we’re creating a server certificate for
“www.example.com”, and indicating that we’d like it to be signed by
After our node has created a signing request, we return to the
chef-ssl utility to process it. The chef-ssl autosign command
finds pending CSRs for a given CA by matching the --ca-name argument
against the ca parameter used in the x509_certificate resource.
You’ll be asked whether you’d like to sign each request it finds.