Skip to content

Creating an internal CA

For services hosted within UIS we occasionally make use of the UIS traffic manager to proxy traffic from the Big Bad Internet to our VMs which sit on .private.cam.ac.uk addresses. There are generally three ways the traffic manager can be configured:

  1. No encryption between traffic manager and VM.
  2. Encryption between traffic manager and VM but without server verification.
  3. Encryption between traffic manager and VM with server verification.

Option 3 is to be preferred since it provides not only confidentiality but protection against man-in-the-middle attacks.

We could create a certificate signed by a global trust authority as we do for public servers but this would lead to .private.cam.ac.uk hostnames leaking into the public domain via certificate transparency lists.

The traffic manager can be configured to trust a custom Certificate Authority (CA). We can maintain a separate CA per service or make use of a shared one.

Creating the CA root certificate and key

Create a key for the CA. The confidentiality of this key is the source of security so keep it safe.

openssl genrsa -out ca-private-key.pem 4096

Now create a new CA root certificate. The various fields such as organisation, etc don't matter but it is good form to set them to something sensible.

openssl req -new -x509 -days 3650 -key ca-private-key.pem -out ca-crt.pem

Creating the certificate signing request

The certificate signing request is used to create a certificate for the VM itself. Rather than having to type each value in to openssl you can specify them in advance in a config file. For example, the Raven passwords app might use the following config in password.conf:

# Example OpenSSL configuration file for creating Certificate Signing
# Requests (CSRs) suitable for requesting certificates via
# the JISC sectigo TLS Certificate Service
#
# Edit this file as necessary (see comments), and then run (e.g.):
#
#   openssl req -config qv.cnf -new -out <hostname>.csr -keyout <hostname>.key
#
# Replacing <hostname> with the primary server hostname (or
# similar). Accept most defaults but supply information for
# 'University institution' and 'Hostname'.

[ req ]
default_bits = 4096
default_md = sha256
distinguished_name = dn

# Uncomment to add SAN extensions and make further changes below
req_extensions = ext

[ dn ]
countryName                     = Country Name (use default)
countryName_default             = GB

stateOrProvinceName             = State or Province Name (use default)
stateOrProvinceName_default     = Cambridgeshire

localityName                    = Locality Name (use default)
localityName_default            = Cambridge

organizationName                = Organisation Name (use default)
organizationName_default        = University of Cambridge
organizationalUnitName_min      = 2
organizationalUnitName_max      = 64

# A common approach is to make commonName the primary DNS name of the
# service (e.g. www.is.cam.ac.uk) and use the alt_section below to set
# 'Subject Alternative Names' (SANs) for alternative names such as
# is.cam.ac.uk, intranet.is.cam.ac.uk, etc.
#
# However browsers now typically ignore commonName in favour of what
# appears in the SAN section of certificates, so it's now best practice
# to put ALL the names you want
commonName                      = secret-server1.srv.uis.private.cam.ac.uk
commonName_default              = secret-server1.srv.uis.private.cam.ac.uk
commonName_min                  = 2
commonName_max                  = 64

[ ext ]
subjectAltName=@alt_section

[ alt_section ]
DNS.0=secret-server1.srv.uis.private.cam.ac.uk
DNS.1=secret-server2.srv.uis.private.cam.ac.uk

Generate a new key for the passwords app:

openssl genrsa -out passwords-private-key.pem 4096

Generate a certificate signing request (CSR) for the service:

openssl req -config passwords.conf -new \
    -out passwords-csr.pem -key passwords-private-key.pem

Signing the CSR

The CA key can now be used to sign the CSR:

openssl x509 -req -days 3650 -in passwords-csr.pem \
    -CA ca-crt.pem -CAkey ca-private-key.pem -set_serial 01 \
    -out passwords-crt.pem -extensions ext -extfile passwords.conf

Checking our work

Check the generated certificate has all the server names:

openssl x509 -noout -in passwords-crt.pem -text

Deploying

We now have several files. The following files are not secret:

  • ca-crt.pem
  • passwords.conf
  • passwords-csr.pem
  • passwords-crt.pem

The following files are secret:

  • ca-private-key.pem
  • passwords-private-key.pem

Where the files end up depends on their use:

  • ca-crt.pem can be sent to the traffic manager admins to install.
  • ca-private-key.pem must be kept safe and confidential so that it can be used to sign more certificates if needed.
  • passwords.conf and passwords-csr.pem can be saved for next time.
  • passwords-crt.pem and passwords-private-key.pem can be copied to the VM.

Examples

DevOps members can find the CA root private key for the passwords app in 1password along with the password service's private key.