feat(crypto): cfg.kms + key-manager factory + AWS KMS provider (Step 6.7b) - #156
Merged
Merged
Conversation
…6.7b) Make BYOK configurable + provider-selectable. New cfg.kms (enabled / provider ∈ noop|local|aws / default_key_id / region / local_key) + tenants[].kms_key_id (a KMS ARN for aws, a hex 32-byte KEK for local). build_key_manager_from_config factory (in the gateway, lazy rag-backends imports so rag-backends stays config-free) selects the provider; build_app(key_manager=) exposes app.state.key_manager + app.state.kms_enabled (passthrough NoopKeyManager when disabled). AwsKmsKeyManager subclasses EnvelopeKeyManager and wraps/unwraps the DEK via AWS KMS Encrypt/Decrypt for the tenant's customer-managed key (over the already-present aioboto3 — no new dep). Per-tenant CMK from the key-id map (+ default_key_id); any KMS failure or missing key id maps to KeyUnavailableError (sealing). An injectable client seam makes it fully unit-testable with a fake KMS — no AWS creds/network. Scope: AWS provider + config + factory + the app.state.key_manager seam. Deferred: GCP/Azure/Vault providers + key rotation (6.7c); wiring EncryptingStorage into the ingest path (blocked on tiered-storage plumbing — chunk content is inline today). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second slice of Step 6.7 — BYOK: makes the 6.7a encryption library configurable + provider-selectable, and adds the first cloud provider (AWS KMS).
cfg.kms(enabled/provider∈noop/local/aws/default_key_id/region/local_key) +tenants[].kms_key_id— the per-tenant key reference (a KMS ARN foraws, a hex 32-byte KEK forlocal).build_key_manager_from_config(cfg)(in the gateway, lazyrag-backendsimports sorag-backendsstays config-free) selects the provider.build_app(key_manager=…)exposesapp.state.key_manager+app.state.kms_enabled(passthroughNoopKeyManagerwhen disabled).AwsKmsKeyManager(rag-backends/kms/aws.py) subclassesEnvelopeKeyManagerand wraps/unwraps the DEK via AWS KMS Encrypt/Decrypt for the tenant's customer-managed key — over the already-presentaioboto3(no new dependency). Per-tenant CMK from the key-id map (+default_key_id); any KMS failure (revoked / denied / unreachable) or a missing key id →KeyUnavailableError(sealing). An injectableclientseam makes it fully unit-testable with a fake KMS — no AWS creds / network.Scope / deferred: AWS provider + config + factory + the
app.state.key_managerseam. 6.7c — GCP KMS / Azure Key Vault / HashiCorp Vault providers (sameEnvelopeKeyManagerpattern, behind[kms-*]extras) + zero-downtime key rotation. WiringEncryptingStorageinto the ingest path is deferred (chunk content is inline today; it lands with tiered storage, ADR-0007).Tests & gates
tests/kms/test_aws.py— round-trip, KMS-key-bound cross-tenant block, sealing on missing key, default-key fallback, KMS-error → KeyUnavailableError); config defaults; factory (noop/local/aws); gateway wiring (app.state.key_manager+kms_enabled+ a local round-trip).tests/ packages/2353 passed, 1 skipped; gateway 289 passed (+8, no regression). Green: ruff,mypy --strict(306 files), RAG001, policy-coverage, log-schema; only the intendeddist/rag.schema.*regen (no core-schema / openapi drift).Documentation
cfg.kms+ AWS + per-tenant key + factory section.Test plan
uv run pytest tests/ packages/ -m "not integration"— 2353 passed, 1 skippeduv run pytest apps/gateway/tests— 289 passedmypy --strict(306) + RAG001 + policy-coverage + log-schema; config schema-drift regenerated🤖 Generated with Claude Code