Purpose
This guide walks through integrating the Virtru Customer Key Server (CKS) with AWS CloudHSM to provide hardware-backed encryption key protection. By connecting CKS to a CloudHSM cluster, your organization's encryption keys are stored and managed within a FIPS 140-2 Level 3 validated hardware security module ensuring keys are never exposed in plaintext outside the HSM boundary.
Important Limitations
CKS with CloudHSM integration is not supported on serverless container platforms, including:
- AWS Fargate
- Google Cloud Run
- Azure Container Instances
These platforms do not provide the system-level access required for secure hardware cryptographic integration, specifically the ability to install custom system libraries, access privileged filesystem locations, and establish direct network connections to the HSM cluster.
Prerequisites
Before beginning, ensure the following:
- Prerequisites and the CKS base installation have already been completed
- An AWS CloudHSM cluster has been created but not yet initialized
- The HSM cluster and the CKS host must have network connectivity (same VPC or peered VPC). Same Availability Zone is recommended for lowest latency.
- You have SSH access to the CKS host machine
AWS CloudHSM SDK 5 uses two packages. There is no client daemon in SDK 5.
| Package | Purpose |
|---|---|
cloudhsm-cli |
Command-line tool for HSM management and key operations |
cloudhsm-pkcs11 |
PKCS#11 library for application-level HSM communication |
Information to Collect Before Running the Setup Wizard
You will need the following values during this procedure. Some are created during the steps below; others should be collected in advance.
| Value | Description | Example |
|---|---|---|
| HSM IP Address | The ENI IP address of your HSM instance, from the AWS CloudHSM console | 10.0.1.42 |
| CU Username | The crypto user account name for CKS operations | cryptouser |
| CU Password | The password for the crypto user account | (set during Step 5) |
| Key Label | The label applied to all organization keys on the HSM | rsa001 |
| Slot Label | The HSM slot label used by CKS | hsm1 |
| Working Directory | The directory used during initial CKS setup | /var/virtru/cks |
Step 1: Create an HSM Instance
Create an HSM instance within your cluster via the AWS CloudHSM console. Note the HSM IP address, you will need it throughout this procedure.
Ensure the HSM is in the same Availability Zone as your CKS host.
Step 2: Download and Sign the Cluster CSR
Download the cluster's Certificate Signing Request (CSR) from the AWS console. The file will be named:
cluster-<cluster-id>_ClusterCsr.csr
Generate a private key for your customer Certificate Authority:
openssl genrsa -aes256 -out customerCA.key 2048
Generate a self-signed CA certificate (valid approximately 10 years):
openssl req -new -x509 -days 3652 -key customerCA.key -out customerCA.crt
Sign the cluster CSR with your customer CA:
openssl x509 -req -days 3652 \ -in cluster-<cluster-id>_ClusterCsr.csr \ -CA customerCA.crt \ -CAkey customerCA.key \ -CAcreateserial \ -out cluster-<cluster-id>_CustomerHsmCertificate.crt
Upload the signed certificate (CustomerHsmCertificate.crt) and your customer CA certificate (customerCA.crt) to the AWS CloudHSM console to complete cluster initialization.
Step 3: Configure Networking
Configure security groups per the AWS CloudHSM documentation. Add the HSM cluster's security group to the CKS host instance so it can communicate with the HSM.
For details, refer to the AWS guide: Create a cluster security group.
Step 4: Install the CloudHSM Client (SDK 5)
Install the CloudHSM CLI and PKCS#11 library on the CKS host. Download the packages appropriate for your OS from the AWS CloudHSM Client SDK 5 downloads page.
For Ubuntu 24.04, download the packages into /tmp:
cd /tmp wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Noble/cloudhsm-cli_latest_u24.04_amd64.deb wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Noble/cloudhsm-pkcs11_latest_u24.04_amd64.deb sudo apt install ./cloudhsm-cli_latest_u24.04_amd64.deb sudo apt install ./cloudhsm-pkcs11_latest_u24.04_amd64.deb
Configure both tools with the HSM IP address, and copy the signing certificate to the CloudHSM directory:
sudo /opt/cloudhsm/bin/configure-cli -a <HSM_IP> sudo /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_IP> sudo cp customerCA.crt /opt/cloudhsm/etc/customerCA.crt
Note: For production deployments, AWS recommends at least two HSM instances. With a single HSM and this check disabled, HSM failure could mean total key loss.
For single-HSM clusters, disable the key availability check on both tools:
sudo /opt/cloudhsm/bin/configure-cli --disable-key-availability-check sudo /opt/cloudhsm/bin/configure-pkcs11 --disable-key-availability-check
Step 5: Activate the Cluster and Create a Crypto User
Launch the CloudHSM CLI in interactive mode:
/opt/cloudhsm/bin/cloudhsm-cli interactive
Activate the cluster. This sets the admin password and transitions the cluster to an active state.
Prompt:
aws-cloudhsm > cluster activate
You will be prompted to set a new password for the admin user. Record this password securely.
Log in as the admin to create a crypto user:
Prompt:
aws-cloudhsm > login --username admin --role admin
Enter the admin password when prompted.
Create a crypto user for CKS operations:
Prompt:
aws-cloudhsm > user create --username cryptouser --role crypto-user
Enter and confirm a password for the crypto user when prompted.
Important: Record the crypto user credentials. The CKS requires them in the format cryptouser:<password> during the setup wizard.
Log out when finished:
aws-cloudhsm > logout
Step 6: Generate a New RSA Key Pair
If you are setting up CKS with CloudHSM for the first time and do not have existing keys to import, generate a new key pair on the HSM.
In the CloudHSM CLI, log in as the crypto user:
Prompt:
aws-cloudhsm > login --username cryptouser --role crypto-user
Generate an RSA 2048-bit key pair:
Prompt:
aws-cloudhsm > key generate-asymmetric-pair rsa \ --public-label rsa001 \ --private-label rsa001 \ --modulus-size-bits 2048 \ --public-exponent 65537 \ --public-attributes encrypt=true \ --private-attributes decrypt=true
Verify the keys were created:
Prompt:
aws-cloudhsm > key list --filter attr.label="rsa001"
You should see both a public key and a private key listed with the label rsa001.
Step 7: Prepare the Customer CA Certificate
Before running the setup wizard, copy your customerCA.crt into the HSM configuration directory within your CKS working directory:
sudo mkdir -p /var/virtru/cks/hsm-config sudo cp customerCA.crt /var/virtru/cks/hsm-config/customerCA.crt
Important: The connection to the HSM from the CKS requires this certificate to reside in the /hsm-config directory. The CKS container will mount it to /opt/cloudhsm/etc/customerCA.crt inside the container.
Step 8: Run the HSM Setup Wizard
Open a second SSH session to the CKS host and run the setup script in your scripts directory:
bash setup-cks-hsm-latest.sh
The wizard will prompt you for the following values.
Prompt: Enter Working Directory:
Example: /var/virtru/cks
Enter the same directory used during initial CKS setup.
Prompt: Enter the HSM Server IP Address:
Example: 10.0.1.42
Enter the ENI IP address of your HSM instance from the AWS console.
Prompt: Enter the HSM Slot Label:
Example: hsm1
Prompt: Enter the RSA Keypair Label:
Example: rsa001
This must match the label used when generating or importing keys in Step 6 or the Appendix.
Prompt: Enter the HSM Pin (in the format <CU_user_name>:<password>):
Example: cryptouser:<password>
Enter the crypto user credentials created in Step 5.
The wizard will run a list-keys test against the HSM to verify connectivity.
Prompt: Did the CKS successfully list the keys? Please enter yes or no.
- Answer
yesif the key listing succeeded. The wizard will update your environment file and generate therun.shstartup script. - Answer
noif the key listing failed. Review the error output and verify your HSM IP, credentials, certificate placement, and key labels before retrying.
Step 9: Start CKS
Start the CKS container using the generated startup script:
bash /var/virtru/cks/run.sh
Step 10: Validate the Deployment
Confirm CKS is running and can communicate with the HSM.
Check that the container started successfully:
docker ps -a
You should see a container named Virtru_CKS in the list.
Verify CKS health:
curl https://yourcksURL:443/status
You can also monitor the CKS container logs for errors:
docker logs -f Virtru_CKS
Configuration Reference
The following environment variables control the CloudHSM integration. These are set automatically by the setup wizard and stored in env/cks.env, but are documented here for reference.
| Variable | Value | Description |
|---|---|---|
HSM_IP |
<HSM ENI IP> |
IP address of the CloudHSM instance |
PKCS11_VENDOR |
custom |
Vendor type (custom for CloudHSM) |
PKCS11_LIB_NAME |
CloudHSM |
Library identifier: triggers CloudHSM initialization on container start |
PKCS11_LIB_PATH |
/opt/cloudhsm/lib/libcloudhsm_pkcs11.so |
Path to the PKCS#11 shared library inside the container |
PKCS11_SLOT_LBL |
hsm1 |
HSM slot label |
PKCS11_KEY_LBL |
rsa001 |
Label for organization keys on the HSM |
PKCS11_PIN |
cryptouser:<password> |
Crypto user credentials |
KEY_PROVIDER_TYPE |
hsm |
Tells CKS to use the HSM key provider |
CRYPTO_OPERATIONS_TYPE |
hsm |
Tells CKS to use the HSM for crypto operations |
Send Public Key Generated in CloudHSM to Virtru
In the CloudHSM CLI, list the keys to identify the public key reference:
aws-cloudhsm > key list --filter attr.label=rsa001 --verbose
Note the key-reference value for the key with class public-key.
Export the public key to a file:
aws-cloudhsm > key generate-file --encoding pem \ --path /tmp/rsa001.pub \ --filter key-reference=<public-key-reference>
The file /tmp/rsa001.pub now contains the PEM-encoded public key. Copy this file into the cks_info/ directory and re-create the send_to_virtru.tar.gz archive:
mkdir -p /var/virtru/cks/cks_info cp /tmp/rsa001.pub /var/virtru/cks/cks_info/rsa001.pub cd /var/virtru/cks && tar -zcvf send_to_virtru.tar.gz ./cks_info
Send the updated send_to_virtru.tar.gz to Virtru.
Troubleshooting
CKS cannot connect to the HSM
- Verify the HSM instance is running in the AWS CloudHSM console.
- Confirm the HSM and CKS host have network connectivity (same VPC or peered VPC).
- Check that the HSM cluster security group is attached to the CKS host.
- Verify
customerCA.crtis present at/var/virtru/cks/hsm-config/customerCA.crton the host and is mounted correctly inside the container. - Check CKS container logs for connection errors:
docker logs Virtru_CKS
Key not found errors
- Verify keys exist on the HSM by launching
cloudhsm-cli interactive, logging in as the crypto user, and runningkey list --filter attr.label="rsa001". - Confirm the
PKCS11_KEY_LBLvalue inenv/cks.envmatches the label used when creating or importing keys. - Ensure all keys (public and private) have the same label.
Key generation fails with "key must be available on at least 2 HSMs"
Single-HSM clusters require the key availability check to be disabled on both the CLI and PKCS#11 tools. See Step 4 for the commands. For production, add a second HSM instance via the AWS console instead of disabling this check.
Appendix: Import Keys (Existing CKS Customers)
Use this section if you are upgrading from a file-based CKS installation and need to import your existing RSA keys into the HSM. Complete Steps 1–5 above first, then follow the steps below. After importing, return to Step 7 to continue the setup.
Important: All keys that CKS needs to read must have the same label (e.g., rsa001). The CloudHSM CLI key import pem command supports only public keys (rsa-public / ec-public); private keys must be brought in using the RSA-AES wrapped-import workflow described below.
A.1 Log in as the crypto user
/opt/cloudhsm/bin/cloudhsm-cli interactive aws-cloudhsm > login --username cryptouser --role crypto-user
A.2 Locate your existing CKS key files
Typically in /var/virtru/cks/keys/:
-
rsa_001.pub: public key (PEM-encoded SubjectPublicKeyInfo) -
rsa_001.pem: private key (PEM)
A.3 Import the public key
aws-cloudhsm > key import pem \
--path /var/virtru/cks/keys/rsa_001.pub \
--label rsa001 \
--key-type-class rsa-public \
--attributes encrypt=trueA.4 Create an RSA wrapping key pair on the HSM
This key pair is used only to securely transport your private key into the HSM. Use unique labels so the unwrap command can filter unambiguously.
aws-cloudhsm > key generate-asymmetric-pair rsa \ --public-label cks-wrap-pub \ --private-label cks-unwrap-priv \ --modulus-size-bits 4096 \ --public-exponent 65537 \ --private-attributes unwrap=true
A.5 Export the wrapping public key to the host
aws-cloudhsm > key generate-file --encoding pem \ --path /tmp/wrap-pub.pem \ --filter attr.label=cks-wrap-pub aws-cloudhsm > quit
A.6 Convert the existing private key to PKCS#8 DER
The CloudHSM CLI requires the payload private key in PKCS#8 DER format.
openssl pkcs8 -topk8 -inform PEM -outform DER \ -in rsa_001.pem -out rsa_001_pkcs8.der -nocrypt
A.7 Wrap the private key (RSA-AES envelope)
# Generate an ephemeral AES-256 key openssl rand -out ephemeral_aes 32 EPHEMERAL_AES_HEX=$(hexdump -v -e '/1 "%02X"' < ephemeral_aes) # Wrap the PKCS#8 private key with the ephemeral AES key openssl enc -id-aes256-wrap-pad -K $EPHEMERAL_AES_HEX -iv A65959A6 \ -in rsa_001_pkcs8.der -out payload_wrapped # Wrap the ephemeral AES key with the HSM's RSA public wrapping key openssl pkeyutl -encrypt -in ephemeral_aes -out ephemeral_wrapped \ -pubin -inkey /tmp/wrap-pub.pem \ -pkeyopt rsa_padding_mode:oaep \ -pkeyopt rsa_oaep_md:sha256 \ -pkeyopt rsa_mgf1_md:sha256 # Concatenate: wrapped ephemeral key first, then wrapped payload cat ephemeral_wrapped payload_wrapped > rsa_aes_wrapped
A.8 Unwrap the private key into the HSM
/opt/cloudhsm/bin/cloudhsm-cli interactive aws-cloudhsm > login --username cryptouser --role crypto-user aws-cloudhsm > key unwrap rsa-aes \ --data-path /path/to/rsa_aes_wrapped \ --key-type-class rsa-private \ --label rsa001 \ --hash-function sha256 \ --mgf mgf1-sha256 \ --filter attr.label=cks-unwrap-priv \ --attributes decrypt=true sign=true
Notes:
-
key unwrap rsa-aesrequires CloudHSM CLI 5.11 or later. - The hash/MGF flags here (
sha256/mgf1-sha256) must match the OpenSSLrsa_oaep_md/rsa_mgf1_mdvalues used in Step A.7. - Validate the exact flags against your installed CLI version with
help key unwrap rsa-aesbefore production use.
A.9 Verify the imported keys
aws-cloudhsm > key list --filter attr.label=rsa001 --verbose
Confirm that both a public key and a private key appear with the label rsa001.
A.10 (Optional) Clean up the wrapping key pair
aws-cloudhsm > key delete --filter attr.label=cks-wrap-pub aws-cloudhsm > key delete --filter attr.label=cks-unwrap-priv
Return to Step 7 to continue the setup.