OpenSSL – Generate a new Key and CSR with SAN

What is a SAN

A SAN is a Subject Alternative Name, and as the name implies it serves as a secondary (or tertiary, etc.) DNS name that your web application could be identified as. This is useful in the context of web farms behind a reverse proxy, load-balancing solutions, etc.

For example:

#DNS name used to reach an example website, which has an SSL certificate
store.scriptech.io

#Back-end servers that serve store.scriptech.io behind a load balancer, included as SANs on the SSL certificate
webserver1.scriptech.io
webserver2.scriptech.io

Modern Browsers will show an SSL certificate as invalid if a proper SAN is not included, so it’s best practice for us to be in the habit of including SANs in our CSRs.

How to include a SAN

Because we want to include a SAN (Subject Alternative Name) in our CSR (and certificate), we need to use a customized openssl.cnf file.

While you could edit the ‘openssl req’ command on-the-fly with a tool like ‘sed’ to make the necessary changes to the openssl.cnf file, I will walk through the step of manually updating the file for clarity.

Example openssl.cnf file

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = <Country>
ST = <State>
L = <City>
O = <Company>
OU = <Department>
CN = store.scriptech.io
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS = webserver1.scriptech.io
#DNS.1 = <servername.domain.com>
#DNS.2 = <servername2.domain.com>
#DNS.3 = <servername3.domain.com>
#DNS.4 = <servername4.domain.com>

Note that the subjectAltName declaration calls an array called @alt_names, which is defined at the bottom of the file.

To include a single SAN in your CSR, update the ‘DNS’ declaration to the appropriate value (in this example, ‘webserver1.scriptech.io’), and leave the DNS.x declarations commented out (#). The result is an @alt_names array with a single entry.

To include multiple SANS in your CSR, comment out (#) the ‘DNS’ declaration, and uncomment the DNS.x declarations that you need. For example, your [alt_names] section would look like:

[alt_names]
#DNS = <servername.domain.com>
DNS.1 = webserver1.scriptech.io
DNS.2 = webserver1.scriptech.io
#DNS.3 = <servername3.domain.com>
#DNS.4 = <servername4.domain.com>

The result is an @alt_names array with multiple entries.

Generate the new key and CSR

If you have not already, copy the contents of the example openssl.cnf file above into a file called ‘openssl.cnf’ somewhere. Make note of the location.

Also make sure you update the DN information (Country, State, etc.)

Create a new key

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out store.scriptech.io.key.pem

Create a new CSR

openssl req -new -sha256 -key store.scriptech.io.key.pem -config /etc/ssl/openssl.cnf -out store.scriptech.io.csr

Verify the CSR

To view the contents of your new CSR, use the following command:

openssl req -text -noout -verify -in store.scriptech.io.csr

Certificate Request:
  Data:

  ...

  Requested Extensions:
  
  ...


    X509v3 Subject Alternative Name:
      DNS:webserver1.scriptech.io

This example shows a single SAN which I included in my openssl.cnf file.

Sign the CSR

Now that you have your properly-formatted CSR, you need to sign it using a Trusted Root Certificate Authority. Depending on your context, this could be a third-party CA like DigiCert or GoDaddy, or it could be an internal Certificate Authority (OpenSSL CA, Active Directory Certificate Services)

The contents of a certificate in the openssl format can be viewed with the following command:

openssl x509 -in store.scriptech.io.cer.pem -text -noout