Encryption Envelope Spec (MVP Baseline)¶
Purpose:
- Define one canonical encrypted-field shape for _enc columns and sensitive payloads.
- Prevent ad-hoc encryption formats across services.
Scope:
- Applies to allocations.ssh_private_key_enc, nodes.access_secret_enc, and any future credential-bearing JSON fields.
1. Envelope Shape¶
All encrypted JSON payloads must use this object structure:
{
"v": 1,
"alg": "AES-256-GCM",
"key_id": "local-dev-kek-1",
"nonce": "base64url",
"ct": "base64url"
}
Field rules:
- v: integer schema version (1 for MVP).
- alg: encryption algorithm identifier (AES-256-GCM).
- key_id: logical KEK identifier used to encrypt/decrypt.
- nonce: base64url-encoded GCM nonce.
- ct: base64url-encoded ciphertext+tag bytes.
2. Cryptographic Baseline¶
- Primitive: AES-256-GCM.
- Key size: 32 bytes.
- Nonce size: 12 bytes (GCM standard).
- AAD: none in MVP.
- Encoding:
base64.RawURLEncodingfornonceandct.
3. Key Source by Environment¶
- Local/dev: static 32-byte key from environment variable (documented in local-dev env examples).
- Production: KEK material from managed KMS/HSM;
key_idmust map to KMS versioned key metadata.
4. Rotation Model¶
- New writes use current active
key_id. - Reads must support decrypting any still-supported
key_id. - Rotation strategy:
- enable new key for writes
- background re-encrypt existing rows
- retire old key only after migration verification
5. Operational Rules¶
- Never log plaintext secret values.
- Never log full envelope payloads at info/error level.
- Include only
key_idandvin diagnostic logs when needed. - Invalid envelope payloads must fail closed (treat as decryption error).
6. Go Helper¶
Canonical implementation lives in:
- packages/shared/crypto/envelope.go
- packages/shared/crypto/envelope_test.go
All services must use this helper (or strict equivalent) for envelope serialization and AES-GCM operations.