Smallstep Certificate Manager | Your Hosted Private CA

How to use step-ca with Hardware Security Modules (HSMs)

Carl-Tashian.jpg

Carl Tashian

Follow Smallstep

We're excited to add support for Hardware Security Modules (HSMs), via PKCS #11, to step-ca version 0.15.8.

An HSM is a specialized device that is designed to generate, store, and use private keys securely. The private keys on an HSM cannot be exported from the device. One can only run signing operations on the device. This is an excellent way to protect private keys for a Certificate Authority, whose primary function is to sign Certificate Signing Requests. In the early 2000s, HSMs were sometimes marketed as "eCommerce Accelerators" because companies used them primarily to speed up cryptographic operations for SSL connections. Today, they are more often used to meet tight security and compliance requirements.

PKCS (Public-Key Cryptography Standards) #11 is the most common platform-independent API used by HSMs. There's even a software-based "HSM," SoftHSMv2, which offers a PKCS #11 interface for testing purposes, without the hardware.

With PKCS #11 support, step-ca can be configured to use almost any HSM. HSMs range from the $80 USB Nitrokey HSM 2 all the way up to the $39,000 Entrust nShield Connect XC High rack-mounted HSM.

AWS CloudHSM is an interesting offering because it offers real HSM hardware by the hour and—you guessed it—it's in the cloud. CloudHSM offers HSM clusters, with multi-AZ support as needed. It offers private, single-tenant HSMs with FIPS 140-2 Level 3 security, and costs about $1,000/month/HSM.

In this post, I'll show you how to set up step-ca using AWS CloudHSM. Our Configuration Guide details how to use step-ca's HSM support with any PKCS #11 device.

Tutorial: step-ca + AWS CloudHSM

AWS CloudHSM is an HSM that you can access from your VPC using mutual TLS. It comes with an optional client library that makes it compatible with step-ca via the PKCS #11 API. In this example, we will store the CA certificates for step-ca as files on an EC2 VM, but we'll delegate signing operations to the CloudHSM cluster.

0. Before you begin

You will need:

  • An active CloudHSM cluster. To set one up from scratch, follow all of the instructions in the Getting Started section of the AWS CloudHSM User Guide. There's a lot of steps here and it will take at least 30 minutes to do this initial setup.

    When you're done, you will have:

    • activated an HSM cluster with at least one HSM in it
    • mapped an EC2 instance to the cloudhsm cluster's security group. I used an instance running Ubuntu 18.04.
    • installed and configured the cloudhsm-client package
    • created and installed (into /opt/cloudhsm/etc) your self-signed cluster CA certificate
    • downloaded and signed your cluster CSR using your customer CA
    • initialized the cluster using the CSR you made (aws cloudhsmv2 initialize-cluster)
    • changed the default HSM cluster admin password, using the cloudhsm_mgmt_util tool
  • The CloudHSM PKCS #11 Library. On your EC2 instance, install the cloudhsm-client-pkcs11 by following the instructions in Installing the PKCS #11 Library.

1. Create a certificate user (CU) to use with step-ca

On your EC2 instance, run the HSM management utility, log in to the HSM, and create a "CU" type user for use with step-ca:

$ /opt/cloudhsm/bin/cloudhsm_mgmt_util /opt/cloudhsm/etc/cloudhsm_mgmt_util.cfg
Ignoring E2E enable flag in the configuration file
Connecting to the server(s), it may take time
depending on the server(s) load, please wait...
Connecting to server '172.31.27.83': hostname '172.31.27.83', port 2225...
Connected to server '172.31.27.83': hostname '172.31.27.83', port 2225.
E2E enabled on server 0(172.31.27.83)
aws-cloudhsm> loginHSM CO admin <admin_password>
aws-cloudhsm> createUser CU step_ca RiFJrg93Tn_EXAMPLE
aws-cloudhsm> quit

Note your password! We'll need it later to configure step-ca.

2. Build step-ca with HSM support

Now let's build step-ca. HSM support requires a CGO version of step-ca. Unfortunately, step-ca doesn't distribute CGO binaries, so we'll need to build it from scratch to enable HSM support.

On the VM, run the following as root to build step-ca:

apt update
apt upgrade -y
apt install -y make gcc ack libpcsclite-dev pkg-config
GO_VERSION=1.16
curl -LO https://golang.org/dl/go$GO_VERSION.linux-amd64.tar.gz
tar -C /usr/local -xzf go$GO_VERSION.linux-amd64.tar.gz
cat<<EOF >> /etc/profile
export PATH=\$PATH:/usr/local/go/bin
EOF

Now sign out and back in, so the configuration takes effect.

As a non-root user, let's build the CA:

curl -LO https://github.com/smallstep/certificates/releases/download/v0.15.8/step-certificates_0.15.8.tar.gz
mkdir certificates
pushd certificates
tar xzf ../step-certificates_0.15.8.tar.gz
make bootstrap
make build GOFLAGS=""
popd

