Patterns
Secret management (AWS Secrets Manager, Vault, Doppler)
Storing `sk_live_*` outside source code
A Scell.io `sk_live_*` key allows issuing fiscally binding invoices in the tenant's name: leakage is a P0 incident. Four acceptable storage options. AWS Secrets Manager: native IAM integration, automatic rotation, CloudTrail audit, ~$0.40/secret/month. HashiCorp Vault: self-hosted, dynamic secrets, fine-grained ACL, team-operated. Doppler: dev-friendly SaaS, automatic sync to CI/CD/runtime, free up to 5 users. GCP Secret Manager: native Google Cloud integration. FORBIDDEN: `.env` committed to Git, hardcoded in code, in a `NEXT_PUBLIC_*` variable, in a Docker image, in a Helm values.yaml. Mandatory pattern: (1) key loaded at boot via secrets SDK, (2) IAM/ACL restricts access to services that need it, (3) rotation every 90 days, (4) audit log of each access. For DB-stored encrypted derived secrets (S3 access keys, SuperPDP OAuth tokens), provide an idempotent reseed script in case of `ENCRYPTION_KEY` rotation (cf. ai-services-mistral rule).
Key facts
- Options: AWS Secrets Manager, Vault, Doppler, GCP Secret Manager
- FORBIDDEN: .env in Git, NEXT_PUBLIC_*, hardcoded, Docker image
- Boot-time loading via SDK, restrictive IAM/ACL
- 90-day rotation + access audit log
- Idempotent reseed script for DB-encrypted secrets
Code example
// Boot — load Scell key from AWS Secrets Manager
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
import { ScellClient } from '@scell/sdk';
const secrets = new SecretsManagerClient({ region: 'eu-west-3' });
async function loadScellClient(): Promise<ScellClient> {
const cmd = new GetSecretValueCommand({ SecretId: 'prod/scell/api-key' });
const { SecretString } = await secrets.send(cmd);
if (!SecretString) throw new Error('SCELL_API_KEY missing in Secrets Manager');
// Audit access
logger.info('scell.key.loaded', { source: 'aws-secrets-manager' });
return new ScellClient({ apiKey: JSON.parse(SecretString).api_key });
}
export const scell = await loadScellClient();