Secure Communication for Rails Applications (2)
Creating a Certificate Authority
This is the second in a series dealing with securing the environment of a rails environment. If you missed the introduction, you might want to give it a read.
In this segment, we'll create our own certificate authority (CA) to sign and verify clients connecting to our application, ensuring the clients are who they say they are. Whether you want to do things the easy way or the hard way depends on how much control you want over they way your CA behaves.
The Easy Way:
CA.pl is a script bundled with OpenSSL to simplify the most common cert creation and signing tasks. You can use this to do the heavy lifting when creating a CA:
CA.pl assumes that either you're creating a new CA, or that the
demoCA/ directory exists and has been properly populated. It also contains a number of defaults that might be worth customizing; new certs are created with a 1-year expiration and the root certification authority certificate has a 3-year expiration, for instance.
When running the script, you'll be asked to enter a pass phrase. This should be something reasonable but hard to guess since you'll be entering it every time you sign a certificate request. The rest of the fields should be easy enough to figure out, but be sure and enter a Common Name.
Creating Certs with
After your CA is set up, you're going to want to create three certs: one for the application/web server, one for our typical user, and one for an administrative user. This also can be done with
/path/to/openssl/CA.pl -newreq /path/to/openssl/CA.pl -signreq
This will create three files in the current directory:
- newreq.pem - the new certificates's signing request
- newkey.pem - the new cert's key file
- newcert.pem - the certificate file, signed by the CA you just created
For the typical and administrative users, we go the extra step of creating PKCS12 files for them before renaming them, since we're likely to be installing the certs into a browser. Once again, this is handled by CA.pl:
You'll be asked for an export password, to be tied to the PKCS12 file. This will generate
At this point, you should have a server keypair, as well as a keypair and p12 file for both user and admin.
The Hard Way: Customizing
If you're satisfied with what we have, feel free to move on. If you want to include your CA db in a source repo (see note below) or change some policies, you might want to do some tweaking.
When you look through
CA.pl, you'll see that it's simply a wrapper around a number of defaults passed into openssl. In fact, the
CA.pl source is a wonderful–if terse–introduction to the most commonly used openssl commands.
For this project, create the
certs/ directory into which all the credentials will be collected, and
certs/ca to hold the CA database. Change the default names
retsyn-ca.key, respectively. I'd also like to customize
CA.pl a little bit, and put it in a
bin directory to keep the project neat.
Finally, I don't like the defaults set up in the system's openssl.cnf file, so I'll instruct CA.pl to use a different configuration.
Back to the shell:
mkdir -p bin certs mv demoCA certs/ca cp /path/to/openssl/CA.pl bin cp /path/to/openssl/config/openssl.cnf certs/ca
Editing CA.pl, we change the configuration section:
SSLEAY_CONFIG="-config ./certs/ca/openssl.cnf" DAYS="-days 730"; # 2 years instead of 1 CADAYS="-days 3652"; # ~10 years instead of three ... CATOP="./certs/ca"; # demoCA seems meh CAKEY="retsyn-ca.key"; # root CA cert key file CACERT="retsyn-ca.pem"; # root CA cert file
For openssl.cnf, the obvious changes are these:
dir = ./certs/ca # Where everything is kept certificate = $dir/retsyn-ca.pem # The CA certificate private_key = $dir/private/retsyn-ca.key # The private key
We can also change the way the config file behaves when creating certificates by defining policy requirements within the openssl.cnf:
[policy_custom] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = supplied
match indicates that the cert's value will be the same as the CA's,
supplied values will be given by the generating user,
optional values are not required.
There are also a number of
[req_*] options that can be set for arbitrary levels of specificity.
Note: you shouldn't put your root CA certificate key or any other key file anywhere public, or anywhere it might be easily snagged. This includes public git repos and the like. (Yes, while all of my code for this article is on github, it's not intended to be used in any production environment, it's just for demonstration. Shut up.) Conversely, you MUST put your root CA certificate somewhere public if you want your users to be able to trust your root CA. Users who don't want to get a nasty warning message about your shady tactics will need to install your root CA into their browser or environment.
The Really Hard Way: Straight to
If you really want explicit control over every aspect of this process you can issue
openssl commands directly; in the words of @altonbrown, that's another show.
In the next post, we'll build our authentication system.