This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/database/migrations/003_vault.sql
2026-02-24 10:44:12 +00:00

49 lines
2.6 KiB
SQL

-- 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';