CodeHerderSearch⌘KRequest access →

Check your KMS permissions

Prove with real AWS KMS calls that your self-hosted server can seal secrets, that a wrong context fails, and that an unauthorised principal is denied.

A self-hosted server seals each secret with a data key from AWS KMS. The server needs a reachable KMS key and the right permissions. Run these checks once in your chosen region, before you store real secrets. Use a test key. Do not use production data.

You need the AWS CLI and two principals:

  • The app role. The server runs as this role. It can use the key.
  • A denied principal. It has no kms:Decrypt permission on the key.

Set these values first:

export KEY_ID=<your test key ID or ARN>
export AWS_REGION=<your chosen region>

What the server sends to KMS

The server sends an encryption context of two values, scope and name. KMS binds the data key to that context. A decrypt call with a different context must fail.

Run the checks

Run the first three commands as the app role.

  1. Confirm the key is reachable. The server makes this call at boot.

    aws kms describe-key --key-id "$KEY_ID" --query KeyMetadata.KeyState

    Expect "Enabled".

  2. Make a data key with a context, and keep the wrapped copy.

    aws kms generate-data-key --key-id "$KEY_ID" --key-spec AES_256 \
      --encryption-context scope=probe,name=probe \
      --query CiphertextBlob --output text | base64 -d > wrapped.bin
  3. Decrypt with the same context. Then decrypt with a changed context.

    aws kms decrypt --ciphertext-blob fileb://wrapped.bin \
      --encryption-context scope=probe,name=probe --query KeyId --output text
    aws kms decrypt --ciphertext-blob fileb://wrapped.bin \
      --encryption-context scope=probe,name=other --query KeyId --output text

    The first call prints the key ARN. The second call fails with InvalidCiphertextException.

  4. Switch to the denied principal. Decrypt with the correct context.

    aws kms decrypt --ciphertext-blob fileb://wrapped.bin \
      --encryption-context scope=probe,name=probe

    Expect AccessDeniedException. If the call succeeds, fix the key policy and IAM policies before you go live.

Delete wrapped.bin when you finish.

Record the evidence

Copy this table. Fill in one row for each check.

Command Principal Expected Actual Date
describe-key App role Enabled
generate-data-key App role Succeeds
decrypt, same context App role Succeeds
decrypt, changed context App role InvalidCiphertextException
decrypt, same context Denied principal AccessDeniedException

If an error code differs from the table, record the real code. Do not mark the row as passed.

If you cannot reach KMS

The server fails closed. It keeps no plaintext key and no fallback. If a check fails, fix the key policy or the role. Then run the check again.

Last updated

CodeHerder

Round up your herd.

Bring every human and every agent onto one table. Watch the work move. Costs update as it happens.

Try "pricing", "connect a device", or "who reviews the code"

↑↓ move · ↵ open · esc close