AWS KMS encryption provider
AWS Key Management Service provider implementing crypto.EncryptionProvider. Master keys never leave AWS's FIPS 140-2 validated HSMs. Every direct encrypt and decrypt call goes through the KMS API. The provider is a drop-in EncryptionProvider. You write NewProvider plus two piko.With options, and Piko handles the rest.
Overview
The defining property of KMS is that the master key cannot leave the HSM. You hand KMS plaintext and get back ciphertext (or a wrapped data key). The key material itself stays in the HSM, audited through CloudTrail, gated by IAM policies, and rotatable on a schedule AWS manages. The provider supports direct encryption (small payloads, one KMS call per operation), envelope encryption through GenerateDataKey, and streaming encryption for large objects. Envelope mode encrypts a batch of objects with a single data key, then encrypts that data key with KMS. The result is fewer KMS calls and lower per-byte cost on bulk workloads.
Streaming is the typical path for large storage objects. EncryptStream and DecryptStream issue exactly one KMS call per stream (GenerateDataKey to encrypt, Decrypt to read back). They then run local AES-256-GCM at constant memory of about 64 KB regardless of file size. Large uploads stay cheap, and you write no envelope code yourself.
KMS is auditable, slower than local crypto, and billed per request. Direct operations add network latency and show up in CloudTrail with the calling principal. Compliance and audit requirements that demand HSM-backed keys are the standard reason to accept those tradeoffs. KMS rotates the master key on its own schedule, so existing ciphertext keeps decrypting without re-encryption.
The crypto service layer wraps every provider in a circuit breaker (5 consecutive failures opens it for 30 seconds), so a KMS outage fails fast instead of stalling the caller. Bulk workloads still use envelope encryption to reduce KMS pressure. All public methods are safe for concurrent use.
Requirements
- An AWS account with a customer master key (CMK) created in the chosen region, the provider does not create keys.
- IAM permissions on the key:
kms:Encrypt,kms:Decrypt,kms:GenerateDataKey,kms:DescribeKey. Addkms:ReEncrypt*for key rotation flows. - AWS credentials via the standard chain (environment, shared config, EC2/ECS/Lambda role, IAM Identity Centre).
- Network egress to the region's KMS endpoint (for example
kms.eu-west-1.amazonaws.com).
Configuration
import (
"context"
"piko.sh/piko/wdk/crypto/crypto_provider_aws_kms"
)
provider, err := crypto_provider_aws_kms.NewProvider(ctx, crypto_provider_aws_kms.Config{
KeyID: "alias/myapp-prod", // required: key ID, ARN, alias name, or alias ARN
Region: "eu-west-1", // required
MaxRetries: 3, // optional: SDK retry attempts, default 3
})
if err != nil {
return err
}
NewProvider validates the config and applies defaults for you, so you only need KeyID and Region. A zero or unset MaxRetries becomes 3, so you cannot set it to 0 to disable retries.
NewProvider is pure Go with no build tags and no CGO. It compiles and runs in every Piko run mode, including the interpreted dev mode and compiled binaries.
NewProvider makes a live DescribeKey call to AWS at construction time. Wiring this provider into piko.New blocks on KMS reachability. It fails at startup if KMS is unreachable, the key does not exist, or the principal lacks kms:DescribeKey. This surfaces a misconfigured key as a boot error, not as a first-request failure.
Bootstrap
ssr := piko.New(
piko.WithCryptoProvider("aws_kms", provider),
piko.WithDefaultCryptoProvider("aws_kms"),
)
WithCryptoProvider registers the provider under a name. WithDefaultCryptoProvider selects the active one. When a storage service is also wired, Piko registers the crypto stream transformer against the storage pipeline on its own. The pipeline then encrypts uploads at rest with no extra glue.
The provider implements the same EncryptionProvider port as the local AES-GCM and GCP KMS providers. You can register a local provider for development and KMS for production, then switch between them through WithDefaultCryptoProvider alone, with no application code change.
Tradeoffs
KMS bills per request and adds round-trip latency. A hot path doing a KMS call per object is both expensive and slow. The standard mitigation is envelope encryption. Ask KMS for a data key once per session (or once per batch). Encrypt the bulk data locally with the plaintext data key, and store the wrapped data key alongside the ciphertext. The Piko crypto service supports this pattern without extra configuration. The provider returns each generated data key in secure memory and zeroes the plaintext after use, so it handles key hygiene for you. Reach for envelope encryption before you reach for more KMS quota.
See also
Other crypto providers:
- GCP KMS, equivalent HSM-backed model on Google Cloud.
- Local AES-GCM, in-process AES-256-GCM with a local key file. Trades the audit trail and per-op latency of KMS for zero per-op cost.
Storage transformer (the typical consumer):
- Crypto transformer, wraps the storage pipeline so this provider encrypts uploads at rest.
Framework docs:
- How to encrypt and decrypt data, wiring the crypto service end-to-end.
- Crypto API reference, every type and method on the crypto service.
External:
- AWS KMS Developer Guide, authoritative reference.
- Envelope encryption pattern, the standard pattern for bulk operations.
- KMS pricing, read this before high-volume rollouts.