Changeset 0.9.4 (#54)
This commit is contained in:
48
server/database/migrations/003_vault.sql
Normal file
48
server/database/migrations/003_vault.sql
Normal file
@@ -0,0 +1,48 @@
|
||||
-- 003_vault.sql — API Key Encryption + User Vault
|
||||
-- v0.9.4: Two-tier encryption for API keys
|
||||
--
|
||||
-- Phase 1 (this migration): Add new columns alongside existing plaintext.
|
||||
-- Phase 2 (Go startup): Backfill — encrypt plaintext keys, generate UEKs.
|
||||
-- Phase 3 (future): Drop api_key_plain after confirmed stable.
|
||||
|
||||
-- =========================================
|
||||
-- 1. USERS — Vault support
|
||||
-- =========================================
|
||||
-- Per-user encryption key (UEK) wrapped with password-derived key (Argon2id).
|
||||
-- UEK protects personal BYOK API keys. Platform admin cannot recover without
|
||||
-- the user's password.
|
||||
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS encrypted_uek BYTEA;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS uek_salt BYTEA;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS uek_nonce BYTEA;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS vault_set BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
COMMENT ON COLUMN users.encrypted_uek IS 'UEK encrypted with Argon2id(password)-derived key';
|
||||
COMMENT ON COLUMN users.uek_salt IS 'Argon2id salt for UEK derivation';
|
||||
COMMENT ON COLUMN users.uek_nonce IS 'AES-GCM nonce for UEK wrapping';
|
||||
COMMENT ON COLUMN users.vault_set IS 'true once UEK has been generated and wrapped';
|
||||
|
||||
-- =========================================
|
||||
-- 2. PROVIDER_CONFIGS — Encrypted key storage
|
||||
-- =========================================
|
||||
-- Rename current plaintext column, add encrypted BYTEA columns.
|
||||
-- Backfill happens in Go (needs ENCRYPTION_KEY env var).
|
||||
|
||||
-- Keep plaintext temporarily for backfill; Go startup reads it, encrypts,
|
||||
-- writes to new columns, then NULLs it out.
|
||||
ALTER TABLE provider_configs RENAME COLUMN api_key_enc TO api_key_plain;
|
||||
ALTER TABLE provider_configs ADD COLUMN IF NOT EXISTS api_key_enc BYTEA;
|
||||
ALTER TABLE provider_configs ADD COLUMN IF NOT EXISTS key_nonce BYTEA;
|
||||
ALTER TABLE provider_configs ADD COLUMN IF NOT EXISTS key_scope TEXT;
|
||||
|
||||
-- Backfill key_scope from existing scope column (safe default)
|
||||
UPDATE provider_configs SET key_scope = scope WHERE key_scope IS NULL;
|
||||
|
||||
-- Now make it NOT NULL with default
|
||||
ALTER TABLE provider_configs ALTER COLUMN key_scope SET NOT NULL;
|
||||
ALTER TABLE provider_configs ALTER COLUMN key_scope SET DEFAULT 'global';
|
||||
|
||||
COMMENT ON COLUMN provider_configs.api_key_plain IS 'DEPRECATED: plaintext key, cleared after vault backfill';
|
||||
COMMENT ON COLUMN provider_configs.api_key_enc IS 'AES-256-GCM encrypted API key (BYTEA)';
|
||||
COMMENT ON COLUMN provider_configs.key_nonce IS 'AES-GCM nonce for api_key_enc';
|
||||
COMMENT ON COLUMN provider_configs.key_scope IS 'Encryption tier: global/team use env key, personal uses UEK';
|
||||
Reference in New Issue
Block a user