Building and Automating an Internal Certificate Authority

by J. Edward Durrett

In networked systems, nearly every common service, with the notable exception of DNS, speaks some form of encryption. If
telnet or plain http is still in use on a network, it is seriously high time to upgrade. With tls everywhere, however, a new
problem arises. We also need certificates everywhere. There is, of course, the option to use self-signed certificates and that
is the default behavior of some programs like sendmail. Although that does have risks, they are relatively small compared to
the cost of buying a certificate from a commercial certificate authority. There is a better solution one where all the tools
are already on most Linux/Unix systems. Using openssl, ssh and sudo, creating an internal Certificate Authority is quick and
simple. Automating the process of acquiring and signing certificates with the new Certificate Authority is also a snap.

The first step is to create a Certificate Authority and this document on readthedocs.io does a good job of
explaining the steps
[1]. After setting up the configuration files, this script will do all the steps needed to get
started:

 
#!/bin/sh
mkdir -p ca/root-ca/private ca/root-ca/db crl certs
chmod 700 ca/root-ca/private
cp /dev/null ca/root-ca/db/root-ca.db
cp /dev/null ca/root-ca/db/root-ca.db.attr
echo 01 > ca/root-ca/db/root-ca.crt.srl
echo 01 > ca/root-ca/db/root-ca.crl.srl
openssl req -new -config root-ca.conf -out ca/root-ca.csr -keyout ca/root-ca/private/root-ca.key
openssl ca -selfsign -config root-ca.conf -in ca/root-ca.csr -out ca/root-ca.crt -extensions root_ca_ext
mkdir -p ca/signing-ca/private ca/signing-ca/db crl certs
chmod 700 ca/signing-ca/private
cp /dev/null ca/signing-ca/db/signing-ca.db
cp /dev/null ca/signing-ca/db/signing-ca.db.attr
echo 01 > ca/signing-ca/db/signing-ca.crt.srl
echo 01 > ca/signing-ca/db/signing-ca.crl.srl
openssl req -new -config signing-ca.conf -out ca/signing-ca.csr -keyout ca/signing-ca/private/signing-ca.key
openssl ca -config root-ca.conf -in ca/signing-ca.csr -out ca/signing-ca.crt -extensions signing_ca_ext


The next step is allowing clients to submit a CSR (certificate signing request) and obtain a certificate. There are many
solutions out there, such as cfssl [2], but it is possible to achieve this by using just what is already on the system. By
setting up ssh access with a key which restricts the user to one command, the certificate request script, we can have a
generic user submit a CSR. By putting sudo into the mix, we can grant limited access for that user to use openssl.

Here is an example sudo entry specifying the user certifier can run openssl with root priveliges without a password
(authentication is done with the ssh key pair):

 
certifier ALL=(root) NOPASSWD:/usr/bin/openssl


Then, getting a new certificate is as simple as this command:

 
cat server.csr | ssh -i certifier_id certifier@certauth.example.com > server.crt


By placing the above command in a script called by cron, a new certificate can be generated every month, day or week –
whatever the site requirements are.

Crating a Certificate Authority for internal use is fairly easy. Of course, additional requirements might be needed, like
maintaining a CRL (Certificate Revocation List), but the basics are already there in most Linux / Unix distributions. Simple,
cost effective solutions are always preferred to complex expensive solutions in my shop.

[1] https://pki-tutorial.readthedocs.io/en/latest/simple/index.html

[2] https://github.com/cloudflare/cfssl







Copyright (c) 2019, Jason Edward Durrett - All content on this site, unless otherwise noted, is subject to this license.

Please contact me if any errors, such as erroneous / misleading content or missing / incomplete attribution, are found.