mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 19:21:29 +00:00
1a2e9f9212
- idx_jobs_status_scheduled_at: job processor queries - idx_certificate_versions_cert_created: latest version lookups - idx_audit_events_timestamp_desc: audit trail pagination - idx_agents_online_heartbeat: health check partial index - idx_deployment_targets_agent_name: unique constraint on agent+name Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
231 lines
9.2 KiB
SQL
231 lines
9.2 KiB
SQL
-- Create initial schema for certificate control plane
|
|
-- IDs are TEXT to support application-generated prefixed IDs (e.g., "team-123", "cert-456")
|
|
|
|
-- Table: teams
|
|
CREATE TABLE IF NOT EXISTS teams (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
description TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_teams_name ON teams(name);
|
|
|
|
-- Table: owners
|
|
CREATE TABLE IF NOT EXISTS owners (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
email VARCHAR(255) NOT NULL,
|
|
team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_owners_email ON owners(email);
|
|
CREATE INDEX IF NOT EXISTS idx_owners_team_id ON owners(team_id);
|
|
|
|
-- Table: renewal_policies
|
|
CREATE TABLE IF NOT EXISTS renewal_policies (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
renewal_window_days INT NOT NULL,
|
|
auto_renew BOOLEAN NOT NULL DEFAULT true,
|
|
max_retries INT NOT NULL DEFAULT 3,
|
|
retry_interval_minutes INT NOT NULL DEFAULT 60,
|
|
alert_thresholds_days JSONB NOT NULL DEFAULT '[30, 14, 7, 0]',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_renewal_policies_name ON renewal_policies(name);
|
|
|
|
-- Table: issuers
|
|
CREATE TABLE IF NOT EXISTS issuers (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
type VARCHAR(255) NOT NULL,
|
|
config JSONB,
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_issuers_name ON issuers(name);
|
|
CREATE INDEX IF NOT EXISTS idx_issuers_enabled ON issuers(enabled);
|
|
|
|
-- Table: agents
|
|
CREATE TABLE IF NOT EXISTS agents (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
hostname VARCHAR(255) NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'offline',
|
|
last_heartbeat_at TIMESTAMPTZ,
|
|
registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
api_key_hash VARCHAR(255) NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_hostname ON agents(hostname);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_last_heartbeat_at ON agents(last_heartbeat_at);
|
|
|
|
-- Table: managed_certificates
|
|
CREATE TABLE IF NOT EXISTS managed_certificates (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
common_name VARCHAR(255) NOT NULL,
|
|
sans TEXT[] DEFAULT ARRAY[]::TEXT[],
|
|
environment VARCHAR(50),
|
|
owner_id TEXT NOT NULL REFERENCES owners(id) ON DELETE RESTRICT,
|
|
team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
|
issuer_id TEXT NOT NULL REFERENCES issuers(id) ON DELETE RESTRICT,
|
|
renewal_policy_id TEXT NOT NULL REFERENCES renewal_policies(id) ON DELETE RESTRICT,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
|
expires_at TIMESTAMPTZ,
|
|
tags JSONB NOT NULL DEFAULT '{}',
|
|
last_renewal_at TIMESTAMPTZ,
|
|
last_deployment_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_managed_certificates_status ON managed_certificates(status);
|
|
CREATE INDEX IF NOT EXISTS idx_managed_certificates_expires_at ON managed_certificates(expires_at);
|
|
CREATE INDEX IF NOT EXISTS idx_managed_certificates_owner_id ON managed_certificates(owner_id);
|
|
CREATE INDEX IF NOT EXISTS idx_managed_certificates_team_id ON managed_certificates(team_id);
|
|
CREATE INDEX IF NOT EXISTS idx_managed_certificates_issuer_id ON managed_certificates(issuer_id);
|
|
CREATE INDEX IF NOT EXISTS idx_managed_certificates_name ON managed_certificates(name);
|
|
|
|
-- Table: deployment_targets
|
|
CREATE TABLE IF NOT EXISTS deployment_targets (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
type VARCHAR(255) NOT NULL,
|
|
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
config JSONB,
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_deployment_targets_agent_id ON deployment_targets(agent_id);
|
|
CREATE INDEX IF NOT EXISTS idx_deployment_targets_enabled ON deployment_targets(enabled);
|
|
CREATE INDEX IF NOT EXISTS idx_deployment_targets_name ON deployment_targets(name);
|
|
|
|
-- Table: certificate_target_mappings
|
|
CREATE TABLE IF NOT EXISTS certificate_target_mappings (
|
|
certificate_id TEXT NOT NULL REFERENCES managed_certificates(id) ON DELETE CASCADE,
|
|
target_id TEXT NOT NULL REFERENCES deployment_targets(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (certificate_id, target_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_certificate_target_mappings_target_id ON certificate_target_mappings(target_id);
|
|
|
|
-- Table: certificate_versions
|
|
CREATE TABLE IF NOT EXISTS certificate_versions (
|
|
id TEXT PRIMARY KEY,
|
|
certificate_id TEXT NOT NULL REFERENCES managed_certificates(id) ON DELETE CASCADE,
|
|
serial_number VARCHAR(255) NOT NULL,
|
|
not_before TIMESTAMPTZ NOT NULL,
|
|
not_after TIMESTAMPTZ NOT NULL,
|
|
fingerprint_sha256 VARCHAR(255) NOT NULL UNIQUE,
|
|
pem_chain TEXT NOT NULL,
|
|
csr_pem TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_certificate_versions_certificate_id ON certificate_versions(certificate_id);
|
|
CREATE INDEX IF NOT EXISTS idx_certificate_versions_fingerprint ON certificate_versions(fingerprint_sha256);
|
|
|
|
-- Table: jobs
|
|
CREATE TABLE IF NOT EXISTS jobs (
|
|
id TEXT PRIMARY KEY,
|
|
type VARCHAR(255) NOT NULL,
|
|
certificate_id TEXT REFERENCES managed_certificates(id) ON DELETE CASCADE,
|
|
target_id TEXT REFERENCES deployment_targets(id) ON DELETE SET NULL,
|
|
agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
|
attempts INT NOT NULL DEFAULT 0,
|
|
max_attempts INT NOT NULL DEFAULT 3,
|
|
last_error TEXT,
|
|
deployment_result JSONB,
|
|
scheduled_at TIMESTAMPTZ,
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_certificate_id ON jobs(certificate_id);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_scheduled_at ON jobs(scheduled_at);
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_agent_id ON jobs(agent_id);
|
|
|
|
-- Table: policy_rules
|
|
CREATE TABLE IF NOT EXISTS policy_rules (
|
|
id TEXT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
type VARCHAR(255) NOT NULL,
|
|
config JSONB NOT NULL,
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_policy_rules_name ON policy_rules(name);
|
|
CREATE INDEX IF NOT EXISTS idx_policy_rules_enabled ON policy_rules(enabled);
|
|
|
|
-- Table: policy_violations
|
|
CREATE TABLE IF NOT EXISTS policy_violations (
|
|
id TEXT PRIMARY KEY,
|
|
certificate_id TEXT NOT NULL REFERENCES managed_certificates(id) ON DELETE CASCADE,
|
|
rule_id TEXT NOT NULL REFERENCES policy_rules(id) ON DELETE CASCADE,
|
|
message TEXT NOT NULL,
|
|
severity VARCHAR(50) NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_policy_violations_certificate_id ON policy_violations(certificate_id);
|
|
CREATE INDEX IF NOT EXISTS idx_policy_violations_rule_id ON policy_violations(rule_id);
|
|
CREATE INDEX IF NOT EXISTS idx_policy_violations_severity ON policy_violations(severity);
|
|
|
|
-- Table: audit_events
|
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
id TEXT PRIMARY KEY,
|
|
actor VARCHAR(255) NOT NULL,
|
|
actor_type VARCHAR(50) NOT NULL,
|
|
action VARCHAR(255) NOT NULL,
|
|
resource_type VARCHAR(255) NOT NULL,
|
|
resource_id VARCHAR(255) NOT NULL,
|
|
details JSONB,
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_audit_events_resource_type_id ON audit_events(resource_type, resource_id);
|
|
CREATE INDEX IF NOT EXISTS idx_audit_events_actor ON audit_events(actor);
|
|
CREATE INDEX IF NOT EXISTS idx_audit_events_timestamp ON audit_events(timestamp);
|
|
CREATE INDEX IF NOT EXISTS idx_audit_events_action ON audit_events(action);
|
|
|
|
-- Table: notification_events
|
|
CREATE TABLE IF NOT EXISTS notification_events (
|
|
id TEXT PRIMARY KEY,
|
|
type VARCHAR(255) NOT NULL,
|
|
certificate_id TEXT REFERENCES managed_certificates(id) ON DELETE CASCADE,
|
|
channel VARCHAR(255) NOT NULL,
|
|
recipient VARCHAR(255) NOT NULL,
|
|
message TEXT NOT NULL,
|
|
sent_at TIMESTAMPTZ,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
|
error TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_notification_events_certificate_id ON notification_events(certificate_id);
|
|
CREATE INDEX IF NOT EXISTS idx_notification_events_status ON notification_events(status);
|
|
CREATE INDEX IF NOT EXISTS idx_notification_events_type ON notification_events(type);
|
|
|
|
-- Performance indexes for scheduler queries (added for v1.0 hardening)
|
|
CREATE INDEX IF NOT EXISTS idx_jobs_status_scheduled_at ON jobs(status, scheduled_at);
|
|
CREATE INDEX IF NOT EXISTS idx_certificate_versions_cert_created ON certificate_versions(certificate_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_audit_events_timestamp_desc ON audit_events(timestamp DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_online_heartbeat ON agents(status, last_heartbeat_at) WHERE status = 'online';
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_deployment_targets_agent_name ON deployment_targets(agent_id, name);
|