diff --git a/README.md b/README.md index eabed5f..33d9b80 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,209 @@ Output will for example look like: Where the `accessor` ID (here `66IzIsoOpXycYqF33JmfIb8G`) is what you're going to want to use in your CLI command `vault token revoke`. +### Auto-unseal with AWS Key Management Service + +So far we've unsealed Vault after every daemon start with multiple Shamir's Secret Sharing unseal keys or Shamir unseal keys for short. We can have a Vault instance auto-unseal itself by accessing Amazon Web Services (AWS) Key Management Service (KMS) for example via public Internet. Vault supports other providers, we're going with AWS KMS as an example. + +> [!WARNING] +> Per [aws.amazon.com/kms/pricing](https://aws.amazon.com/kms/pricing) having one KMS key costs USD 1 per month pro-rated per hour of key existence. The following example assumes you're creating a symmetric encryption and decryption key with KMS as key material origin in a single region. As such API actions `kms:Encrypt`, `kms:Decrypt` and `kms:DescribeKey` (among others that we don't care about) are included in AWS KMS' Free Tier for up to 20,000 requests monthly. As long as Vault auto-unseals at most 20,000 times a month these operations won't cost you anything. A flat fee of USD 1 for the existence of a KMS key, however, applies. + +#### Create resources + +In AWS one way to get the necessary resources is to: + +* In Key Management Service (KMS) + * Create one key + * Symmetric + * Encryption and decryption + * Key material origin KMS + * Single region + * Write down its Amazon Resource Name (ARN) +* In Identity and Access Management (IAM) + * Create an IAM policy in plain JSON, replace `` with ARN from above: + ``` + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "EnableKMSForVaultAutoUnseal", + "Effect": "Allow", + "Action": [ + "kms:Encrypt", + "kms:Decrypt", + "kms:DescribeKey" + ], + "Resource": "" + } + ] + } + ``` + * Create a user group, attach above customer-managed policy to it + * Create a user + * Add it to the user group + * Create an access key and secret access key + +#### Migrate Vault to auto-unseal with AWS KMS + +The setup roughly goes like so: + +* Configure Vault to use AWS KMS +* (Re-)Start Vault daemon +* Via CLI migrate unseal mechanism to AWS KMS + +One way to configure Vault to do AWS KMS auto-unsealing is to specify the following environment variables. All but the fifth one (`VAULT_SEAL_TYPE=awskms`) depend on the KMS key you created so fill in the blanks with your specific key material. We're assuming that you have a Vault instance running with Docker Compose or a similar mechanism, we'll leave the implementation details to you for how to get these five environment variables into your Vault instance. + +``` +AWS_ACCESS_KEY_ID= +AWS_REGION= +AWS_SECRET_ACCESS_KEY= +VAULT_AWSKMS_SEAL_KEY_ID= +VAULT_SEAL_TYPE=awskms +``` + +(Re-)Start Vault to make the variables take effect. Vault (for example in its Docker log) will then indicate that it's entering seal migration mode: + +``` +core: entering seal migration mode; Vault will not automatically unseal even if using an autoseal: from_barrier_type=shamir to_barrier_type=awskms +``` + +At first glance when in this mode Vault will appear to behave like normal in that its web UI will be up and available. However, any attempt to unseal Vault with your previous unseal keys will do nothing. + +Log in to Vault with the `vault` CLI client, see [Authenticate against Vault](#authenticate-against-vault) above. Issue the migration command as many times as you have your required Shamir unseal keys configured, enter them one at a time. + +``` +# vault operator unseal -migrate +# Which will prompt for: +Unseal Key (will be hidden): +``` + +After each `vault operator unseal -migrate` command the `vault` binary will print the current migration status like so (here after entering one of two Shamir unseal keys): + +``` + Key Value + --- ----- + Seal Type awskms + Recovery Seal Type shamir + Initialized true +--> Sealed true + Total Recovery Shares 3 + Threshold 2 +--> Unseal Progress 1/2 + Unseal Nonce dc..86 + Seal Migration in Progress true + Version 1.18.3 + Build Date 2024-12-16T14:00:53Z + Storage Type file + HA Enabled false +``` + +After entering the last unseal key vault will be unsealed and migrated. This will look like so: + +``` +# vault status + + Key Value + --- ----- + Seal Type awskms + Recovery Seal Type shamir + Initialized true +--> Sealed false + Total Recovery Shares 3 + Threshold 2 + Version 1.18.3 + Build Date 2024-12-16T14:00:53Z + Storage Type file + Cluster Name vault-cluster + Cluster ID 9a..01 + HA Enabled false +``` + +In its log output Vault will indicate that seal migration is complete. That's all there it to it: after every subsequent Vault daemon start it will attempt to access AWS KMS via public Internet and auto-unseal Vault. + +#### Migrate back to Shamir unseal keys + +Once a Vault instance is configured to auto-unseal with AWS KMS or any other key management provider Vault will not ever unseal via any other mechanism. If you lose Internet connectivity to AWS or the key gets deleted at AWS your Vault instance will remain locked. Your way out in this case is to migrate back to Shamir unseal keys. We'll assume that you're running Vault with Docker Compose and that you have environment variables set like so: + +``` +AWS_ACCESS_KEY_ID= +AWS_REGION= +AWS_SECRET_ACCESS_KEY= +VAULT_AWSKMS_SEAL_KEY_ID= +VAULT_SEAL_TYPE=awskms +``` + +Your container also has a bind-mounted HCL-formatted config file `/vault/config/vault.hcl`: + +``` +backend "file" { + path = "/vault/file" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 1 +} + +api_addr = "https://fully.qualified.domain.name" +disable_clustering = true +ui = true +``` + +Add this section to the file: + +``` +seal "awskms" { + disabled = true +} +``` + +So that the end result looks like so: + +``` +backend "file" { + path = "/vault/file" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 1 +} + +api_addr = "https://fully.qualified.domain.name" +disable_clustering = true +ui = true + +seal "awskms" { + disabled = true +} +``` + +Also remove the environment variable `VAULT_SEAL_TYPE` from your container or at least change it to an empty string (`VAULT_SEAL_TYPE=`). Now (re-)start Vault and it'll report: + +``` +core: entering seal migration mode; Vault will not automatically unseal even if using an autoseal: from_barrier_type=awskms to_barrier_type=shamir +``` + +The rest is the reverse of [Migrate Vault to auto-unseal with AWS KMS](#migrate-vault-to-auto-unseal-with-aws-kms): log in to Vault via CLI `vault` binary and do a few incantations of `vault operator unseal -migrate`. Use your Shamir unseal keys. After successful migration `vault` binary will print: + +``` + Key Value + --- ----- +--> Seal Type shamir + Initialized true + Sealed false + Total Shares 3 + Threshold 2 + Version 1.18.3 + Build Date 2024-12-16T14:00:53Z + Storage Type file + Cluster Name vault-cluster + Cluster ID 9a..01 + HA Enabled false +``` + +You now have decoupled Vault from AWS KMS and are back to using Shamir unseal keys. After every Vault daemon restart you'll have to manually unseal your instance again. + ## Clean-up If during any of the above steps you've used the Vault command-line client to authenticate against Vault with your `root` token make sure that client's `~/.vault-token` file is deleted. It contains the verbatim `root` token.