At this point you'll have all of the binaries for step-ca in the certificates/bin directory.

3. Create your Public Key Infrastructure (PKI) keys and certificates

Now we'll create keys on the HSM for our CA, using the step-pkcs11-init utility.

I've added an extra space before setting the HSM_USER and HSM_PASSWORD environment variables here. In Bash, the extra space will exclude these values from our shell history.

$  HSM_USER=step_ca HSM_PASSWORD=RiFJrg93Tn_EXAMPLE
$ certificates/bin/step-pkcs11-init --no-certs --ssh \
                     --kms "pkcs11:module-path=/opt/cloudhsm/lib/libcloudhsm_pkcs11.so;token=cavium?pin-value=$HSM_USER:$HSM_PASSWORD"
Creating PKI ...
✔ Root Key: pkcs11:id=7330;object=root-key
✔ Root Certificate: root_ca.crt
✔ Intermediate Key: pkcs11:id=7331;object=intermediate-key
✔ Intermediate Certificate: intermediate_ca.crt
✔ SSH Host Key: pkcs11:id=7332;object=ssh-host-key
✔ SSH User Key: pkcs11:id=7333;object=ssh-user-key

What just happened? The utility created SSH and X.509 CA private keys on the HSM, and it saved the root and intermediate CA certificates onto disk (CloudHSM doesn't yet support saving the certificates to the HSM). It printed the URIs for the keys we're going to use in the CA. (Save these! You'll need them to configure your CA.)

If you run into trouble here, be sure the cloudhsm-client service is running and the credentials are correct.

4. Configure step-ca

First, let's get step-ca installed:

$ sudo cp certificates/bin/step-ca /usr/bin
$ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/step-ca

We'll also want to install the step command line tool:

$ wget https://github.com/smallstep/cli/releases/download/v0.15.8/step_0.15.8_amd64.deb
$ sudo dpkg -i step_linux_0.15.8_amd64.deb

Now run step ca init --ssh and go through the steps. We're not going to use the PKI generated here, but we will use the configuration file as our basis.

Once you have your PKI generated in .step, move your certificate files into their homes:

$ mv root_ca.crt intermediate_ca.crt .step/certs
$ rm -r .step/secrets

Now open up .step/config/ca.json in an editor. You'll want the top of the file to reference the HSM intermediate key and SSH keys you just created. For this, you'll need to change the key and ssh key to match the pkcs11: URIs above. These are the values you need to change:

{
        ...
        "key": "pkcs11:id=7331;object=intermediate-key",
        "ssh": {
                "hostKey": "pkcs11:id=7332;object=ssh-host-key",
                "userKey": "pkcs11:id=7333;object=ssh-user-key"
        },
        ...
}

Finally, add a new kms top-level object, with your pkcs11 module URI:

{
        ...
        "kms": {
                "type": "pkcs11",
                "uri": "pkcs11:module-path=/opt/cloudhsm/lib/libcloudhsm_pkcs11.so;token=cavium?pin-value=step_ca:RiFJrg93Tn_EXAMPLE"
        },
        ...
}

The CA should start right up, using the HSM:

$ step-ca .step/config/ca.json
badger 2021/03/04 00:24:20 INFO: All 1 tables opened in 0s
badger 2021/03/04 00:24:20 INFO: Replaying file id: 0 at offset: 1407
badger 2021/03/04 00:24:20 INFO: Replay took: 4.527µs
badger 2021/03/04 00:24:20 DEBUG: Value log discard stats empty
2021/03/04 00:24:20 Serving HTTPS on :443 ...

In another window, get a test certificate for localhost:

$ step ca certificate localhost localhost.key localhost.crt

Tada. You're now getting certificates signed by the CloudHSM cluster.

Alternatives to HSMs for storing private keys in step-ca

  • step-ca also supports AWS Key Management Service (KMS) or Google Cloud KMS. These services are HSM-backed. However, they are not single-tenant solutions, so they won't meet everyone's security or compliance requirements. Our configuration guide has instructions for setting up step-ca to use cloud key management services.
  • For on-premise installations, the YubiKey PIV application can be used, with any recent YubiKey. See our post, Build a Tiny Certificate Authority for your Homelab.
  • Commercial offering: For about $75/vCPU/month, you can run step-ca as a Registration Authority (RA) in front of Google's Certificate Authority Service. See this post for details.

Read more about Cryptographic Protection in step-ca in our Configuration Guide

Other new features in step and step-ca v0.15.8

Carl Tashian (Website, LinkedIn) is an engineer, writer, exec coach, and startup all-rounder. He's currently an Offroad Engineer at Smallstep. He co-founded and built the engineering team at Trove, and he wrote the code that opens your Zipcar. He lives in San Francisco with his wife Siobhan and he loves to play the modular synthesizer 🎛️🎚️