Deploying your Certificate Authority

Posted on: 2025-02-03

SSL certificates used to be a big business, with every organization having to pay money to a handful of companies to obtain a certificate signed by a trusted Certificate Authority (CA). The Let's Encrypt project was a great benefit for the Internet at large, bringing free and easy to deploy certificates to everybody. Today, the need for you to deploy your own CA is much less, and if you have a public web site I highly encourage you to use the Let's Encrypt system to get a valid certificate. However, there are still use cases for deploying your own CA. One example is for internal sites, where both the HTTP and DNS endpoints aren't available for validation. Another example is an air-gapped network. Whatever the case, it's never a good idea to rely on self-signed certificates, so here I will show you how you can easily deploy your own CA, create a wildcard certificate for all your sites, and then add the certificate to your devices trust stores.

Before we write our first script, it's important to speak about security. In an organization, your CA is one of the most important pieces of your digital infrastructure. It allows people to impersonate your digital assets. So it's important that you create these assets on a secure system. This means you should have an air-gapped computer (or at least virtual machine) that you keep offline except when you need to create a certificate.

The first script we'll write is make_ca_cert.sh and it will be used to create the CA key and certificate:

#!/bin/bash

openssl genrsa -aes256 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt -subj "/C=CA/ST=QC/L=City/O=Example/OU=IT/CN=My Example Root CA"
openssl x509 -outform pem -in rootCA.crt -out rootCA.pem

echo "CA Certificate (unix): rootCA.crt"
echo "CA Certificate (pem): rootCA.pem"

This script will create three files. First, a private key for the root CA. Then, the actual certificate will be created in 2 different formats. Note that this key should never leave your air-gapped server. The certificate files can be distributed to any device that needs to trust your new CA. This CA will last for 10 years.

The next step is to create extended.cfg which will contain some configuration values for our end certificate:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.example.com
DNS.2 = example.com
DNS.3 = test.example.com

This is where you define which hostnames should be covered by the certificate. You can also use a wildcard for the certificate to apply to any subdomain.

Finally, let's create make_wildcard_cert.sh to craft your certificate:

#!/bin/bash

openssl genrsa -out wildcard.example.com.key 2048
openssl req -new -key wildcard.example.com.key -out wildcard.example.com.csr -subj "/C=CA/ST=QC/L=City/O=Example/OU=IT/CN=My Example Root CA"
openssl x509 -req -in wildcard.example.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out wildcard.example.com.crt -days 380 -sha256 -extfile extended.cfg
openssl x509 -in wildcard.example.com.crt -text -noout

echo "Key: wildcard.example.com.key"
echo "Certficiate: wildcard.example.com.crt"

This will create two files, a private key and a certificate. Both files should be stored on any host that will need to use them, such as web hosts. You can simply copy them to /etc/certs and then use them with Nginx, Apache, etc. The certificate will last for a year, which means you need to create a new one each year on the anniversary date.

The last step is to add your CA to the trusted list on client devices: