---
title: "Keep encryption keys in a key service · Agent Wranglers"
url: https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets/key-management
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Keep encryption keys in a key service

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Configuration and secrets](https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- Level: Recommended
- Chapter: [Configuration and secrets](https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets)
- Rule: Encrypt stored data with keys held in a key management service that never hands out the key itself. Rotate each key automatically, and keep the people who manage keys apart from the roles that use them.
- How: Use the cloud's key service, such as AWS KMS, Google Cloud KMS or Azure Key Vault, or a self-hosted one such as OpenBao. Create each key and its policy in code. Give the app's role encrypt and decrypt rights on its own key only. Give the key admin role rights to manage keys but not to decrypt. Turn on automatic rotation every 365 days at most. Rotation keeps the old key versions, so old data still decrypts. A deleted key makes its data unreadable for good. Set the longest waiting period the service allows, 30 days on AWS, and alert on every scheduled deletion. Encrypt single fields in the app with the same keys, as [Encrypt the most sensitive fields](https://agentwranglers.se/playbook/data/personal-data/field-encryption) describes. Disks, databases and backups take their keys from here, as [Encrypt data on the wire and on disk](https://agentwranglers.se/playbook/adversarial-testing/data-and-secrets/encrypt-data) requires.
- Check: The script below lists no customer-managed key without automatic rotation. No key policy grants every key action to a role other than the key admin role. Schedule the deletion of a test key in a sandbox account, and the alert arrives within 15 minutes.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Terraform example

```hcl
resource "aws_kms_key" "orders" {
  description             = "Encrypts the orders database"
  enable_key_rotation     = true
  rotation_period_in_days = 365
  deletion_window_in_days = 30
}

resource "aws_cloudwatch_event_rule" "key_deletion" {
  name = "kms-key-scheduled-for-deletion"
  event_pattern = jsonencode({
    source = ["aws.kms"]
    detail = { eventName = ["ScheduleKeyDeletion", "DisableKey"] }
  })
}
```

### Python example

```python
import boto3

kms = boto3.client("kms")

def keys_without_rotation():
    for page in kms.get_paginator("list_keys").paginate():
        for key in page["Keys"]:
            meta = kms.describe_key(KeyId=key["KeyId"])["KeyMetadata"]
            if meta["KeyManager"] != "CUSTOMER" or meta["KeyState"] != "Enabled":
                continue
            if meta.get("KeySpec") == "SYMMETRIC_DEFAULT" and not kms.get_key_rotation_status(KeyId=key["KeyId"])["KeyRotationEnabled"]:
                yield key["KeyId"]

for key_id in keys_without_rotation():
    print(key_id)
```

### TypeScript example

```ts
import { KMSClient, paginateListKeys, DescribeKeyCommand, GetKeyRotationStatusCommand } from '@aws-sdk/client-kms';

const kms = new KMSClient({});

for await (const page of paginateListKeys({ client: kms }, {})) {
  for (const { KeyId } of page.Keys ?? []) {
    const { KeyMetadata: meta } = await kms.send(new DescribeKeyCommand({ KeyId }));
    const isRotatableCustomerKey = meta.KeyManager === 'CUSTOMER' && meta.KeyState === 'Enabled' && meta.KeySpec === 'SYMMETRIC_DEFAULT';
    if (!isRotatableCustomerKey) continue;
    const { KeyRotationEnabled } = await kms.send(new GetKeyRotationStatusCommand({ KeyId }));
    if (!KeyRotationEnabled) console.log(KeyId);
  }
}
```

## Sources

- [NIST SP 800-57 Part 1 Rev. 5 Recommendation for Key Management](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final)
- [AWS Well-Architected SEC08-BP01 Implement secure key management](https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/sec_protect_data_rest_key_mgmt.html)

## Related rules

- [Erase retired databases and every copy](https://agentwranglers.se/playbook/data/personal-data/retired-data-stores) in Data
- [Encrypt the most sensitive fields](https://agentwranglers.se/playbook/data/personal-data/field-encryption) in Data
- [Encrypt data on the wire and on disk](https://agentwranglers.se/playbook/adversarial-testing/data-and-secrets/encrypt-data) in Security testing

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets/key-management">Agent Wranglers infrastructure playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Rotate secrets automatically](https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets/automatic-secret-rotation)
- [Configuration and secrets](https://agentwranglers.se/playbook/infrastructure/configuration-and-secrets)
