---
title: "Keep encryption keys in a key service · Agent Wranglers"
url: https://agentwranglers.se/playbook/application-security/cryptography-and-keys/key-management
id: APS-57
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1619
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 [Cryptography and keys](https://agentwranglers.se/playbook/application-security/cryptography-and-keys.md).

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

- ID: APS-57
- Level: Recommended
- Chapter: [Cryptography and keys](https://agentwranglers.se/playbook/application-security/cryptography-and-keys.md)
- 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.
- 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.
- 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/application-security/cryptography-and-keys/field-encryption.md) describes. Disks, databases and backups take their keys from here, as [Encrypt data on the wire and on disk](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/encrypt-data.md) requires.

## 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

- DAT-35 [Erase retired databases and every copy](https://agentwranglers.se/playbook/data/personal-data/retired-data-stores.md) in Data and databases
- DAT-80 [Encrypt database storage with a key you control](https://agentwranglers.se/playbook/data/database-security/encryption-at-rest.md) in Data and databases
- DAT-74 [Give each tenant its own encryption key when customers ask to hold it](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-encryption-keys.md) in Data and databases
- INF-89 [Record which governments can demand each provider's data](https://agentwranglers.se/playbook/infrastructure/hosting-platforms/provider-jurisdiction.md) in Infrastructure and environments
- DEN-24 [Swap direct identifiers for keyed pseudonyms](https://agentwranglers.se/playbook/data-engineering/personal-data-in-the-warehouse/warehouse-pseudonyms.md) in Data engineering
- APS-58 [Encrypt the most sensitive fields](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/field-encryption.md) in Application security
- APS-54 [Encrypt data on the wire and on disk](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/encrypt-data.md) in Application security
- APS-103 [Wrap data keys with a key-encryption key](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/envelope-encryption.md) in Application security

**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/application-security/cryptography-and-keys/key-management">Agent Wranglers application security playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Use only standard cryptography](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/standard-cryptography.md)
- Next: [Wrap data keys with a key-encryption key](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/envelope-encryption.md)
- [Cryptography and keys](https://agentwranglers.se/playbook/application-security/cryptography-and-keys.md)
