Files
LambdaMail/migrations/0005_create_acme_tables.up.sql
T

57 lines
2.6 KiB
SQL

-- Self-managed ACME state (PLAN.md section 8.3, mode B).
--
-- This lives in Postgres rather than on disk so that recreating the container
-- keeps the account and the issued certificates. Losing them would force a
-- re-registration and a re-issuance on every deploy, which reaches the CA's
-- rate limits quickly.
--
-- Every secret column is encrypted with the same KEK as the DKIM keys: these
-- are reusable secrets, so they are sealed, never hashed.
CREATE TABLE acme_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- One account per directory URL, so staging and production coexist.
directory_url VARCHAR(255) NOT NULL UNIQUE,
email VARCHAR(255),
registration_uri TEXT,
private_key_enc BYTEA NOT NULL,
private_key_nonce BYTEA NOT NULL,
key_version INT NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE acme_certificates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
domain CITEXT NOT NULL UNIQUE,
certificate_pem TEXT NOT NULL,
private_key_enc BYTEA NOT NULL,
private_key_nonce BYTEA NOT NULL,
key_version INT NOT NULL DEFAULT 1,
-- Increments on every key change. A TLSA record published for a
-- generation must outlive every certificate of that generation
-- (RFC 7671 section 8.1).
key_generation INT NOT NULL DEFAULT 1,
not_after TIMESTAMPTZ NOT NULL,
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_acme_certificates_expiry ON acme_certificates(not_after);
-- The key reserved for the next issuance. It exists ahead of the certificate
-- precisely so its TLSA association can be published and allowed to propagate
-- before the certificate that uses it is served.
CREATE TABLE acme_pending_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
domain CITEXT NOT NULL UNIQUE,
private_key_enc BYTEA NOT NULL,
private_key_nonce BYTEA NOT NULL,
key_version INT NOT NULL DEFAULT 1,
-- SHA-256 of the SubjectPublicKeyInfo, which is the "3 1 1" TLSA value
-- for this key. Stored so the rollover can publish it without re-deriving.
tlsa_sha256 CHAR(64) NOT NULL,
-- When the association was published; the rollover waits out two TTLs
-- from here before switching the certificate over.
published_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);