Files
warmbly/internal/infrastructure/kms/factory.go
T
Matthew Meszaros a8fa4386d5 infra(kms): pluggable Provider interface + local AES-256-GCM impl
Define kms.Provider so the cipher service can swap between AWS KMS and
a self-hostable local-key path. Local impl uses AES-256-GCM with the
master key sourced from KMS_LOCAL_MASTER_KEY (base64) or KMS_LOCAL_MASTER_KEY_FILE.
Factory FromEnv selects at boot via KMS_PROVIDER; defaults to aws for
backwards compatibility.

Ciphertext blob format is opaque: switching providers requires a DEK
migration because each provider can only decrypt its own blobs.

10 tests cover round-trip, tamper detection, nil-key rejection, and
factory env-selection paths.
2026-05-27 14:40:56 +00:00

41 lines
1.2 KiB
Go

package kms
import (
"context"
"fmt"
"os"
"github.com/aws/aws-sdk-go-v2/aws"
)
// FromEnv constructs the active KMS provider from environment variables.
//
// KMS_PROVIDER=aws -> NewAWS (uses awscfg, KMS_AWS_KEY_ID or fallbackAWSKeyID)
// KMS_PROVIDER=local -> NewLocalFromEnv
// (unset) -> defaults to "aws" for backwards compatibility
//
// Callers pass an AWS config that's only consulted when the AWS provider is
// selected. The fallbackAWSKeyID is used when KMS_AWS_KEY_ID is empty — this
// preserves the historical "alias/master-key[-dev]" default used at boot.
func FromEnv(ctx context.Context, awscfg aws.Config, fallbackAWSKeyID string) (Provider, error) {
provider := os.Getenv("KMS_PROVIDER")
if provider == "" {
provider = "aws"
}
switch provider {
case "aws", "aws-kms":
keyID := os.Getenv("KMS_AWS_KEY_ID")
if keyID == "" {
keyID = fallbackAWSKeyID
}
if keyID == "" {
return nil, fmt.Errorf("kms: aws provider requires KMS_AWS_KEY_ID or fallback key id")
}
return New(ctx, awscfg, keyID)
case "local":
return NewLocalFromEnv()
default:
return nil, fmt.Errorf("kms: unknown KMS_PROVIDER %q (want: aws, local)", provider)
}
}