Skip to content

Latest commit

 

History

History
209 lines (164 loc) · 7.88 KB

File metadata and controls

209 lines (164 loc) · 7.88 KB

Generated by Merlin Studio (https://app.merlin-studio.cloud). Licensed under the Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0).

CloudHSM-backed KMS — Pre-Deploy Setup

The landing zone for AcmeCorp is configured for HSM-backed customer-managed keys (FIPS 140-2 Level 3). Every generated CMK renders the placeholder

custom_key_store_id = "PLACEHOLDER_CLOUDHSM_KEY_STORE_ID"
origin              = "AWS_CLOUDHSM"

(or the CDK / LZA equivalent). tofu apply / cdk deploy will fail until the CloudHSM cluster, the KMS custom key store, and the placeholder substitution are in place. Walk this guide end-to-end before deploying.

This requirement is typically driven by FedRAMP High (SC-12, SC-13) or EUCS High — toggled via section 06's Use HSM-backed KMS keys control (kms_use_hsm = true) or per-CMK hsm: true.

Cost & footprint

CloudHSM is not cheap. Plan for the bill before you provision:

  • Single HSM: ~$1.45/hour = ~$1 050/month in us-east-1 / us-west-2 / EU regions.
  • High-availability cluster (2 HSMs, minimum recommended for production): ~$2 100/month, plus a few dollars for the backups in S3 and ENIs.
  • Cross-region replicas (for DR) multiply this further.

You must keep at least 2 HSMs in the cluster for HA — a single HSM is a single point of failure and AWS recommends a minimum of two for any production custom key store. Some compliance frameworks (FedRAMP High) effectively require HA HSM clusters to satisfy availability controls.


Step 1 — Create the CloudHSM cluster

Create the cluster in the same region as the KMS keys it will back (the landing zone's primary region — typically eu-central-1). The cluster must live in a VPC; AWS recommends a dedicated VPC with private subnets in at least two AZs so the second HSM can land in a different AZ.

# 1a. Create the cluster (one-time; takes a few minutes).
aws cloudhsmv2 create-cluster \
  --hsm-type hsm1.medium \
  --subnet-ids subnet-aaa subnet-bbb \
  --region eu-central-1

# Record the ClusterId returned (cluster-xxxxxxxx).

Then provision the first HSM in the cluster:

aws cloudhsmv2 create-hsm \
  --cluster-id cluster-xxxxxxxx \
  --availability-zone eu-central-1a

Wait until the cluster shows State = UNINITIALIZED and the HSM is ACTIVE, then proceed to step 2.

Step 2 — Initialize the cluster (CO credentials)

You must initialize the cluster by signing its CSR with your own CA. Until you do, the cluster cannot mint keys. AWS walks through this in detail at CloudHSM Getting Started; the high-level steps are:

  1. Get the cluster CSR: aws cloudhsmv2 describe-clusters --filters clusterIds=cluster-xxxxxxxx --query 'Clusters[0].Certificates.ClusterCsr' --output text > cluster.csr
  2. Sign the CSR with a CA you control (offline / KMS / on-prem PKI — not an AWS-managed CA). Output: CustomerHsmCertificate.crt + CustomerCA.crt.
  3. Initialize the cluster:
    aws cloudhsmv2 initialize-cluster \
      --cluster-id cluster-xxxxxxxx \
      --signed-cert file://CustomerHsmCertificate.crt \
      --trust-anchor file://CustomerCA.crt
  4. Install the CloudHSM Client and connect: sudo /opt/cloudhsm/bin/configure-cli -a <hsm-ip>
  5. Log in as PRECO (pre-Crypto-Officer) and set the Crypto Officer (CO) password:
    /opt/cloudhsm/bin/cloudhsm-cli interactive
    login --username admin --role admin
    change-password --username admin --role admin
    
  6. Add a second HSM with aws cloudhsmv2 create-hsm in a different AZ — the cluster auto-syncs key material from the first HSM. You now have an HA cluster.

Step 3 — Create Crypto User (CU) credentials

KMS uses a CU (not the CO) to access keys. From the cloudhsm-cli session:

user create --username kmsuser --role crypto-user

Capture the password somewhere safe (Secrets Manager, a corporate vault) — you will hand it to KMS in step 4 and you will need it again to rotate.

Step 4 — Create the KMS custom key store

Now bind KMS to the cluster. This is the step that mints the cks-xxxxxxxx ID that replaces PLACEHOLDER_CLOUDHSM_KEY_STORE_ID in the generated files.

aws kms create-custom-key-store \
  --custom-key-store-name acmecorp-hsm-store \
  --cloud-hsm-cluster-id cluster-xxxxxxxx \
  --trust-anchor-certificate file://CustomerCA.crt \
  --key-store-password '<kmsuser-password-from-step-3>' \
  --region eu-central-1

The response contains "CustomKeyStoreId": "cks-xxxxxxxx"this is your real value. The key store starts Disconnected.

See KMS — Creating an AWS CloudHSM key store for the full set of options (KMS HSM key store vs. external key store).

Step 5 — Connect the custom key store

aws kms connect-custom-key-store --custom-key-store-id cks-xxxxxxxx \
  --region eu-central-1

# Watch state -> ConnectedState=CONNECTED (takes ~20 minutes; KMS provisions a
# private endpoint into the CloudHSM cluster VPC).
aws kms describe-custom-key-stores --custom-key-store-id cks-xxxxxxxx \
  --query 'CustomKeyStores[0].ConnectionState'

Until ConnectionState=CONNECTED, any CreateKey against the store will fail.

Step 6 — Replace the placeholder in the generated files

The generator emitted PLACEHOLDER_CLOUDHSM_KEY_STORE_ID everywhere a CMK references the store (see PLACEHOLDERS.md for the full file list). Substitute the real ID:

# From the bundle root:
grep -rl PLACEHOLDER_CLOUDHSM_KEY_STORE_ID . \
  | xargs sed -i.bak 's/PLACEHOLDER_CLOUDHSM_KEY_STORE_ID/cks-xxxxxxxx/g'

Verify nothing leaked through:

grep -r PLACEHOLDER_CLOUDHSM_KEY_STORE_ID .   # should print nothing

You are now ready to run tofu apply (OpenTofu), cdk deploy (CDK), or the LZA pipeline.

LZA caveat: the Landing Zone Accelerator's keySets schema does not natively bind to a CloudHSM custom key store. For the LZA format, the generated security-config.yaml documents each HSM-eligible key in comments and you must recreate each key out-of-band post-deploy:

aws kms create-key \
  --origin AWS_CLOUDHSM \
  --custom-key-store-id cks-xxxxxxxx \
  --description "..." \
  --key-usage ENCRYPT_DECRYPT

Then point the LZA-managed alias at the new key ID. The OpenTofu, CDK, and tfvars formats bind to the custom key store directly via the placeholder substitution.

Step 7 — Ongoing operations

  • Backups: AWS automatically backs the cluster up to an S3 bucket in your account every 24 hours. Encrypted with an AWS-owned key — you cannot disable this.
  • Rotation: automatic key rotation is not supported for HSM-backed KMS keys (AWS-side limitation). To rotate, create a new key in the same custom key store, re-point the alias, and disable the old key. Plan this into the runbook.
  • Adding more HSMs: add a third HSM before any maintenance window if you want to keep HA during HSM replacement.
  • Deleting the cluster: delete all HSMs first, then the cluster. KMS keys in a disconnected store become unusable; you cannot recover them without the cluster.

References