Copy architecture docs, ADRs, storage domain specs, research, reviews, and 56 storage architecture tasks from the alkhub_ts monorepo. Adapt for standalone @alkdev/hub repo structure (src/ not packages/hub/). Sanitize all sensitive information: - Replace private IPs (10.0.0.1) with localhost defaults - Remove internal server hostnames (dev1, ns528096) - Replace /workspace/ private paths with npm package references - Remove hardcoded credentials from examples - Rewrite infrastructure.md without private network details Add Deno project scaffolding: deno.json (pinned deps), .gitignore, AGENTS.md, entry point. Migrate existing code stubs (crypto, config types, logger) with updated import paths.
3.2 KiB
ADR-008: Secrets encrypted at rest with key versioning
- Status: Accepted (revised 2026-04-23)
- Date: 2026-04-19
- Revised: 2026-04-23
- Deciders: alkdev
Context
API keys, passwords, OAuth tokens, and SSH keys for external services must be stored securely. The crypto.ts utility from ade-v0 (AES-256-GCM + PBKDF2 with key version support) is battle-tested.
The original decision specified reading the encryption key from an environment variable (HUB_ENCRYPTION_KEY). This is a security concern: environment variables are readable via /proc/PID/environ by any process with the same UID on the host, and are visible in docker inspect. In a multi-container Docker environment, this is a real attack surface.
Decision
Copy crypto.ts to packages/core/utils/crypto.ts. Store encrypted secrets in client_secrets.value as EncryptedData { keyVersion, salt, iv, data }.
Two-layer key model (revised from original):
-
Master key — Provisioned via Docker secret (
/run/secrets/hub_master_key). tmpfs-backed, never on container filesystem, not visible in/proc/environ. Used only to decrypt the config file's encrypted fields. Rarely rotated (requires redeploying the Docker secret). -
Data encryption keys — Stored in the config file's
encryptionKeysfield (itself encrypted with the master key). Multi-key format:v1:base64,v2:base64— the first key is "current" (used for new encryptions), all keys are available for decryption (enables rotation). Generated viacrypto.generateEncryptionKey(). Rotated by updating the config file and re-encryptingclient_secretsrows — no Docker secret change needed.
Key versioning supports rotation — bump keyVersion, re-encrypt on next access. The rotation protocol is defined in storage/services.md.
No environment variables for secrets or important configuration. This is a hard rule. Non-sensitive convenience vars (e.g., ALKHUB_CONFIG_PATH) are acceptable. Nothing that would be damaging if exposed via /proc may be in an env var.
Full config system specification: docs/architecture/hub-config.md. Startup sequence: docs/architecture/hub-startup.md.
Consequences
Encryption keys must be available at runtime. If lost, all secrets unrecoverable. Standard for symmetric encryption.
Positive: Key versioning enables rotation without downtime. Proven crypto implementation. Docker secrets eliminate the /proc/environ leak vector. Two-layer keys allow independent rotation schedules (master key rarely, data keys as needed). Config file with encrypted fields is safe to version-control (ciphertext only).
Negative: Encryption key loss means total data loss (same as before). Two keys to manage instead of one. Slightly more complex deployment (mount config file + secret, rather than just setting env vars). Config file must be prepared with the alkhub-config CLI tool before deployment.
Mitigated by: Storing master key in Docker secrets (not DB, not env), supporting key rotation so compromised keys can be cycled, alkhub-config tool automating config file preparation, infrastructure.md documenting the Docker deployment pattern.