Credential Encryption

For: Platform engineers and security teams evaluating the data-at-rest security model for inline AI provider credentials.

Security Overview | mTLS | Bundle Signing | Credential Encryption

Axemere encrypts AI provider API keys before they are stored in the database using envelope encryption: a fresh key generated per credential, wrapped by a dedicated Cloud KMS key that never leaves KMS. A database backup, stolen snapshot, or SQL injection attack yields only ciphertext, and unwrapping it requires a live KMS call, not just database access.

Table of Contents


What Is Encrypted

Credential modeWhat is stored in DBEncrypted?
inlineActual AI provider API keyYes — AES-256-GCM
aliasName of an environment variable (e.g. OPENAI_API_KEY)No — not a secret
byokEmpty: caller supplies the key at request timeN/A

Only inline mode stores a real secret in the database. alias and byok modes do not need encryption because no secret is persisted.


How Envelope Encryption Works

Axemere uses genuine envelope encryption: a fresh, random 256-bit key (the DEK, data encryption key) is generated for every credential and used to encrypt it locally with AES-256-GCM (NIST SP 800-38D). The DEK itself is then wrapped by a call to a dedicated Cloud KMS key (the KEK, key encryption key) that never leaves KMS: never in an environment variable, never in the control plane's process memory outside the moment of a wrap/unwrap call, never readable by anyone with database or pod access alone.

AES-256-GCM
encrypt with the DEK

wraps/unwraps
the DEK

stored in the database

read

AES-256-GCM
decrypt with the DEK

Plaintext API key
sk-proj-...

Random DEK
generated per credential

Cloud KMS key
(never leaves KMS)

Encrypted credential
(ciphertext + wrapped DEK)

Database

Plaintext API key
sent to gateway over mTLS

Self-hosted and other-cloud deployments, not yet covered by this Cloud KMS integration, use a simpler fallback: direct AES-256-GCM encryption under a single platform-held key. That fallback still yields only ciphertext from a database backup or SQL injection, but the key itself is held directly rather than in a hardware-backed KMS, a weaker guarantee against an attacker with broader infrastructure access. The managed, GCP-hosted control plane runs the Cloud KMS-backed version described above.


Encryption Flow

When an inline credential is registered via the admin API or console:

  1. The control plane receives the plaintext API key.
  2. A fresh, random 256-bit DEK is generated for this credential.
  3. AES-256-GCM encrypts the value locally with the DEK.
  4. The DEK is wrapped with a single Cloud KMS call against the dedicated KEK, then discarded from memory.
  5. The wrapped DEK and the ciphertext are stored together in the database; no plaintext, and no unwrapped DEK, ever reaches storage.

Decryption Flow

When a gateway requests its credential set from the control plane:

  1. The control plane reads the stored encrypted value.
  2. The wrapped DEK is unwrapped with a Cloud KMS call (a short-lived, TTL'd in-process cache avoids a KMS round trip on every request for the same credential).
  3. AES-256-GCM decrypts the value locally with the unwrapped DEK.
  4. The plaintext API key is returned to the gateway over mTLS; it is never stored or logged by the control plane.

In steady state, every inline credential uses this envelope-encrypted format once the Cloud KMS integration is configured: migration to it runs automatically and idempotently on every control plane startup. A simpler, legacy decrypt path remains in the code as a defensive fallback for a narrow migration-time edge case (a KMS call failing mid-migration on one credential, before the next startup retries it), not because residual legacy-encrypted credentials are expected to persist.

DatabaseCloud KMSControl PlaneGatewayDatabaseCloud KMSControl PlaneGatewayKey used for outbound request to AI provider, never loggedRequest credentials [mTLS]Read stored credentialEncrypted credential (ciphertext + wrapped DEK)Unwrap DEKPlaintext DEKDecrypt with DEKPlaintext API key [over mTLS]

Credential Modes and Encryption Scope

mode: inline
api_key: sk-proj-...

mode: alias
secret_ref: OPENAI_API_KEY

mode: byok
secret_ref: empty

Credential Registration
PUT /v1/admin/credentials

Envelope Encrypt
DEK + Cloud KMS

Store as-is
(env var name, not secret)

Nothing stored
(caller supplies key per-request)

Database: encrypted

Database: OPENAI_API_KEY

Database: null


Threat Model

ThreatMitigated?Notes
Database backup / dump theftYesOnly ciphertext and a wrapped key are in the database; nothing there alone decrypts it
Misconfigured DB IAMYesSame — ciphertext and a wrapped key only
SQL injection on CP DBYesOnly ciphertext and a wrapped key reachable
Compromised CP process memoryNoPlaintext in memory during request lifecycle
Compromised gateway process memoryNoGateway receives plaintext over mTLS for use in outbound requests
mTLS interceptionNoSeparate concern: see mTLS guide
Insider with CP database access but no KMS decrypt permissionYesThe wrapping key never leaves Cloud KMS; database access alone can't unwrap a credential
Insider with both CP infra access AND KMS decrypt permission on the wrapping keyNoFull customer-managed CMEK (a key we never have standing access to) is still future work

Envelope encryption protects the database at rest, and narrows who can decrypt it: unlike a static platform key, unwrapping a credential now requires a live, audited Cloud KMS call against a specific key, not just database access. It does not protect in-flight data or process memory, and it does not yet protect against someone with both infrastructure and the relevant KMS permissions. That's the correct and intended scope today, with full CMEK as the next step.


See Also