mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 15:01:32 +00:00
docs: add compliance mapping guides and comprehensive documentation audit
Add SOC 2 Type II, PCI-DSS 4.0, and NIST SP 800-57 compliance mapping guides — the final V2 deliverable. All claims verified against actual codebase (router.go, config.go, main.go). Also audit and update all existing docs: fix endpoint/tool/test counts in features.md, expand demo-guide.md and demo-advanced.md with CLI/MCP/discovery coverage, update connectors.md F5/IIS status to V3 paid, add compliance reference to architecture.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -102,6 +102,7 @@ export CERTCTL_AGENT_ID=agent-local-01
|
||||
| [Advanced Demo](docs/demo-advanced.md) | Issue a certificate end-to-end with technical deep-dives |
|
||||
| [Architecture](docs/architecture.md) | System design, data flow diagrams, security model |
|
||||
| [Connectors](docs/connectors.md) | Build custom issuer, target, and notifier connectors |
|
||||
| [Compliance Mapping](docs/compliance.md) | SOC 2 Type II, PCI-DSS 4.0, NIST SP 800-57 alignment guides |
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -508,7 +509,7 @@ All nine development milestones (M1–M9) are complete. The backend covers the f
|
||||
- **M16b: CLI + Bulk Import** ✅ — `certctl-cli` with 10 subcommands (list/get/renew/revoke certs, list agents/jobs, health, metrics, PEM bulk import), stdlib-only, JSON/table output
|
||||
- **M20: Enhanced Query API** ✅ — sparse field selection (`?fields=`), sort with direction (`?sort=-notAfter`), time-range filters (`expires_before`, `created_after`, etc.), cursor-based pagination (`?cursor=&page_size=`), `GET /certificates/{id}/deployments`, additional filters (`agent_id`, `profile_id`)
|
||||
- **M18b: Filesystem Cert Discovery** ✅ — agents scan configured directories (PEM/DER), report findings to control plane, deduplication by SHA-256 fingerprint, claim/dismiss/triage workflow via API
|
||||
- **Compliance Mapping** — SOC 2 Type II, PCI-DSS 4.0, NIST SP 800-57 capability mapping documentation
|
||||
- **Compliance Mapping** ✅ — SOC 2 Type II, PCI-DSS 4.0, NIST SP 800-57 capability mapping documentation
|
||||
|
||||
### V3: Team & Enterprise
|
||||
Team access controls, identity provider integration, enterprise deployment targets, compliance and risk scoring, advanced fleet operations, event-driven architecture, advanced search, real-time operational views, and premium CA integrations.
|
||||
|
||||
@@ -605,7 +605,7 @@ All endpoints are under `/api/v1/` and follow consistent patterns:
|
||||
|
||||
Resources: certificates, issuers, targets, agents, jobs, policies, profiles, teams, owners, agent-groups, audit, notifications.
|
||||
|
||||
The full API is documented in an OpenAPI 3.1 specification at `api/openapi.yaml` with 78 operations, all request/response schemas, and pagination conventions. See the [OpenAPI Guide](openapi.md) for usage with Swagger UI and SDK generation.
|
||||
The full API is documented in an OpenAPI 3.1 specification at `api/openapi.yaml` with 78 documented operations (including health, readiness, and auth endpoints; 7 discovery endpoints from M18b pending spec update), all request/response schemas, and pagination conventions. See the [OpenAPI Guide](openapi.md) for usage with Swagger UI and SDK generation.
|
||||
|
||||
Jobs support additional action endpoints: `POST /api/v1/jobs/{id}/cancel`, `POST /api/v1/jobs/{id}/approve`, `POST /api/v1/jobs/{id}/reject`.
|
||||
|
||||
@@ -783,5 +783,6 @@ certctl uses a layered testing approach aligned with the handler → service →
|
||||
- [Quick Start](quickstart.md) — Get certctl running locally
|
||||
- [Advanced Demo](demo-advanced.md) — Issue a certificate end-to-end
|
||||
- [Connector Guide](connectors.md) — Build custom connectors
|
||||
- [Compliance Mapping](compliance.md) — SOC 2, PCI-DSS 4.0, and NIST SP 800-57 alignment
|
||||
- [MCP Server Guide](mcp.md) — AI-native access to the API
|
||||
- [OpenAPI Spec](openapi.md) — Full API reference and SDK generation
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
# NIST SP 800-57 Key Management Alignment
|
||||
|
||||
NIST SP 800-57 Part 1 Rev 5 (May 2020) is the authoritative US government guidance on cryptographic key management. This document maps certctl's implementation to its recommendations. certctl follows NIST guidance where applicable; this guide documents the alignment and identifies gaps for future roadmap planning.
|
||||
|
||||
## Key Generation (Section 6.1)
|
||||
|
||||
certctl generates certificate keys on agent infrastructure using Go's `crypto/rand` for entropy, backed by `/dev/urandom` on Linux and `CryptGenRandom` on Windows. Key generation happens as follows:
|
||||
|
||||
**Agent-Side Key Generation (Production Default)**
|
||||
- Agents generate ECDSA P-256 key pairs per certificate using `crypto/ecdsa` + `crypto/elliptic` (Go stdlib)
|
||||
- Key generation triggered by `AwaitingCSR` job state in renewal/issuance workflows
|
||||
- Agent creates Certificate Signing Request (CSR) with `x509.CreateCertificateRequest`, signed with the agent's private key
|
||||
- Only the CSR crosses the network to the control plane; private key material never leaves the agent
|
||||
- Configuration: `CERTCTL_KEYGEN_MODE=agent` (default, production)
|
||||
|
||||
**Server-Side Key Generation (Demo Only)**
|
||||
- Available for development and testing via `CERTCTL_KEYGEN_MODE=server`
|
||||
- Explicitly logged as a warning at startup: "server-side keygen enabled (production deployments must use agent mode)"
|
||||
- Docker Compose demo uses server mode for backward compatibility
|
||||
- Not recommended for production; agent mode is the secure default
|
||||
|
||||
**Entropy Source**
|
||||
- `crypto/rand` provides cryptographically secure random bytes
|
||||
- On Linux: backed by `/dev/urandom` via `getrandom()` syscall
|
||||
- On Windows: backed by `CryptGenRandom()` (now `BCryptGenRandom()`)
|
||||
- Meets NIST SP 800-90B requirements for entropy generation
|
||||
|
||||
## Key Storage and Protection (Sections 6.3, 6.4)
|
||||
|
||||
certctl implements tiered key storage with different protection profiles based on key purpose.
|
||||
|
||||
**Agent Private Keys**
|
||||
- Stored on agent filesystem at `CERTCTL_KEY_DIR` (default: `/var/lib/certctl/keys`)
|
||||
- File permissions: 0600 (read/write by agent process only, no world/group access)
|
||||
- One PEM file per certificate, organized by certificate ID
|
||||
- Accessible only to the agent process; isolated from other processes
|
||||
- For container deployments: use Docker volumes with restricted permissions (`-v /var/lib/certctl/keys:0600`)
|
||||
|
||||
**Issuing CA Keys (Local CA Connector)**
|
||||
- Loaded from disk at server startup via `CERTCTL_CA_CERT_PATH` and `CERTCTL_CA_KEY_PATH` env vars
|
||||
- Supports RSA (PKCS#1, PKCS#8) and ECDSA (SEC1, PKCS#8) key formats
|
||||
- Validates certificate constraints before use:
|
||||
- `IsCA=true` flag present
|
||||
- `KeyUsageCertSign` extension set
|
||||
- Valid certificate chain (for sub-CA mode)
|
||||
- Keys held in memory during server runtime (no on-disk caching after load)
|
||||
- Cleared from memory only on server shutdown
|
||||
|
||||
**Sub-CA Mode (Enterprise Integration)**
|
||||
- CA certificate and key signed by upstream enterprise root (e.g., Active Directory Certificate Services)
|
||||
- Certctl acts as subordinate CA, inheriting issuer DN from upstream CA
|
||||
- All issued certificates chain to enterprise trust anchor
|
||||
- CA key protection inherits upstream root's key management practices
|
||||
- Configured via: `CERTCTL_CA_CERT_PATH=/path/to/ca.crt` and `CERTCTL_CA_KEY_PATH=/path/to/ca.key`
|
||||
|
||||
**NIST Gap: HSM Storage**
|
||||
NIST SP 800-57 Part 1 recommends Hardware Security Module (HSM) storage for high-value keys (CA signing keys). certctl V2 uses filesystem storage on the server. HSM support is planned for V5 roadmap, enabling integration with:
|
||||
- AWS CloudHSM
|
||||
- Azure Dedicated HSM
|
||||
- Thales Luna, Gemalto SafeNet, YubiHSM (on-premises)
|
||||
- PKCS#11-compatible devices
|
||||
|
||||
## Cryptoperiods (Section 5.3, Table 1)
|
||||
|
||||
NIST recommends cryptoperiods (key validity durations) based on key type and security requirements. certctl enforces cryptoperiods through certificate profiles and renewal policies.
|
||||
|
||||
**Certificate Profile Enforcement**
|
||||
- Certificate profiles (M11a) define `max_ttl` constraint per enrollment profile
|
||||
- All certificates issued through a profile cannot exceed the profile's max_ttl
|
||||
- Profile configuration example:
|
||||
```json
|
||||
{
|
||||
"id": "prof-web-prod",
|
||||
"name": "Production Web Certs",
|
||||
"max_ttl_seconds": 31536000, // 1 year max
|
||||
"allowed_key_algorithms": ["ECDSA_P256"],
|
||||
"required_sans": ["example.com"]
|
||||
}
|
||||
```
|
||||
|
||||
**Renewal Thresholds**
|
||||
- Renewal policies with configurable `alert_thresholds_days`: `[30, 14, 7, 0]` (days before expiry)
|
||||
- Background scheduler checks renewal eligibility every 1 hour
|
||||
- Certificates transitioned to `Expiring` status at 30 days, `Expired` at 0 days
|
||||
- Renewal workflow can be triggered manually or automatically
|
||||
|
||||
**NIST Cryptoperiod Recommendations vs certctl Implementation**
|
||||
|
||||
| Key Type | NIST Recommendation | certctl Implementation |
|
||||
|----------|---------------------|------------------------|
|
||||
| CA signing key | 3–10 years | Configured via CA certificate not-after date; inheritable from upstream CA in sub-CA mode |
|
||||
| End-entity web server cert | 1–3 years (trending shorter) | Profile `max_ttl` configurable; ACME issuer typically 90 days; SC-081v3 mandating 47 days by 2029 |
|
||||
| Code signing cert | 2–8 years | Profile enforcement via `max_ttl`; not primary certctl use case |
|
||||
| Short-lived credentials | < 1 hour recommended | Profile TTL < 1 hour; exempt from CRL/OCSP (expiry is sufficient revocation); auto-expiry on scheduler tick |
|
||||
| OCSP signing key | 1–2 years | Embedded OCSP responder uses issuing CA key (same period as issuer) or delegated signing cert |
|
||||
| TLS/SSL interoperability cert | 1–2 years | Trending 1 year or less; certctl's ACME/sub-CA/step-ca issuers all support short periods |
|
||||
|
||||
## Key States and Transitions (Section 5.2)
|
||||
|
||||
NIST defines lifecycle states for keys: pre-activation, active, suspended, deactivated, compromised, and destroyed. certctl maps these to certificate and job states:
|
||||
|
||||
| NIST Key State | certctl Equivalent | Implementation |
|
||||
|---|---|---|
|
||||
| **Pre-activation** | `Pending` job state / `AwaitingCSR` | Job created but key not yet generated; awaiting agent CSR submission (agent-mode) or server keygen (demo mode) |
|
||||
| **Active** | Certificate status `Active` | Cert deployed to targets and in use; within validity period (not before < now < not after) |
|
||||
| **Suspended** | Job state `AwaitingApproval` | Interactive approval holds deployment job pending human review; resumes on approval or cancels on rejection |
|
||||
| **Deactivated** | Certificate status `Expired` | Past not-after date; auto-transitioned by scheduler every 2 minutes; renewal eligible |
|
||||
| **Compromised** | Certificate status `Revoked` | Issued via `POST /api/v1/certificates/{id}/revoke` with RFC 5280 revocation reason |
|
||||
| **Destroyed** | Archived (implementation detail) | Operator responsibility; certctl retains all certs in audit trail for compliance; no destructive deletion API |
|
||||
|
||||
**State Transition Audit Trail**
|
||||
All transitions logged to immutable `audit_events` table with:
|
||||
- Event type (e.g., `certificate_revoked`, `renewal_job_completed`)
|
||||
- Actor (authenticated user or agent ID)
|
||||
- Timestamp (RFC3339)
|
||||
- Resource (certificate ID)
|
||||
- Reason (revocation reason code, approval reason, etc.)
|
||||
- HTTP method, path, status (for API calls)
|
||||
|
||||
Example audit entry for revocation:
|
||||
```json
|
||||
{
|
||||
"id": "ae-2024-0615",
|
||||
"event_type": "certificate_revoked",
|
||||
"actor": "ops-alice@example.com",
|
||||
"timestamp": "2024-06-15T14:23:00Z",
|
||||
"resource_id": "cert-web-prod-2024",
|
||||
"resource_type": "certificate",
|
||||
"description": "Revoked: reason=keyCompromise",
|
||||
"body_hash": "sha256:a1b2c3d..."
|
||||
}
|
||||
```
|
||||
|
||||
## Algorithm Recommendations (Section 5.1, SP 800-131A)
|
||||
|
||||
NIST SP 800-131A Rev 2 (January 2024) categorizes cryptographic algorithms as Approved, Conditionally Approved, or Disallowed. certctl implements only NIST-approved algorithms:
|
||||
|
||||
| Algorithm | NIST Status | certctl Support | Notes |
|
||||
|-----------|-------------|-----------------|-------|
|
||||
| **ECDSA P-256** | Approved (128-bit security strength) | Default for agent-side keygen | Meets NIST curve requirements (FIPS 186-4) |
|
||||
| **ECDSA P-384** | Approved (192-bit security strength) | Supported via profile configuration | Higher security margin; slower than P-256 |
|
||||
| **ECDSA P-521** | Approved (256-bit security strength) | Supported via profile configuration | Rarely needed; overkill for TLS |
|
||||
| **RSA 2048** | Approved minimum (112-bit security, transitioning) | Supported via all issuers | Deprecated path; migrate to 3072+ by 2030 per NIST |
|
||||
| **RSA 3072** | Approved (128-bit security) | Supported via all issuers | Recommended minimum for long-term security |
|
||||
| **RSA 4096** | Approved (192-bit security) | Supported via all issuers | Supported but slower; overkill for most TLS |
|
||||
| **SHA-256** | Approved | Used throughout | CSR signing, certificate fingerprints, audit body hashing, CRL/OCSP signing |
|
||||
| **SHA-384** | Approved (192-bit) | Supported where algorithm selection available | Used in some CA signing scenarios |
|
||||
| **SHA-512** | Approved (256-bit) | Supported where algorithm selection available | Rarely needed; SHA-256 suffices for most use cases |
|
||||
| **SHA-1** | Deprecated | Not used in certctl | Browsers reject SHA-1 certs; certctl never generates them |
|
||||
|
||||
**Algorithm Enforcement via Profiles**
|
||||
Certificate profiles enforce allowed key algorithms:
|
||||
```json
|
||||
{
|
||||
"id": "prof-web-prod",
|
||||
"allowed_key_algorithms": ["ECDSA_P256", "ECDSA_P384", "RSA3072"]
|
||||
}
|
||||
```
|
||||
|
||||
**Post-Quantum Cryptography (Tracking)**
|
||||
NIST has finalized PQC standards (FIPS 204, FIPS 205) in August 2024:
|
||||
- **ML-KEM** (Kyber): Approved key encapsulation mechanism
|
||||
- **ML-DSA** (Dilithium): Approved digital signature algorithm
|
||||
- **SLH-DSA** (SPHINCS+): Approved stateless hash-based signature scheme
|
||||
|
||||
certctl will track NIST's PQC roadmap and plan integration when hybrid PQC+classical certificate formats reach browser/infrastructure support. Currently, pure PQC certificates are not widely interoperable.
|
||||
|
||||
## Key Distribution and Transport (Section 6.2)
|
||||
|
||||
NIST SP 800-57 Part 1 Section 6.2 addresses secure key distribution to minimize exposure during transit. certctl implements a zero-transmission-of-private-keys model:
|
||||
|
||||
**Private Key Distribution**
|
||||
- Agent-side keygen model: Private keys never leave agent infrastructure
|
||||
- CSR transmitted over HTTPS (TLS 1.2+) with mutual TLS optional
|
||||
- API key authentication via `Authorization: Bearer <api-key>` header
|
||||
- All API calls logged to immutable audit trail
|
||||
|
||||
**Signed Certificate Distribution**
|
||||
- Certificates (public component) distributed via `GET /agents/{id}/work` over HTTPS
|
||||
- Work endpoint enriches deployment jobs with certificate PEM and metadata
|
||||
- Certificate PEM is idempotent (same cert always returns same bytes)
|
||||
|
||||
**Target Deployment**
|
||||
- Deployment to targets via local filesystem write (NGINX, Apache, HAProxy)
|
||||
- No network transmission of private keys to targets
|
||||
- Agents read local private key from `CERTCTL_KEY_DIR` on deployment
|
||||
- For appliances without agents (F5 BIG-IP, IIS), proxy agent pattern:
|
||||
- Proxy agent runs in same trust zone as appliance
|
||||
- Proxy agent holds target API credentials (iControl, WinRM)
|
||||
- Control plane never communicates with appliance directly
|
||||
- Deployment request includes certificate and proxy agent ID
|
||||
- Proxy agent executes deployment via appliance API
|
||||
|
||||
**Revocation Distribution**
|
||||
- Certificate Revocation List (CRL) via `GET /api/v1/crl/{issuer_id}`
|
||||
- Returns DER-encoded X.509 CRL signed by issuing CA
|
||||
- 24-hour validity period
|
||||
- Includes all revoked serials, reasons, and revocation timestamps
|
||||
- Subject to URL caching; OCSP preferred for real-time revocation
|
||||
- OCSP via `GET /api/v1/ocsp/{issuer_id}/{serial}`
|
||||
- Returns DER-encoded OCSP response (OCSPResponse ASN.1 structure)
|
||||
- Signed by issuing CA (or delegated OCSP signing cert)
|
||||
- Responds with good/revoked/unknown status
|
||||
- Real-time, more bandwidth-efficient than CRL polling
|
||||
|
||||
## Revocation and Compromise (NIST SP 800-57 Part 3)
|
||||
|
||||
NIST SP 800-57 Part 3 covers revocation (Section 2.5) when keys are suspected compromised or no longer needed. certctl implements comprehensive revocation infrastructure:
|
||||
|
||||
**Revocation API**
|
||||
- Endpoint: `POST /api/v1/certificates/{id}/revoke`
|
||||
- Request body:
|
||||
```json
|
||||
{
|
||||
"reason": "keyCompromise",
|
||||
"reason_text": "Private key exposed in log file"
|
||||
}
|
||||
```
|
||||
- Supports all 8 RFC 5280 revocation reason codes:
|
||||
- `unspecified` — no specific reason provided
|
||||
- `keyCompromise` — private key suspected compromised
|
||||
- `caCompromise` — issuing CA key compromised
|
||||
- `affiliationChanged` — subject org/affiliation changed
|
||||
- `superseded` — cert superseded by newer cert
|
||||
- `cessationOfOperation` — key no longer in use
|
||||
- `certificateHold` — temporary hold (rarely used)
|
||||
- `privilegeWithdrawn` — subject authorization withdrawn
|
||||
|
||||
**Revocation Recording**
|
||||
- Certificate status updated to `Revoked`
|
||||
- Entry recorded in `certificate_revocations` table with:
|
||||
- Certificate serial number
|
||||
- Revocation timestamp
|
||||
- Revocation reason code
|
||||
- Issuer ID
|
||||
- Idempotent (revoking an already-revoked cert is safe; returns 200 OK)
|
||||
|
||||
**Issuer Notification (Best-Effort)**
|
||||
- Control plane calls `issuer.RevokeCertificate(ctx, serial, reason)` on issuing connector
|
||||
- Failure does not block the revocation (async, logged, retried)
|
||||
- Supported issuers:
|
||||
- Local CA: generates new CRL immediately
|
||||
- ACME: submits revocation to ACME server (RFC 8555 Section 7.6)
|
||||
- step-ca: calls `/revoke` API
|
||||
- OpenSSL: executes user-provided revocation script
|
||||
|
||||
**Revocation Notifications**
|
||||
- Notifiers triggered after revocation recorded: Slack, Teams, PagerDuty, OpsGenie, email, webhook
|
||||
- Message includes certificate common name, issuer, reason, actor, timestamp
|
||||
- Delivery is asynchronous and retried on failure
|
||||
|
||||
**CRL and OCSP Distribution**
|
||||
- CRL updated on every revocation (or scheduled refresh for non-issued revocations)
|
||||
- OCSP responder queries revocation table in real-time
|
||||
- Short-lived certificate exemption: certs with TTL < 1 hour skip CRL/OCSP (expiry is sufficient revocation)
|
||||
|
||||
**Revocation Audit Trail**
|
||||
All revocation events logged:
|
||||
- Event type: `certificate_revoked`
|
||||
- Actor: authenticated user or service
|
||||
- Reason code: RFC 5280 enum
|
||||
- Timestamp: RFC3339
|
||||
- Issuer notification status: success or error reason
|
||||
|
||||
## Alignment Summary Table
|
||||
|
||||
| NIST SP 800-57 Area | Status | Coverage | Notes |
|
||||
|---|---|---|---|
|
||||
| **Key Generation** | ✅ Aligned | 100% | Agent-side ECDSA P-256 using crypto/rand; server mode flagged as demo-only |
|
||||
| **Key Storage** | ⚠️ Partially Aligned | 80% | Filesystem with 0600 perms; HSM support planned V5 |
|
||||
| **Cryptoperiods** | ✅ Aligned | 100% | Profile-enforced max_ttl; threshold-based renewal alerting |
|
||||
| **Key States** | ✅ Aligned | 100% | Full lifecycle tracking with immutable audit trail |
|
||||
| **Algorithms** | ✅ Aligned | 100% | NIST-approved algorithms only; post-quantum tracking in progress |
|
||||
| **Key Distribution** | ✅ Aligned | 100% | Private keys never transmitted; CSR/cert over TLS; agent-local deployment |
|
||||
| **Revocation** | ✅ Aligned | 100% | CRL, OCSP, all RFC 5280 reason codes; real-time updates |
|
||||
|
||||
## Gaps and Remediation Roadmap
|
||||
|
||||
### V2 (Current)
|
||||
- [x] Agent-side key generation
|
||||
- [x] Profile-enforced cryptoperiods
|
||||
- [x] CRL and OCSP distribution
|
||||
- [x] RFC 5280 revocation support
|
||||
- [x] Immutable audit trail
|
||||
|
||||
### V3 (Planned: 2026)
|
||||
- Role-based access control (limit revocation/approval to authorized operators)
|
||||
- Bulk revocation by profile/owner/agent (fleet-level revocation policy)
|
||||
|
||||
### V5 (Planned: 2027+)
|
||||
- HSM support for CA key storage
|
||||
- PKCS#11 integration for hardware tokens
|
||||
- FIPS 140-2/3 validated crypto module (BoringCrypto build or external FIPS library)
|
||||
- Key destruction API (explicit secure erasure of agent keys)
|
||||
- Key escrow / recovery mechanism (backup encrypted private keys for disaster recovery)
|
||||
|
||||
### Post-Quantum (2027+)
|
||||
- ML-KEM and ML-DSA support when browser/TLS ecosystem supports hybrid certificates
|
||||
- Migration path documentation (how to transition existing RSA certs to PQC)
|
||||
|
||||
## References
|
||||
|
||||
- NIST SP 800-57 Part 1 Rev 5 (May 2020): https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf
|
||||
- NIST SP 800-131A Rev 2 (January 2024): https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf
|
||||
- FIPS 186-4 (Digital Signature Standard): https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
|
||||
- RFC 5280 (X.509 PKI Certificate and CRL Profile): https://tools.ietf.org/html/rfc5280
|
||||
- RFC 8555 (Automatic Certificate Management Environment): https://tools.ietf.org/html/rfc8555
|
||||
- NIST FIPS 204 (ML-DSA): https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf
|
||||
- NIST FIPS 205 (ML-KEM): https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.205.pdf
|
||||
|
||||
## Questions or Corrections?
|
||||
|
||||
This document reflects certctl's implementation as of March 2026. For the latest code, refer to:
|
||||
- Key generation: `cmd/agent/main.go` (agent keygen) and `internal/service/renewal.go` (server keygen)
|
||||
- Key storage: `internal/config/config.go` (CERTCTL_KEY_DIR, CERTCTL_CA_CERT_PATH)
|
||||
- Revocation: `internal/service/revocation.go` and `internal/api/handler/certificates.go`
|
||||
- Audit trail: `internal/api/middleware/audit.go`
|
||||
@@ -0,0 +1,791 @@
|
||||
# PCI-DSS 4.0 Compliance Mapping
|
||||
|
||||
This guide maps certctl's existing capabilities to PCI-DSS 4.0 requirements relevant to TLS certificate and cryptographic key management. It is **not a compliance attestation** — a qualified security assessor (QSA) must evaluate your organization's complete control environment. Rather, this document helps you understand which PCI-DSS control objectives certctl supports and where operator responsibility lies.
|
||||
|
||||
Organizations subject to PCI-DSS typically need to demonstrate control over certificate issuance, renewal, rotation, revocation, and key management. Certctl automates the technical controls for certificate lifecycle; compliance depends on how you deploy, monitor, and audit it.
|
||||
|
||||
## How to Use This Guide
|
||||
|
||||
Your QSA will request evidence that your certificate and key management systems meet specific PCI-DSS 4.0 requirements. For each applicable requirement, this guide identifies:
|
||||
|
||||
1. **Which certctl features support the control** — API endpoints, database tables, background processes
|
||||
2. **What evidence you can produce** — audit logs, dashboard metrics, API queries, deployment configs
|
||||
3. **Operator responsibilities** — what you must do outside certctl (policy, monitoring, access control)
|
||||
4. **Status** — Available (v1.0 shipped), Planned (future release), or Operator Responsibility (outside scope)
|
||||
|
||||
---
|
||||
|
||||
## Requirement 4: Protect Data in Transit
|
||||
|
||||
**Objective**: Ensure strong cryptography is used to protect sensitive data during transmission.
|
||||
|
||||
### 4.2.1 — Strong Cryptography for Transmission
|
||||
|
||||
**Requirement**: Use appropriate and current cryptographic algorithms for all TLS and SSH connections protecting card data in transit.
|
||||
|
||||
**certctl Support**:
|
||||
- **Automated TLS certificate lifecycle** — Certctl issues TLS certificates to NGINX, Apache HAProxy targets via `POST /api/v1/deployments`. Certificates include RSA 2048-bit and ECDSA P-256 key types (configurable per profile, M11a).
|
||||
- **Control plane TLS enforcement** — All REST API endpoints served exclusively over HTTPS. Agent-to-server heartbeat and work polling use TLS. No plaintext protocol options.
|
||||
- **Issuer connector key negotiation** — ACME v2 (Let's Encrypt, ZeroSSL) validates issuer cryptography. Local CA enforces RSA/ECDSA constraints. step-ca integration ensures Smallstep's cryptography standards.
|
||||
- **Certificate profiles** (M11a) document allowed key types and minimum key sizes per environment (development, production, cardholder-network).
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Exported certificate inventory via `GET /api/v1/certificates` with key algorithm and size (serial JSON).
|
||||
- Issued certificate details showing RSA 2048+ or ECDSA P-256 for all deployed certificates.
|
||||
- Audit trail (`GET /api/v1/audit`) showing issuer connector selection and certificate profile assignment per certificate.
|
||||
- Target deployment logs showing TLS certificate installation on NGINX/Apache/HAProxy.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- Configure certificate profiles for your environments with approved key algorithms.
|
||||
- Audit cipher suite configuration on deployed targets (certctl deploys certs; you verify target TLS settings).
|
||||
- Periodically review `CERTCTL_KEYGEN_MODE` — must be `agent` in production (never `server`).
|
||||
- Monitor issuer connector configuration to ensure issuers meet your cryptography standards.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
---
|
||||
|
||||
### 4.2.2 — Certificate Inventory and Validation
|
||||
|
||||
**Requirement**: Ensure all TLS/SSL certificates used for data transmission are valid, current, and meet required cryptographic standards.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Managed Certificate Inventory** — Full CRUD API (`/api/v1/certificates`) with sortable, filterable list. Fields: common name, SANs, subject, issuer, serial number, key type/size, not-before/after dates, issuer ID, profile ID, owner, team, status (Active/Expiring/Expired/Revoked).
|
||||
|
||||
- **Filesystem Certificate Discovery** (M18b) — Agents scan configured directories (`CERTCTL_DISCOVERY_DIRS` env var) for existing PEM/DER certificates every 6 hours and on startup. Control plane deduplicates by SHA-256 fingerprint. Three triage statuses: Unmanaged (not managed by certctl), Managed (linked to a managed certificate), Dismissed (operator-marked as out-of-scope).
|
||||
- API endpoints:
|
||||
- `GET /api/v1/discovered-certificates?status=Unmanaged` — find orphaned certs
|
||||
- `GET /api/v1/discovery-summary` — aggregate counts by status
|
||||
- `POST /api/v1/discovered-certificates/{id}/claim` — link to managed certificate
|
||||
- `POST /api/v1/discovered-certificates/{id}/dismiss` — mark out-of-scope
|
||||
|
||||
- **Expiration Threshold Alerting** — Renewal policies support `alert_thresholds_days` (default 30, 14, 7, 0). Background scheduler evaluates daily; certificates transition to Expiring/Expired status automatically. Notifications sent to owners via email/webhook/Slack/Teams/PagerDuty.
|
||||
|
||||
- **Certificate Status Tracking** — Four statuses: Active (deployed, not yet expired), Expiring (within threshold, awaiting renewal), Expired (past not-after date), Revoked (revoked via RFC 5280 revocation API). Dashboard charts show status distribution.
|
||||
|
||||
- **Revocation Infrastructure** (M15a, M15b):
|
||||
- CRL endpoint: `GET /api/v1/crl` (JSON format) or `GET /api/v1/crl/{issuer_id}` (DER X.509 CRL, 24h validity, signed by issuing CA)
|
||||
- OCSP responder: `GET /api/v1/ocsp/{issuer_id}/{serial}` (returns DER-encoded OCSP response: good/revoked/unknown)
|
||||
- Short-lived cert exemption: certs with TTL < 1 hour skip CRL/OCSP (expiry is sufficient revocation)
|
||||
|
||||
- **Stats API** (M14) — Real-time visibility:
|
||||
- `GET /api/v1/stats/summary` — total certs, by status, by issuer
|
||||
- `GET /api/v1/stats/expiration-timeline?days=90` — expiration distribution (weekly buckets)
|
||||
- `GET /api/v1/stats/job-trends?days=30` — renewal/issuance job success rates
|
||||
- `GET /api/v1/certificates` with `?sort=-notAfter&fields=id,commonName,notAfter,status` — sparse, sorted inventory
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Discovered certificate report: `GET /api/v1/discovered-certificates` JSON export showing all certs on systems, fingerprints, and status.
|
||||
- Managed certificate inventory: `GET /api/v1/certificates` with filters (`?status=Expiring` for upcoming renewals).
|
||||
- Expiration alert configuration: policy JSON showing `alert_thresholds_days` for each environment.
|
||||
- CRL/OCSP availability proof: HTTP GET requests to `/api/v1/crl` and `/api/v1/ocsp/{issuer}/{serial}` with signed responses.
|
||||
- Audit trail for certificate creation/renewal/revocation: `GET /api/v1/audit?type=certificate_issued,certificate_renewed,certificate_revoked`.
|
||||
- Dashboard charts showing expiration timeline, renewal success trends, status distribution.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- Configure `CERTCTL_DISCOVERY_DIRS` on agents to scan all certificate storage locations (e.g., `/etc/nginx/certs`, `/etc/apache2/certs`, `/usr/local/share/ca-certificates`).
|
||||
- Regularly triage discovered certificates: `GET /api/v1/discovered-certificates?status=Unmanaged`, claim or dismiss each.
|
||||
- Set renewal policies for all certificate profiles with appropriate `alert_thresholds_days` (recommendation: 30, 14, 7, 0).
|
||||
- Monitor expiration dashboard and respond to Expiring alerts before certificates expire.
|
||||
- Verify that issued certificates meet your organization's cryptography standards (key type, key size, SANs).
|
||||
- Test CRL/OCSP endpoints periodically to confirm they are reachable and signed correctly.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped, discovery M18b, revocation M15a/M15b)
|
||||
|
||||
---
|
||||
|
||||
## Requirement 3: Protect Stored Cardholder Data (Key Management)
|
||||
|
||||
**Objective**: Render cardholder data unreadable anywhere it is stored; protect cryptographic keys used to encrypt data.
|
||||
|
||||
### 3.6 — Cryptographic Key Documentation
|
||||
|
||||
**Requirement**: Document and implement all key management processes and procedures covering generation, storage, archival, destruction, and change; protect cryptographic keys; and restrict access to keys to the minimum required.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Certificate Profile Documentation** (M11a) — Named profiles define allowed key types, maximum TTL, and allowed EKUs per use case. Each profile is a documented policy:
|
||||
```json
|
||||
{
|
||||
"id": "p-web-tls",
|
||||
"name": "Web TLS Production",
|
||||
"allowed_key_types": ["RSA_2048", "ECDSA_P256"],
|
||||
"max_ttl_seconds": 31536000,
|
||||
"require_sans": true,
|
||||
"description": "Production TLS certs for external web services"
|
||||
}
|
||||
```
|
||||
|
||||
- **Owner and Team Tracking** (M11b) — Every certificate is assigned an owner (person + email) and optionally a team. This documents key responsibility and escalation paths.
|
||||
|
||||
- **Issuer Connector Specification** — Configuration and API endpoints document which CA and protocol issues each certificate:
|
||||
- `GET /api/v1/issuers/{id}` returns issuer type (local-ca, acme, step-ca, openssl), CA endpoint, authentication method, constraints
|
||||
- Each issuer type has documented key handling (e.g., Local CA loads CA key from `CERTCTL_CA_CERT_PATH`, step-ca via JWK provisioner)
|
||||
|
||||
- **Immutable Audit Trail** (M19) — Every certificate lifecycle event recorded in append-only `audit_events` table:
|
||||
- `certificate_issued` — when certificate created, by whom, issuer type, profile
|
||||
- `certificate_renewed` — when renewed, by whom, issuer
|
||||
- `certificate_revoked` — when revoked, by whom, RFC 5280 reason code
|
||||
- `certificate_deployed` — when deployed to target, by agent, target type
|
||||
- Query: `GET /api/v1/audit?resource_type=certificate&resource_id={cert_id}`
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Exported certificate profiles: `GET /api/v1/profiles` showing documented key types, max TTLs, constraints per environment.
|
||||
- Certificate-to-owner mapping: `GET /api/v1/certificates` with owner/team fields.
|
||||
- Issuer configuration audit: `GET /api/v1/issuers` showing CA endpoints, key storage paths, auth methods.
|
||||
- Audit trail for a certificate: `GET /api/v1/audit?resource_type=certificate&resource_id={cert_id}` showing complete lifecycle.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- Define and document certificate profiles for each environment and use case.
|
||||
- Assign owner and team to each certificate via API or dashboard.
|
||||
- Document issuer connector configuration (CA endpoint, auth method, key storage location).
|
||||
- Maintain baseline audit trail exports for compliance evidence.
|
||||
- Establish certificate retirement policy (how long to retain audit records after certificate expiry/revocation).
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
---
|
||||
|
||||
### 3.7 — Key Lifecycle Procedures
|
||||
|
||||
**Requirement**: Generate, store, protect, access, and destroy cryptographic keys used to encrypt data in transit or at rest.
|
||||
|
||||
This requirement covers key generation, storage, rotation, and destruction. Certctl addresses the certificate/TLS key portion (not symmetric encryption keys used for cardholder data at rest — those are outside scope).
|
||||
|
||||
#### 3.7.1 — Key Generation
|
||||
|
||||
**Requirement**: Generate new keys using strong cryptography.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Agent-Side Key Generation** (M8) — Production mode (default `CERTCTL_KEYGEN_MODE=agent`):
|
||||
- Agents generate ECDSA P-256 key pairs using `crypto/ecdsa` + `crypto/elliptic.P256()` + `crypto/rand` (cryptographically secure random).
|
||||
- Key generation happens **only on the agent**, never on the control plane.
|
||||
- Agent submits Certificate Signing Request (CSR) with public key to control plane via `POST /api/v1/agents/{id}/csr`.
|
||||
- Issued certificate is returned; private key remains on agent at `CERTCTL_KEY_DIR` (default `/var/lib/certctl/keys`).
|
||||
|
||||
- **Server-Side Fallback** (demo/development only) — `CERTCTL_KEYGEN_MODE=server`:
|
||||
- Control plane generates RSA 2048-bit or ECDSA P-256 keys using `crypto/rand` + `crypto/rsa`.
|
||||
- Server signs CSR and stores the private key in the certificate version record for agent deployment. **Security note:** In server keygen mode, the control plane holds private keys — this is why agent keygen mode is the recommended default for production.
|
||||
- **Must not be used in production.** Explicit warning logged: `Key generation mode is server; this should only be used for testing.`
|
||||
|
||||
- **Issuer-Specific Key Negotiation**:
|
||||
- **ACME (Let's Encrypt, ZeroSSL)**: Let's Encrypt controls key types; certctl requests ECDSA P-256 by default.
|
||||
- **Local CA**: Supports RSA 2048+, ECDSA (P-256, P-384), PKCS#8 format. Key algorithm inherited from CA cert or specified via profile.
|
||||
- **step-ca**: Smallstep's provisioner defines key type; certctl respects server constraints.
|
||||
- **OpenSSL / Custom CA**: User-provided signing script; key type depends on CA backend.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Deployment configuration: `CERTCTL_KEYGEN_MODE=agent` in production (verify in `docker-compose.yml`, Kubernetes manifests, or systemd units).
|
||||
- Agent log excerpt showing key generation: `openssl genrsa...` or agent process logs with CSR submission timestamp.
|
||||
- Certificate CSR audit: `GET /api/v1/audit?type=certificate_issued` showing CSR fingerprint (SHA-256 hash of CSR PEM).
|
||||
- Renewal job logs showing agent-submitted CSR, not server-generated key.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Enforce `CERTCTL_KEYGEN_MODE=agent` in all production deployments.** Never use `server` mode outside demos.
|
||||
- Verify agent hardware is adequately isolated (crypto/rand relies on OS `/dev/urandom` quality).
|
||||
- Monitor `CERTCTL_KEY_DIR` on agents for unauthorized file access (use OS-level file audit if available).
|
||||
- Backup agent key directory (`/var/lib/certctl/keys`) as part of disaster recovery procedure.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
#### 3.7.2 — Key Storage and Access Control
|
||||
|
||||
**Requirement**: Restrict cryptographic key access to the minimum required and protect keys from unauthorized access.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Agent-Side Key Storage** (M8) — Private keys written to `CERTCTL_KEY_DIR` (default `/var/lib/certctl/keys`):
|
||||
- File permissions: `0600` (readable/writable by agent process owner only).
|
||||
- Filename convention: one file per certificate (e.g., `web-tls-prod.key`, `api-service.key`).
|
||||
- No key data passed over the network between agent and control plane (CSR only).
|
||||
- Keys used locally by agent to sign TLS handshakes, never transmitted to control plane or other systems.
|
||||
|
||||
- **Control Plane Key Storage** — Sensitive credentials managed via environment variables or `.env` files:
|
||||
- CA private key path: `CERTCTL_CA_CERT_PATH` + `CERTCTL_CA_KEY_PATH` (for Local CA sub-CA mode).
|
||||
- ACME account key: embedded in ACME issuer config (not stored separately; ACME library handles in memory).
|
||||
- step-ca provisioner key: `CERTCTL_STEPCA_PROVISIONER_KEY` env var (JWK, in memory during runtime).
|
||||
- API keys: `CERTCTL_API_KEY` (SHA-256 hashed in database, plaintext never stored).
|
||||
- Database credentials: `CERTCTL_DATABASE_URL` in `.env` file, not in source code.
|
||||
|
||||
- **Docker Compose Credential Management** — `.env` file (git-ignored) holds all secrets:
|
||||
```bash
|
||||
CERTCTL_API_KEY=sk-test-...
|
||||
CERTCTL_DATABASE_URL=postgres://user:pass@db:5432/certctl
|
||||
CERTCTL_CA_KEY_PATH=/run/secrets/ca.key
|
||||
```
|
||||
Credentials never in `docker-compose.yml` or Dockerfile.
|
||||
|
||||
- **Kubernetes Secrets** (operator responsibility) — Deploy control plane with:
|
||||
```yaml
|
||||
env:
|
||||
- name: CERTCTL_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: certctl-secrets
|
||||
key: database-url
|
||||
- name: CERTCTL_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: certctl-secrets
|
||||
key: api-key
|
||||
```
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Agent key directory listing (without keys): `ls -la /var/lib/certctl/keys` (shows file count, permissions, timestamps).
|
||||
- Deployment manifest (`docker-compose.yml` or Kubernetes YAML) showing secrets via env var or Secret object (not inline).
|
||||
- `.env` file (do not share contents, only confirm existence and git-ignore status).
|
||||
- API key hash verification: `GET /api/v1/auth/check` with API key, verifying hash matching without plaintext exposure.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Store `.env` and credential files outside version control.** Verify `.gitignore` includes `.env`, `*.key`, `ca.key`, etc.
|
||||
- **Restrict file system access to `/var/lib/certctl/keys` on agents** via OS-level permissions (Linux: `chmod 0700`, owned by agent user).
|
||||
- **Limit CA key file read access** — `CERTCTL_CA_KEY_PATH` should be readable only by certctl server process (OS permissions).
|
||||
- **Rotate API keys periodically** (recommendation: annually or when personnel changes). No audit trail for API key rotation (outside certctl scope).
|
||||
- **Backup private key stores** (agent key dirs, CA key file) as part of disaster recovery. Encrypt backups at rest.
|
||||
- **Monitor access logs** to `/var/lib/certctl/keys` and CA key file location (use OS audit or file integrity monitoring).
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
#### 3.7.3 — Key Rotation
|
||||
|
||||
**Requirement**: Rotate cryptographic keys upon expiration or compromise.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Automated Certificate Renewal** — Renewal policies trigger certificate renewal automatically:
|
||||
- Background scheduler checks every 60 minutes (configurable via `CERTCTL_SCHEDULER_RENEWAL_CHECK_INTERVAL`).
|
||||
- For each policy, evaluates all managed certificates: if `(not-after - now) <= policy.renewal_threshold_days`, trigger renewal.
|
||||
- Renewal job created in AwaitingCSR state; agent receives work, generates new key pair, submits new CSR.
|
||||
- Issuer connector signs new CSR with new key; old key discarded by agent after new certificate installed.
|
||||
- New certificate deployed to target via deployment job.
|
||||
|
||||
- **Expiration-Based Rotation** — Certificate profiles (M11a) define `max_ttl_seconds` (e.g., 31536000 for 1 year, 3600 for short-lived certs):
|
||||
- Short-lived certificates (TTL < 1 hour) rotate every deployment cycle, providing defense-in-depth (RFC 5280 revocation not needed).
|
||||
- Longer-lived certs (90/180/365 days) rotated via renewal policy thresholds (30/14/7 day alerts).
|
||||
|
||||
- **Renewal Audit Trail** — Every renewal recorded:
|
||||
- `GET /api/v1/audit?type=certificate_renewed&resource_id={cert_id}` shows each renewal, old serial, new serial, issuer, actor.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Renewal policy configuration: `GET /api/v1/policies` showing `renewal_threshold_days` and `alert_thresholds_days`.
|
||||
- Renewal job history: `GET /api/v1/jobs?type=Renewal&status=Completed` with timestamp, before/after serial numbers.
|
||||
- Certificate version history: `GET /api/v1/certificates/{id}/versions` showing all issued versions, dates, issuers.
|
||||
- Audit trail: `GET /api/v1/audit?type=certificate_renewed` for trending and compliance reporting.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Define renewal policies for all certificate profiles** with appropriate thresholds (typically 30 days before expiration for 90+ day certs, more aggressive for shorter-lived).
|
||||
- **Monitor renewal job success** via dashboard (M14 charts show renewal success trends) and alerts.
|
||||
- **Investigate renewal failures** (stuck AwaitingCSR, issuer connectivity, deployment errors) promptly to avoid expired certificates.
|
||||
- **Test renewal workflow in staging environment** before rolling out to production.
|
||||
- **Document key rotation schedule** for your organization (renewal policy thresholds, approval workflows if AwaitingApproval).
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
#### 3.7.4 — Key Destruction
|
||||
|
||||
**Requirement**: Render cryptographic keys unreadable and unusable when they reach the end of their cryptographic lifetime.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Certificate Revocation API** (M15a) — `POST /api/v1/certificates/{id}/revoke` with RFC 5280 reason codes:
|
||||
- `unspecified` — general revocation
|
||||
- `keyCompromise` — suspected key compromise
|
||||
- `caCompromise` — CA compromise
|
||||
- `affiliationChanged`, `superseded`, `cessationOfOperation`, `certificateHold`, `privilegeWithdrawn` — lifecycle management
|
||||
- Revocation recorded in `certificate_revocations` table with timestamp and reason.
|
||||
- Issuer notified (best-effort; ACME lacks standard revocation, Local CA skips issuer step).
|
||||
- Revocation notifications sent to owner via email/webhook/Slack/Teams/PagerDuty.
|
||||
|
||||
- **CRL and OCSP Publication** (M15b) — Revoked certificates published in:
|
||||
- CRL: `GET /api/v1/crl` (JSON format) or `GET /api/v1/crl/{issuer_id}` (DER X.509, signed by CA, 24h validity)
|
||||
- OCSP: `GET /api/v1/ocsp/{issuer_id}/{serial}` (returns revoked status for clients validating certificate chain)
|
||||
- Clients checking certificate status via OCSP or CRL see revoked status within 24 hours.
|
||||
|
||||
- **Private Key Destruction on Agent** — When certificate renewed or revoked:
|
||||
- Agent removes old private key file from `CERTCTL_KEY_DIR` when new certificate deployed.
|
||||
- Job status tracking confirms old key is no longer needed.
|
||||
- No audit trail of key deletion (private keys don't pass through control plane).
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Revocation requests: `GET /api/v1/audit?type=certificate_revoked` with RFC 5280 reason codes.
|
||||
- CRL publication: HTTP GET `/api/v1/crl` and parse JSON to show revoked serial numbers and timestamps.
|
||||
- OCSP responder validation: Query `GET /api/v1/ocsp/{issuer}/{serial}` for a known-revoked cert; response includes `revoked` status.
|
||||
- Audit trail: Certificate status transitions (Active → Revoked) recorded in `audit_events`.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Revoke certificates immediately upon key compromise suspicion** using reason code `keyCompromise`.
|
||||
- **Revoke certificates at end of lifecycle** (host decommissioning, service sunset) using reason code `cessationOfOperation`.
|
||||
- **Monitor CRL/OCSP availability** — ensure clients can check revocation status (test with TLS validator tools).
|
||||
- **Establish certificate revocation procedure** (who can revoke, approval workflow if required, documentation).
|
||||
- **Physically destroy backup private keys** (if offline backups are kept) when certificate is revoked or after archival period expires.
|
||||
- **Test revocation workflow in staging** — issue test cert, revoke, verify OCSP/CRL reflects revocation within SLA.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
---
|
||||
|
||||
## Requirement 8: Identify and Authenticate
|
||||
|
||||
**Objective**: Limit access to system components and cardholder data by business need-to-know, and authenticate and manage all access.
|
||||
|
||||
### 8.3 — Strong Authentication
|
||||
|
||||
**Requirement**: Authentication mechanisms must use strong cryptography and render authentication credentials (passwords, passphrases, keys) unreadable during transmission and storage.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **API Key Authentication** — All REST API endpoints require authentication (default):
|
||||
- Bearer token format: `Authorization: Bearer sk-...`
|
||||
- Key stored as SHA-256 hash in database (plaintext never persisted).
|
||||
- Comparison uses `crypto/subtle.ConstantTimeCompare` to prevent timing attacks.
|
||||
- Configuration: `CERTCTL_AUTH_TYPE=api-key` (enforced by default, no opt-out without explicit env var).
|
||||
|
||||
- **GUI Authentication Context** — Web dashboard login flow:
|
||||
- Login page (`/login`) accepts API key entry.
|
||||
- AuthProvider context stores API key in session (localStorage in browser, sent in Authorization header for all API calls).
|
||||
- 401 Unauthorized responses trigger automatic redirect to login.
|
||||
- Logout button clears session.
|
||||
- No session server-side (stateless API).
|
||||
|
||||
- **Credential Transmission** — All API traffic over TLS:
|
||||
- HTTPS enforced at server level (no plaintext HTTP).
|
||||
- API key transmitted in Authorization header (not URL parameter, not cookie).
|
||||
- Browser to server: TLS.
|
||||
- Agent to server: TLS.
|
||||
- No credential logging (API key hash only, never plaintext).
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- API configuration: `CERTCTL_AUTH_TYPE=api-key` in deployment manifest.
|
||||
- Database schema: `api_keys` table showing SHA-256 hash column, not plaintext.
|
||||
- API audit log: `GET /api/v1/audit?action=api_call` showing Bearer token validation (no plaintext keys logged).
|
||||
- TLS certificate on control plane: `openssl s_client -connect {server}:8443` showing valid certificate, TLS 1.2+, strong cipher.
|
||||
- GUI login flow: browser network tab showing Authorization header (token value redacted in compliance report).
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Issue API keys to users/systems** requiring API access (outside certctl; you maintain key registry).
|
||||
- **Rotate API keys periodically** (recommendation: annually, or when personnel changes).
|
||||
- **Revoke API keys immediately** when user leaves or token is compromised (set `enabled=false` in API key management — not yet implemented in v1, owner must track manually).
|
||||
- **Enforce strong TLS** on control plane: TLS 1.2+, modern ciphers (configure on reverse proxy or `CERTCTL_TLS_*` env vars if operator-controlled).
|
||||
- **Protect `.env` and credential files** where API key is defined (restrict file system access, no version control).
|
||||
- **Monitor API audit trail** for suspicious access patterns (many 401 errors, access from unexpected IPs, etc.).
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
### 8.6 — Application Account Management
|
||||
|
||||
**Requirement**: Users' system access must be restricted to the minimum level of application functions or data needed to perform duties. Application accounts (non-human) must use strong authentication.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **No Application Account Management in v1** — Certctl does not manage user accounts (no user directory, LDAP, OIDC).
|
||||
- All authentication via API key (service-to-service or human user with API key).
|
||||
- No per-user roles or permissions (that's V3 RBAC feature).
|
||||
- Single API key shared across team or one key per automation script (operator's responsibility to manage).
|
||||
|
||||
- **Credentials Not in Source Code** — Security hardening:
|
||||
- API keys via `CERTCTL_API_KEY` env var (not in `main.go`, Dockerfile, `docker-compose.yml`).
|
||||
- Database credentials via `CERTCTL_DATABASE_URL` in `.env` (git-ignored).
|
||||
- CA private key path via `CERTCTL_CA_CERT_PATH`/`CERTCTL_CA_KEY_PATH` (not inline).
|
||||
|
||||
- **Service Account Isolation** (planned for V3) — Future RBAC will support:
|
||||
- Automation script API keys with scoped permissions (e.g., read-only, renew-only, deploy-only).
|
||||
- OIDC/SSO for human users with fine-grained role assignment (admin, operator, viewer).
|
||||
- Audit trail showing which account/role performed each action.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Deployment manifest (Dockerfile, docker-compose.yml) showing no hardcoded API keys, database credentials, or CA key paths.
|
||||
- `.env` file existence (confirm via CI or compliance check, without sharing contents).
|
||||
- `.gitignore` configuration showing `.env`, `*.key`, secrets excluded.
|
||||
- Code review: grep `main.go`, `config.go` for `CERTCTL_API_KEY` — should only see env var reference, not hardcoded values.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Manage API keys externally** (issue, rotate, revoke).
|
||||
- **Document who/what has API key access** (automation scripts, team members, third-party integrations).
|
||||
- **Rotate application credentials** (API keys, database passwords) according to your organization's policy.
|
||||
- **Segregate credentials** — one API key per automation script where possible, or use V3 RBAC scoping.
|
||||
- **Monitor application account usage** via audit trail — `GET /api/v1/audit` filtered by action/actor.
|
||||
|
||||
**Status**: **Available in part** (v1.0: credentials out of source code). **Planned V3**: scoped API keys and RBAC.
|
||||
|
||||
---
|
||||
|
||||
## Requirement 10: Log and Monitor
|
||||
|
||||
**Objective**: Log and monitor access to network resources and cardholder data.
|
||||
|
||||
### 10.2 — Implement Automated Audit Logging
|
||||
|
||||
**Requirement**: Automatically log and monitor all access to system components and records containing cardholder data.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Immutable API Audit Log** (M19) — Middleware captures every API call:
|
||||
- `audit_events` table (append-only, no UPDATE/DELETE):
|
||||
- `method`: HTTP method (GET, POST, PUT, DELETE)
|
||||
- `path`: API endpoint path (e.g., `/api/v1/certificates`)
|
||||
- `actor`: authenticated user/service (extracted from API key or context)
|
||||
- `body_hash`: SHA-256 hash of request body (truncated to 16 chars, first 8 chars shown in logs)
|
||||
- `status_code`: HTTP response status (200, 201, 400, 401, 404, 500, etc.)
|
||||
- `latency_ms`: request duration in milliseconds
|
||||
- `timestamp`: RFC 3339 timestamp
|
||||
|
||||
- **Certificate Lifecycle Events** — Higher-level events logged separately:
|
||||
- `certificate_issued` — new certificate created, issuer, profile, profile ID
|
||||
- `certificate_renewed` — certificate renewed, old/new serial, renewal policy
|
||||
- `certificate_revoked` — certificate revoked, RFC 5280 reason code
|
||||
- `certificate_deployed` — certificate deployed to target, agent, target type
|
||||
- `certificate_validated` — validation job result (success/failure reason)
|
||||
|
||||
- **Job Lifecycle Events** — Job status transitions:
|
||||
- `job_created` — renewal/issuance/deployment/validation job created
|
||||
- `job_status_updated` — job state change (Pending → AwaitingCSR → Running → Completed/Failed)
|
||||
|
||||
- **Policy and Configuration Events** — Administrative changes:
|
||||
- `policy_created`, `policy_updated`, `policy_deleted` — renewal policy changes
|
||||
- `profile_created`, `profile_updated`, `profile_deleted` — certificate profile changes
|
||||
- `issuer_created`, `issuer_deleted` — CA connector registration changes
|
||||
|
||||
- **Excluded Paths** — Health/readiness probes not logged to reduce noise:
|
||||
- `GET /health` (excluded by default)
|
||||
- `GET /ready` (excluded by default)
|
||||
- Configurable via `CERTCTL_AUDIT_EXCLUDE_PATHS` env var
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Audit trail export: `GET /api/v1/audit` or manual database query, showing sample events with timestamp, actor, action, resource.
|
||||
- API call audit log: Query `audit_events` table showing method, path, actor, status code for last 24-48 hours.
|
||||
- Configuration changes: `GET /api/v1/audit?type=policy_created,policy_updated,issuer_created` showing who changed what and when.
|
||||
- Certificate lifecycle: `GET /api/v1/audit?resource_type=certificate&resource_id={cert_id}` showing complete issuance → deployment → renewal/revocation history.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Enable audit logging** — it's on by default; verify `CERTCTL_AUDIT_EXCLUDE_PATHS` is not set to exclude certificate-related paths.
|
||||
- **Monitor audit log growth** — `audit_events` table will grow with every API call. Recommend database maintenance (log rotation policy, archival after 90 days, etc.).
|
||||
- **Export and archive audit logs** — periodically `SELECT * FROM audit_events WHERE timestamp > {date}` and export to secure storage (S3, syslog, SIEM).
|
||||
- **Establish audit review procedure** — QSA may request sample of logs; have export process documented.
|
||||
- **Test audit logging** — make API call, verify event appears in audit trail within seconds.
|
||||
|
||||
**Status**: **Available** (M19 shipped)
|
||||
|
||||
### 10.3 — Protect Audit Trail
|
||||
|
||||
**Requirement**: Promptly protect audit trail files from unauthorized modifications.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Append-Only Database Design** — PostgreSQL triggers and constraints prevent modification:
|
||||
- `audit_events` table has no `UPDATE` or `DELETE` triggers.
|
||||
- Application code never executes UPDATE/DELETE on `audit_events`.
|
||||
- Primary key is `id` (serial); new events always INSERT.
|
||||
|
||||
- **Read-Only API Access** — Audit events accessible only via read (`GET /api/v1/audit`):
|
||||
- No `POST /api/v1/audit/{id}` endpoint (no creation from API).
|
||||
- No `PUT /api/v1/audit/{id}` endpoint (no modification).
|
||||
- No `DELETE /api/v1/audit/{id}` endpoint (no deletion).
|
||||
- Only control plane can record events (via internal service layer, not exposed API).
|
||||
|
||||
- **Database Access Control** (operator responsibility) — PostgreSQL user permissions:
|
||||
- `certctl` application user: INSERT, SELECT on `audit_events`.
|
||||
- `certctl_read_only` user (for compliance/audit team): SELECT only on `audit_events`.
|
||||
- `postgres` superuser: restricted to DBA operations, logged separately by PostgreSQL.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Database schema: `\d audit_events` showing columns, primary key, no UPDATE/DELETE triggers.
|
||||
- Application code review: `internal/service/audit.go` showing `RecordEvent(...)` as only INSERT operation.
|
||||
- API endpoint audit: grep `internal/api/handler/audit*.go` or `internal/api/router/router.go` — no PUT/DELETE routes for events.
|
||||
- PostgreSQL permissions: `psql -d certctl -c "\dp audit_events"` showing INSERT/SELECT grants only.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Restrict database access** — issue read-only PostgreSQL user for compliance/audit team (no write privileges).
|
||||
- **Enable PostgreSQL query logging** — log all database connections and operations for DBA audit trail.
|
||||
- **Backup audit logs** — regularly export `audit_events` to offsite storage (S3, archive tape, syslog aggregator) for long-term retention.
|
||||
- **Monitor database modifications** — alert if any UPDATE/DELETE is attempted on `audit_events` (log-based alerting or PostgreSQL event triggers).
|
||||
- **Encrypt audit exports** — if archiving to external storage, encrypt backups at rest.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
### 10.4 — Promptly Review and Address Audit Trail Exceptions
|
||||
|
||||
**Requirement**: Promptly review audit logs and investigate exceptions/anomalies.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Dashboard Charts** (M14) — Real-time observability:
|
||||
- **Renewal Success Trends** (30-day line chart) — shows job success rate; spikes in failures warrant investigation.
|
||||
- **Certificate Status Distribution** (donut chart) — shows Expiring/Expired counts; high Expired = missed renewals.
|
||||
- **Expiration Timeline** (90-day weekly heatmap) — shows upcoming expirations; bunching = renewal policy tuning needed.
|
||||
- **Issuance Rate** (30-day bar chart) — shows certificate creation/renewal activity; anomalies (zero issuances for weeks) indicate stopped automation.
|
||||
|
||||
- **Stats API** (M14) — Machine-readable trends:
|
||||
- `GET /api/v1/stats/job-trends?days=30` — renewal/issuance/deployment success/failure counts per day.
|
||||
- `GET /api/v1/stats/summary` — total certs, counts by status.
|
||||
- `GET /api/v1/stats/expiration-timeline?days=90` — expiration buckets for forecasting.
|
||||
|
||||
- **Agent Fleet Overview** (M14) — Agent health visibility:
|
||||
- Pie chart: agent status distribution (healthy, offline, error).
|
||||
- Version breakdown: agent versions in use (identify outdated agents).
|
||||
- Per-agent detail: last heartbeat timestamp, OS/architecture, IP address, recent jobs.
|
||||
|
||||
- **Alert Notifications** (M3, M16a) — Configurable escalation:
|
||||
- Email alerts: certificate approaching expiration, renewal failure, revocation notification.
|
||||
- Webhook: custom HTTP POST to your monitoring system (Slack, Teams, PagerDuty, OpsGenie, custom webhook).
|
||||
- Deduplication: one alert per threshold/certificate per day (avoid alert fatigue).
|
||||
|
||||
- **Audit Trail Filtering and Export** (M13) — Compliance reporting:
|
||||
- `GET /api/v1/audit?actor={user}×tamp_after={date}` — filter audit log by actor, timestamp, type.
|
||||
- Export CSV/JSON via dashboard: audit page → select filters → "Export CSV" or "Export JSON".
|
||||
- Can export full audit trail for QSA review.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Dashboard screenshots: expiration timeline, renewal success trends, status distribution.
|
||||
- Job trend report: `GET /api/v1/stats/job-trends?days=90` showing success/failure rates.
|
||||
- Agent fleet health: `GET /api/v1/agents` showing heartbeat status, version count distribution.
|
||||
- Audit log sample: `GET /api/v1/audit?limit=100` showing certificate issuance/renewal/revocation activity.
|
||||
- Alert configuration: screenshot of renewal policy `alert_thresholds_days` (30, 14, 7, 0) and notifier settings (email, Slack, etc.).
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Review dashboard charts weekly** — look for anomalies (high Expired count, failure spike, renewal stalled).
|
||||
- **Respond to alerts promptly** — expiration alert = investigate renewal (check job logs, issuer connectivity, agent heartbeat).
|
||||
- **Set alert thresholds appropriately** — default 30/14/7/0 days is a starting point; adjust per your SLA and staffing.
|
||||
- **Maintain alert distribution list** — ensure alerts reach the right on-call engineer/team.
|
||||
- **Archive and review audit logs** — export monthly/quarterly for compliance trending (e.g., "all certificate changes last quarter").
|
||||
- **Test alert delivery** — trigger a test renewal failure or manual revocation, verify alert is sent.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped, M14 observable charts, M19 audit log)
|
||||
|
||||
### 10.7 — Retain and Protect Audit Trail History
|
||||
|
||||
**Requirement**: Retain audit trail history for at least one year and ensure it can be retrieved.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Immutable Audit Trail** (M19) — `audit_events` table stores all API calls and certificate lifecycle events with timestamps.
|
||||
- **No Automatic Purge** — Certctl does not delete audit events. They remain in PostgreSQL indefinitely.
|
||||
- **Queryable History** — All events accessible via `GET /api/v1/audit` with time range, actor, resource filters.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Database retention policy: confirm `audit_events` table has no DELETE triggers or maintenance jobs that purge events.
|
||||
- Sample audit query: `SELECT COUNT(*) FROM audit_events WHERE timestamp > NOW() - INTERVAL '365 days'` showing one year+ of events.
|
||||
- Export procedure: documented process for exporting audit logs to cold storage (S3, archive tape, syslog).
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Configure PostgreSQL backup/retention** — certctl relies on database backups for audit trail protection.
|
||||
- Backup `audit_events` table daily or per your RPO/RTO.
|
||||
- Retain backups for at least 1 year (configure retention policy on backup system).
|
||||
- Test restore procedure annually.
|
||||
|
||||
- **Export and archive audit logs** — periodically export `SELECT * FROM audit_events WHERE timestamp > {start_date}` to offsite storage.
|
||||
- Recommendation: monthly exports to S3 with versioning enabled.
|
||||
- Encrypt exports at rest.
|
||||
- Retain archives for at least 3 years (adjust per your compliance requirements).
|
||||
|
||||
- **Monitor audit log growth** — `audit_events` table will grow ~1-5 MB/day depending on API call volume.
|
||||
- Estimate: 10,000 API calls/day = ~50 MB/month.
|
||||
- Plan PostgreSQL storage and backup capacity accordingly.
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
---
|
||||
|
||||
## Requirement 6: Develop and Maintain Secure Systems and Applications
|
||||
|
||||
**Objective**: Develop and maintain secure systems and applications.
|
||||
|
||||
### 6.3.1 — Security Coding Practices
|
||||
|
||||
**Requirement**: Develop all custom application code in accordance with secure coding practices and include authentication, access control, input validation, and error handling.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Input Validation** — Centralized validators enforce strong input constraints:
|
||||
- Common name: max 253 chars, DNS-safe characters only, no leading/trailing hyphens.
|
||||
- CSR PEM: must be valid PEM format (regex validation).
|
||||
- Policy type: whitelist enum (Issuance, Renewal, Revocation, etc.).
|
||||
- API key: alphanumeric + hyphens only.
|
||||
- Implemented in `internal/domain/validation.go` and called from all handler layer inputs.
|
||||
|
||||
- **Error Handling** — No sensitive data leakage in error responses:
|
||||
- HTTP 500 errors return generic "Internal Server Error" message, not stack trace.
|
||||
- Database errors logged internally (structured slog), not exposed to client.
|
||||
- 404 errors do not reveal whether resource exists (consistent "Not Found" regardless of auth vs. not-found).
|
||||
|
||||
- **No Hardcoded Credentials** — All secrets via environment variables:
|
||||
- `CERTCTL_API_KEY`, `CERTCTL_DATABASE_URL`, `CERTCTL_CA_KEY_PATH` — env vars only.
|
||||
- Credentials not in `main.go`, Dockerfile, `docker-compose.yml`, or Git history.
|
||||
- `.env` file git-ignored and excluded from version control.
|
||||
|
||||
- **Dependency Management** — Go module pinning (`go.mod`):
|
||||
- All external dependencies pinned to specific versions.
|
||||
- No wildcard versions or `latest` tags.
|
||||
- CI runs `go mod verify` to detect tampering.
|
||||
|
||||
**Evidence You Can Provide**:
|
||||
- Code review: `internal/domain/validation.go` showing input validation functions (Common name length, CSR PEM, policy type, etc.).
|
||||
- Error handling audit: `internal/api/handler/certificates.go` showing HTTP error responses (no stack traces).
|
||||
- Credentials in source code check: `grep -r "CERTCTL_API_KEY\|DATABASE_URL\|CA_KEY" cmd/ internal/ | grep -v ".env"` (should only show env var references, not values).
|
||||
- `go.mod` review: no wildcard versions, all pinned.
|
||||
- CI workflow: `.github/workflows/ci.yml` showing `go mod verify` step.
|
||||
|
||||
**Operator Responsibility**:
|
||||
- **Review dependency updates** — keep Go version current, update certctl dependencies regularly (security patches).
|
||||
- **Scan container images** — use Trivy, Clair, or similar to scan Docker images for known vulnerabilities.
|
||||
- **Maintain secure coding practices** in any custom issuer/target connectors you deploy (scripts for OpenSSL, BASH/PowerShell for IIS/F5).
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
### 6.5.10 — Broken Authentication and Cryptography Prevention
|
||||
|
||||
**Requirement**: Prevent broken authentication and cryptography weaknesses.
|
||||
|
||||
**certctl Support**:
|
||||
|
||||
- **Authentication** — API key with SHA-256 hashing, constant-time comparison (`crypto/subtle.ConstantTimeCompare`).
|
||||
- **Cryptography** — Go's `crypto/*` standard library (no weak ciphers). ECDSA P-256, RSA 2048+.
|
||||
- **TLS** — HTTPS enforced (no plaintext HTTP endpoints).
|
||||
- **No Sessions** — Stateless API (no session cookies, no session fixation risk).
|
||||
|
||||
**Status**: **Available** (v1.0 shipped)
|
||||
|
||||
---
|
||||
|
||||
## Requirement 7: Restrict Access by Business Need-to-Know
|
||||
|
||||
**Objective**: Limit access to system components and cardholder data by business need-to-know and ensure users are authenticated and authorized.
|
||||
|
||||
### 7.2 — Implement Access Control
|
||||
|
||||
**Requirement**: Ensure proper user identity management and implement access controls based on business need-to-know.
|
||||
|
||||
**certctl v1 Support** (limited):
|
||||
- **Certificate Ownership** (M11b) — Each certificate assigned to owner (person + email) and optional team. Ownership is metadata; access control is not enforced at API level.
|
||||
- **Agent Groups** (M11b) — Renewal policies target specific agent groups (OS, architecture, CIDR, version). Groups are used for policy targeting, not user access control.
|
||||
- **Interactive Approval** (M11b) — `AwaitingApproval` job state allows manual approval/rejection of renewals (enforcement of business workflows, not user access control).
|
||||
|
||||
**certctl v3 Support** (planned):
|
||||
- **OIDC/SSO** — Okta, Azure AD, Google integration. Users log in via identity provider.
|
||||
- **Role-Based Access Control (RBAC)** — Three roles: admin (all operations), operator (issue/renew/deploy), viewer (read-only). Roles assigned via OIDC claims or group membership.
|
||||
- **Profile/Owner Gating** — Operator can renew only certificates assigned to their team; viewer cannot modify anything.
|
||||
- **Audit Trail Attribution** — Every action shows which user/role performed it.
|
||||
|
||||
**Evidence You Can Provide** (v1):
|
||||
- Certificate ownership mapping: `GET /api/v1/certificates` showing owner, team fields (metadata only; access not controlled).
|
||||
- Agent group targeting: `GET /api/v1/policies` showing `agent_group_id` field.
|
||||
- Interactive approval workflow: job detail showing `AwaitingApproval` state, approve/reject endpoints in API docs.
|
||||
|
||||
**Operator Responsibility** (v1):
|
||||
- **Manage API key distribution** externally — only issue API keys to authorized users/systems.
|
||||
- **Implement reverse proxy auth** (Nginx, Apache, Okta proxy) in front of certctl to enforce OIDC/LDAP (outside certctl).
|
||||
- **Plan for V3 RBAC** — budget for upgrade when finer-grained access control is needed.
|
||||
|
||||
**Planned** (V3):
|
||||
- Upgrade to certctl Pro with OIDC/RBAC and per-role audit trail.
|
||||
|
||||
**Status**: **Available in part** (v1.0: ownership metadata, agent group targeting). **Planned V3**: OIDC/RBAC enforcement.
|
||||
|
||||
---
|
||||
|
||||
## Evidence Summary Table
|
||||
|
||||
| PCI-DSS Requirement | certctl Feature | API/UI Evidence | Database/Config | Audit Trail | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| **4.2.1** Strong Crypto | TLS cert issuance, ACME/step-ca/Local CA, RSA 2048+/ECDSA P-256 | `GET /api/v1/certificates` (key_type, key_size) | Certificate profiles | `GET /api/v1/audit?type=certificate_issued` | Available |
|
||||
| **4.2.2** Cert Inventory & Validation | Managed cert CRUD, discovery (M18b), expiration alerting, CRL/OCSP | `GET /api/v1/certificates`, `GET /api/v1/discovered-certificates`, `GET /api/v1/crl`, `GET /api/v1/ocsp/{issuer}/{serial}` | `managed_certificates`, `discovered_certificates` tables | `GET /api/v1/audit?type=certificate_*` | Available |
|
||||
| **3.6** Key Documentation | Profiles, owner/team tracking, issuer config, audit trail | `GET /api/v1/profiles`, `GET /api/v1/issuers`, certificate detail with owner/team | Profiles, certificate owner/team fields, issuer config | `GET /api/v1/audit?resource_type=certificate` | Available |
|
||||
| **3.7.1** Key Generation | Agent-side ECDSA P-256, server keygen (demo only) | Agent logs, renewal job detail, CSR audit | `CERTCTL_KEYGEN_MODE=agent` (config), job_type=AwaitingCSR | `GET /api/v1/audit?type=certificate_issued` with CSR hash | Available |
|
||||
| **3.7.2** Key Storage | Agent `/var/lib/certctl/keys` (0600), env var secrets, .env excluded | Deployment manifest (env var refs), agent key dir listing | `.env` file (git-ignored), `CERTCTL_KEY_DIR`, `CERTCTL_CA_KEY_PATH` | No API audit (keys off-platform) | Available |
|
||||
| **3.7.3** Key Rotation | Auto renewal, expiration thresholds, renewal jobs | Dashboard renewal trends, `GET /api/v1/jobs?type=Renewal`, certificate versions | Renewal policies, certificate version history | `GET /api/v1/audit?type=certificate_renewed` | Available |
|
||||
| **3.7.4** Key Destruction | Revocation API (RFC 5280), CRL/OCSP, private key cleanup | `POST /api/v1/certificates/{id}/revoke`, `GET /api/v1/crl`, OCSP endpoint | `certificate_revocations` table, CRL publication | `GET /api/v1/audit?type=certificate_revoked` | Available |
|
||||
| **8.3** Strong Authentication | API key (SHA-256 hash, TLS), GUI login, 401 redirect | GUI login screenshot, API key auth header, TLS cert | API key hash in database | `GET /api/v1/audit` showing API calls | Available |
|
||||
| **8.6** Acct Management | Credentials out of source, .env excluded, env var config | Code review (no hardcoded secrets), `.gitignore` check | Deployment manifests showing env var refs only | No account lifecycle audit (outside scope) | Available in part |
|
||||
| **10.2** Audit Logging | API audit middleware (M19), certificate lifecycle events | `GET /api/v1/audit` with filter/pagination | `audit_events` table (every API call) | Real-time via API | Available |
|
||||
| **10.3** Audit Protection | Append-only table design, read-only API, DB permissions | API endpoint audit (no PUT/DELETE on events), DB schema | `audit_events` table, PostgreSQL GRANT SELECT | Immutable by design | Available |
|
||||
| **10.4** Review & Alert | Dashboard charts, stats API, notifier integrations | Dashboard (renewal trends, status pie, expiration heatmap), `GET /api/v1/stats/*` | Job results, alert config in policies | `GET /api/v1/audit?type=job_*` | Available |
|
||||
| **10.7** Retention | 1+ year in PostgreSQL, export/archive procedures | Database query `SELECT COUNT(*) FROM audit_events WHERE timestamp > NOW() - INTERVAL '1 year'` | `audit_events` table retention (no auto-delete) | Manual export/archival (operator) | Available |
|
||||
| **6.3.1** Secure Coding | Input validation, error handling, no hardcoded secrets, dependency pinning | Code review (validation.go, handlers), error responses | `go.mod` with pinned versions, `.gitignore` | GitHub Actions CI with `go mod verify` | Available |
|
||||
| **7.2** Access Control | Ownership metadata, agent groups, interactive approval | `GET /api/v1/certificates` (owner/team), `GET /api/v1/agent-groups` | Certificate owner/team fields, agent group criteria | User identity from auth context | Available in part (V3: RBAC) |
|
||||
|
||||
---
|
||||
|
||||
## Operator Responsibilities
|
||||
|
||||
The following control objectives are **outside certctl's scope** and must be managed by your organization:
|
||||
|
||||
| Control Objective | Responsibility | Example Actions |
|
||||
|---|---|---|
|
||||
| **Network Segmentation** | Isolate certctl control plane from cardholder network | Place certctl on separate VLAN, firewall rules |
|
||||
| **Physical Security** | Restrict access to servers/databases | Data center access controls, logging |
|
||||
| **Personnel Screening** | Background checks for staff with access | HR/employment verification |
|
||||
| **Access Control Enforcement** | User authentication & authorization outside API | Implement reverse proxy with OIDC (V3: use certctl Pro RBAC) |
|
||||
| **Incident Response** | Procedures for certificate compromise or breach | Document key revocation process, alert escalation |
|
||||
| **Disaster Recovery** | Backup and restore procedures | Database backup schedule, offsite replication |
|
||||
| **Change Management** | Approval process for config/cert changes | CAB meetings, documented procedures |
|
||||
| **Vulnerability Scanning** | ASV scanning, penetration testing, code review | Annual PCI-DSS penetration test |
|
||||
| **Key Backup & Escrow** | Secure offline storage of CA private keys (if required) | Hardware security module (HSM) or encrypted vault |
|
||||
| **Audit Log Retention** | Long-term archival and protection of audit logs | Export to S3/syslog, retain 3+ years |
|
||||
| **QSA Engagement** | Schedule and coordination of compliance assessment | Annual audit with qualified security assessor |
|
||||
|
||||
---
|
||||
|
||||
## V3 Enhancements for PCI-DSS
|
||||
|
||||
Certctl v3 (Pro) adds paid features that strengthen PCI-DSS compliance posture:
|
||||
|
||||
| Feature | PCI-DSS Benefit |
|
||||
|---|---|
|
||||
| **OIDC/SSO Authentication** | Centralized identity management, audit integration with corporate directory |
|
||||
| **Role-Based Access Control (RBAC)** | Least-privilege enforcement: admin, operator, viewer roles with profile/team gating |
|
||||
| **Bulk Revocation by Profile/Owner/Agent** | Rapid incident response (revoke all certs in cardholder network in minutes) |
|
||||
| **NATS Event Bus with JetStream Audit Streaming** | Real-time event streaming to SIEM (Splunk, ELK, Datadog) for centralized audit trail |
|
||||
| **Certificate Health Scores** | Proactive risk identification (composite scoring: expiration proximity, rotation age, key strength) |
|
||||
| **Advanced Search DSL** | Complex audit queries (POST /search with nested AND/OR, regex, field projection) for compliance reporting |
|
||||
| **CT Log Monitoring** | Detect unauthorized certificate issuance (security vulnerability detection) |
|
||||
| **DigiCert Issuer Connector** | Enterprise CA integration for compliance audits |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps for Compliance
|
||||
|
||||
1. **Review this mapping with your QSA** — Confirm which requirements apply to your cardholder data environment.
|
||||
|
||||
2. **Configure certctl for your environment**:
|
||||
- Set `CERTCTL_KEYGEN_MODE=agent` in production.
|
||||
- Define certificate profiles with approved key types.
|
||||
- Configure renewal policies with appropriate thresholds (e.g., 30 days for 90-day certs).
|
||||
- Enable notifier integrations (email, Slack, PagerDuty) for alerts.
|
||||
- Plan `CERTCTL_DISCOVERY_DIRS` on agents to scan all certificate locations.
|
||||
|
||||
3. **Implement operator controls**:
|
||||
- Document certificate management procedures (issuance, renewal, revocation, archival).
|
||||
- Establish API key rotation schedule.
|
||||
- Set up audit log export and archival (monthly to S3, retain 1+ year).
|
||||
- Configure PostgreSQL backups (daily, 1+ year retention).
|
||||
- Plan incident response (who revokes certs, escalation process, timeline).
|
||||
|
||||
4. **Test compliance readiness**:
|
||||
- Trigger a test renewal and verify CRL/OCSP publication.
|
||||
- Export audit trail and verify it shows expected events.
|
||||
- Test revocation workflow and confirm OCSP reflects status within 24 hours.
|
||||
- Run discovery scan and verify unknown certs are detected and triaged.
|
||||
|
||||
5. **Prepare evidence for QSA**:
|
||||
- API endpoint documentation (OpenAPI spec: `api/openapi.yaml`).
|
||||
- Audit log sample (last 90 days of events).
|
||||
- Configuration export (profiles, policies, issuer/target definitions).
|
||||
- Deployment manifest (showing env var config, no hardcoded secrets).
|
||||
- Test certificates and CRL/OCSP query results.
|
||||
|
||||
6. **Plan for V3** (if RBAC/centralized audit required):
|
||||
- Evaluate certctl Pro for OIDC/SSO and NATS audit streaming.
|
||||
- Assess integration with existing identity provider (Okta, Azure AD, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Questions?
|
||||
|
||||
For additional guidance on certctl features and PCI-DSS mapping:
|
||||
- Review the [Architecture Guide](architecture.md) for system design.
|
||||
- Check [Connectors Documentation](connectors.md) for issuer/target/notifier capabilities.
|
||||
- Run the [Demo Guide](demo-guide.md) to see features in action.
|
||||
- Consult your QSA for final compliance determination.
|
||||
|
||||
**Last Updated**: March 24, 2026 (certctl v1.0 with M18b discovery and M19 audit logging)
|
||||
@@ -0,0 +1,549 @@
|
||||
# SOC 2 Type II Compliance Mapping
|
||||
|
||||
This guide maps certctl's implemented features to AICPA SOC 2 Trust Service Criteria (TSC). It is **not a SOC 2 certification claim** — rather, it helps security engineers, auditors, and evaluators understand how certctl supports your organization's SOC 2 compliance posture. Use this as evidence input for your own control assessment during SOC 2 audits.
|
||||
|
||||
## How to Use This Guide
|
||||
|
||||
SOC 2 audits require evidence that your infrastructure meets specific Trust Service Criteria. Auditors ask: "Does your certificate management tooling support CC6.1 logical access controls?" This guide answers by mapping certctl's features to specific criteria and pointing to evidence (API endpoints, configuration, audit trail).
|
||||
|
||||
Each section includes:
|
||||
|
||||
- **The TSC requirement** — what the auditor is looking for
|
||||
- **certctl's implementation** — which features address it
|
||||
- **Evidence location** — where to find proof (API endpoint, config variable, source code, audit events)
|
||||
- **V2 vs V3 status** — whether feature is in the free community edition (V2) or paid Pro edition (V3)
|
||||
- **Operator responsibility** — aspects your organization must handle outside of certctl
|
||||
|
||||
## CC6: Logical and Physical Access Controls
|
||||
|
||||
### CC6.1 — Logical Access Security
|
||||
|
||||
**Requirement**: The entity restricts logical access to digital and information assets and related facilities by applying user identity authentication, registration, access rights, and usage policies.
|
||||
|
||||
**certctl Implementation** (V2 — Community Edition):
|
||||
|
||||
- **API Key Authentication** — All API calls require a Bearer token (hashed with SHA-256, stored securely, validated with constant-time comparison) or are rejected with 401 Unauthorized. Environment: `CERTCTL_AUTH_TYPE` (default `api-key`; `none` requires explicit opt-in with log warning)
|
||||
- **GUI Authentication** — Web dashboard includes login screen requiring API key entry. Failed auth redirects to login on 401. Auth context persists across page navigation. Logout clears session.
|
||||
- **Configurable CORS** — API restricts cross-origin requests via `CERTCTL_CORS_ORIGINS` allowlist or wildcard. Preflight caching prevents chatty browser auth flows.
|
||||
- **Token Bucket Rate Limiting** — Per-IP rate limiting (configurable via `CERTCTL_RATE_LIMIT_RPS` / `CERTCTL_RATE_LIMIT_BURST`) returns 429 Too Many Requests with Retry-After header. Prevents credential stuffing and brute-force attacks.
|
||||
- **No Password Storage** — certctl does not store user passwords. API keys are the sole authentication mechanism. Your API key generation, distribution, and rotation policies are your responsibility (see "Operator Responsibility" below).
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- API auth implementation: `internal/api/middleware/auth.go`
|
||||
- Auth check endpoint: `GET /api/v1/auth/check` (validates credentials)
|
||||
- Auth info endpoint: `GET /api/v1/auth/info` (returns current auth mode, served without auth so GUI detects mode)
|
||||
- Rate limiting middleware: `internal/api/middleware/rate_limit.go`
|
||||
- CORS configuration: `cmd/server/main.go`, search for `CERTCTL_CORS_ORIGINS`
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **OIDC / SSO Integration** — Optional OIDC providers (Okta, Azure AD, Google) with multi-tenant support. API key fallback for service accounts.
|
||||
- **API Key Scoping** — Per-resource or per-action permissions (e.g., "read certificates from production only" or "issue certs, no revoke")
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Generate and securely distribute API keys to authorized users and systems
|
||||
- Rotate API keys regularly (recommend quarterly)
|
||||
- Revoke API keys immediately upon employee departure
|
||||
- Do not commit API keys to version control (use `.env` or secrets management)
|
||||
- Implement your own IP allowlisting at the firewall if needed (certctl enforces CORS at the HTTP layer, not at network layer)
|
||||
|
||||
---
|
||||
|
||||
### CC6.2 — Prior to Issuing System Credentials
|
||||
|
||||
**Requirement**: The entity provisions, modifies, disables, and removes user identities and rights based on an authorization process that considers user responsibility level and changes in those responsibilities.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Ownership Attribution** — Certificates can be assigned to an owner (email + name). Owner information is stored and audited (see CC7.2). Ownership is tracked through the lifecycle (issuance, renewal, deployment, revocation). Ownership reassignment is audited via the immutable audit trail.
|
||||
- **Team Assignment** — Owners can be organized into teams. Certificate policies can route notifications to team email addresses.
|
||||
- **Audit Trail Attribution** — Every API call records the actor (extracted from the API key or auth context). The audit trail is immutable — no retroactive modification of who did what.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Ownership domain model: `internal/domain/certificate.go` (OwnerID field)
|
||||
- Owner CRUD API: `GET /api/v1/owners`, `POST /api/v1/owners`, `DELETE /api/v1/owners/{id}`
|
||||
- Team CRUD API: `GET /api/v1/teams`, `POST /api/v1/teams`, `DELETE /api/v1/teams/{id}`
|
||||
- Audit trail API: `GET /api/v1/audit` (actor field in every record)
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **RBAC (Role-Based Access Control)** — Predefined roles (Admin, Operator, Viewer) with profile-gated permissions. Administrators manage role assignments.
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Map certctl's ownership model to your organizational structure (departments, teams, on-call rotations)
|
||||
- Establish a formal access request and approval process
|
||||
- Remove ownership access when team members depart
|
||||
- Document your access review process (audit trail shows *who* made changes, but you must justify *why*)
|
||||
|
||||
---
|
||||
|
||||
### CC6.3 — Authentication Policies
|
||||
|
||||
**Requirement**: The entity determines, documents, communicates, and enforces authentication policies that support the identification and authentication of authorized internal and external users and the transmission of user credentials.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **API Key Policy** — All API access requires an API key or explicit opt-out. Opt-out (`CERTCTL_AUTH_TYPE=none`) logs a warning: "WARNING: Auth disabled (CERTCTL_AUTH_TYPE=none) — this is insecure and only for development". Configuration choice is logged at startup.
|
||||
- **Agent Authentication** — Agents authenticate to the server via API keys (same mechanism as users). Agent credentials are separate from user API keys.
|
||||
- **Private Key Policy** — Agent-side key generation is the default (`CERTCTL_KEYGEN_MODE=agent`). Server-side keygen (`CERTCTL_KEYGEN_MODE=server`) requires explicit configuration and logs a warning: "Server-side keygen enabled — private keys will be stored in PostgreSQL (development only)".
|
||||
- **Password Policy** — Not applicable; certctl uses API keys exclusively. Password management is delegated to your organization's IAM system if you integrate OIDC/SSO (V3).
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Auth type configuration: `internal/config/config.go`, `CERTCTL_AUTH_TYPE` env var
|
||||
- Startup logging: `cmd/server/main.go` (logs auth mode at server startup)
|
||||
- Keygen mode configuration: `internal/config/config.go`, `CERTCTL_KEYGEN_MODE` env var
|
||||
- Keygen mode warning: `cmd/server/main.go` and `cmd/agent/main.go`
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **OIDC Policy** — Mandatory MFA when OIDC is enabled
|
||||
- **API Key Expiration** — Automatic key rotation policies (e.g., 90-day expiration for user keys, no expiration for long-lived service account keys)
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Document your API key generation and distribution policy
|
||||
- Establish a formal change control process for auth configuration changes
|
||||
- Test authentication failures (e.g., expired keys, malformed tokens) in a non-production environment
|
||||
- Integrate certctl authentication into your organization's IAM audit reports (who has API keys, when were they issued, who has revoked them)
|
||||
|
||||
---
|
||||
|
||||
### CC6.7 — Information Transmission Protection
|
||||
|
||||
**Requirement**: The entity restricts the transmission, movement, and removal of information in a manner that prevents unauthorized disclosure, whether through digital or non-digital means.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **TLS for Control Plane** — All API communication occurs over HTTPS (TLS 1.2+). Server uses `tls.Dial()` for outbound connections to issuers and targets. Configuration: `CERTCTL_SERVER_ADDR` (default `:8443`).
|
||||
- **Agent-to-Server Communication** — Agents submit CSRs and heartbeats over HTTPS to the server using the same TLS stack.
|
||||
- **Private Key Isolation** — Agents generate ECDSA P-256 private keys locally (`crypto/ecdsa` + `crypto/elliptic`). Private keys are never transmitted to the server — agents submit CSRs only. Private keys are stored on agent filesystem (`CERTCTL_KEY_DIR`, default `/var/lib/certctl/keys`) with 0600 (owner read/write only) permissions. Server-side keygen mode logs a development warning; production must use agent-side keygen.
|
||||
- **Certificate Storage** — Signed certificates are stored in PostgreSQL as PEM text (along with metadata). Certificates are not secrets and may be transmitted plaintext. Private keys are never stored on the control plane in production (agent-side keygen mode).
|
||||
- **Deployment via Target Connectors** — Target connectors write certificates and keys to local filesystem or network appliance APIs. For NGINX/Apache httpd, files are written with restrictive permissions (0600 for keys). For F5/IIS (V3+), credentials are scoped to a proxy agent in the same network zone — the server never holds network appliance credentials.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- TLS configuration: deploy certctl behind a TLS-terminating reverse proxy (NGINX, HAProxy, or cloud load balancer) or use a TLS sidecar
|
||||
- Agent keygen mode: `cmd/agent/main.go` (ECDSA key generation, filesystem storage with 0600)
|
||||
- Private key handling: `internal/connector/target/nginx/nginx.go` and similar (cert/key file write)
|
||||
- Server-side keygen deprecation: `internal/service/renewal.go` (log warning when enabled)
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **Hardware Security Module (HSM) Support** — Optional HSM backend for CA key storage (SubCA and Local CA modes)
|
||||
- **Secrets Rotation** — Encrypted key rotation without server restart
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Enable TLS on the control plane in production (deploy behind a TLS-terminating reverse proxy or load balancer with valid certificates)
|
||||
- Enforce TLS on agent-to-server communication via firewall rules (no cleartext HTTP)
|
||||
- Protect agent filesystem key storage with:
|
||||
- File-level permissions (already 0600)
|
||||
- Encrypted filesystems (LUKS, BitLocker, or cloud provider equivalents)
|
||||
- Backup encryption (keys backed up to vault or HSM, never in cleartext backups)
|
||||
- Restrict PostgreSQL access to authorized services only (network isolation, authentication)
|
||||
- For target systems, ensure network traffic from agents to targets is encrypted (TLS, IPsec, or VPN)
|
||||
|
||||
---
|
||||
|
||||
## CC7: System Operations
|
||||
|
||||
### CC7.1 — System Monitoring
|
||||
|
||||
**Requirement**: The entity monitors system components and the operation of those components for anomalies that are indicative of malfunction, including the implementation of monitoring tools, the reporting of results of those monitoring activities, and the identification, documentation, analysis, and resolution of system anomalies.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Health Endpoint** — `GET /health` returns 200 OK with service status. Consumed by Docker health checks and Kubernetes probes.
|
||||
- **Readiness Endpoint** — `GET /ready` returns 200 OK when the database is connected and migrations are applied.
|
||||
- **Background Scheduler Monitoring** — 5 background loops run on a fixed schedule:
|
||||
- Renewal loop: every 1 hour, scans for certificates approaching renewal threshold
|
||||
- Job processor loop: every 30 seconds, picks up pending/waiting jobs and advances their state
|
||||
- Health check loop: every 2 minutes, pings agents to detect downtime
|
||||
- Notification dispatcher loop: every 1 minute, sends queued alerts
|
||||
- Short-lived cert expiry loop: every 30 seconds, marks expired short-lived credentials
|
||||
Each loop includes error handling and logs failures via structured slog.
|
||||
- **JSON Metrics Endpoint** — `GET /api/v1/metrics` returns JSON object with:
|
||||
- **Gauges** — `certificates_total`, `certificates_active`, `certificates_expiring_soon`, `agents_total`, `agents_healthy`, `pending_jobs`, `failed_jobs`
|
||||
- **Counters** — `certs_issued_total`, `certs_renewed_total`, `certs_revoked_total`, `deployments_completed_total`, `deployments_failed_total`
|
||||
- **Uptime** — `uptime_seconds` (seconds since server start)
|
||||
All values are point-in-time snapshots computed from database tables.
|
||||
- **Structured Logging** — All scheduler operations, API calls, and connector actions log via `slog` (Go's structured logger). Logs include timestamp, level (DEBUG/INFO/WARN/ERROR), structured fields (e.g., `actor`, `resource_id`, `latency_ms`), and request IDs for tracing.
|
||||
- **Request ID Propagation** — Each HTTP request gets a unique ID (`X-Request-ID` header). The ID is included in all correlated logs, making it easy to trace a single request through multiple service layers.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Health/readiness endpoints: `internal/api/handler/health.go`
|
||||
- Background scheduler: `internal/scheduler/scheduler.go` (Start method)
|
||||
- Metrics endpoint: `internal/api/handler/metrics.go`
|
||||
- Stats API endpoints (for detailed time-series): `internal/api/handler/stats.go`
|
||||
- `GET /api/v1/stats/summary` — dashboard KPIs
|
||||
- `GET /api/v1/stats/certificates-by-status` — cert counts by status
|
||||
- `GET /api/v1/stats/expiration-timeline?days=N` — cert expiry distribution
|
||||
- `GET /api/v1/stats/job-trends?days=N` — job completion/failure rates
|
||||
- `GET /api/v1/stats/issuance-rate?days=N` — cert issuance volume
|
||||
- Structured logging middleware: `internal/api/middleware/middleware.go`
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Configure log aggregation (e.g., ELK, Datadog, Splunk) to centralize certctl logs
|
||||
- Set up alerting on scheduler loop failures (e.g., "renewal loop failed to complete within 2h")
|
||||
- Configure health check monitoring (e.g., Prometheus scrape of `/health` and `/ready`)
|
||||
- Establish thresholds for metrics (e.g., alert if `pending_jobs > 50` or `agents_healthy < total_agents`)
|
||||
- Document your log retention policy (audit requirement often mandates 1+ years)
|
||||
- Integrate certctl metrics into your broader observability stack (Grafana dashboards, SLO tracking)
|
||||
|
||||
---
|
||||
|
||||
### CC7.2 — Anomaly Detection
|
||||
|
||||
**Requirement**: The entity monitors system components and the operation of those components for anomalies that are indicative of malfunction, including the implementation of monitoring tools, the reporting of results of those monitoring activities, and the identification, documentation, analysis, and resolution of system anomalies.
|
||||
|
||||
(This criterion overlaps CC7.1 and extends it to specific anomaly response mechanisms.)
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Immutable API Audit Trail** (M19) — Every API call is recorded to `audit_events` table (append-only, no update/delete). Recorded: HTTP method, path, query parameters, actor (user/agent ID), SHA-256 hash of request body (truncated 16 chars for brevity), response status code, latency in milliseconds. Excluded paths (health, ready) are configurable. Audit records are async (non-blocking) and include a timestamp.
|
||||
- **Audit Trail API** — `GET /api/v1/audit?actor=...&action=...&resource_id=...&created_after=...&created_before=...` allows searching for anomalous patterns (e.g., "who accessed certificate XYZ and when?", "did anyone revoke certs at 2 AM?").
|
||||
- **Expiration Threshold Alerting** — Certificate renewal policies define alert thresholds (days before expiry): default `[30, 14, 7, 0]`. When a certificate approaches a threshold, a notification is enqueued. Deduplication prevents duplicate alerts for the same cert at the same threshold. Auto status transition: cert moves to `Expiring` status at 30 days, `Expired` at 0 days.
|
||||
- **Certificate Status Auto-Transitions** — When a cert is issued, it's `Active`. As expiry approaches, status auto-transitions to `Expiring` (at 30d threshold). At expiry, status becomes `Expired`. Revoked certs move to `Revoked`. These transitions are recorded in the audit trail.
|
||||
- **Notification Routing** — Alerts are sent via configured notifiers (Email, Slack, Teams, PagerDuty, OpsGenie). Certificates are routed to their owner's email address (or team email if no individual owner). This allows on-call teams to react to anomalies (e.g., "your production cert will expire in 7 days, request renewal now").
|
||||
- **Deployment Rollback** — If a deployment fails or an older certificate needs to be reactivated, operators can trigger a "rollback" via the GUI. This redeploys a previous certificate version to the target. Rollback actions are audited.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Audit middleware: `internal/api/middleware/audit.go`
|
||||
- Audit trail API: `internal/api/handler/audit.go`, `GET /api/v1/audit`
|
||||
- Expiration alerting: `internal/service/renewal.go` (CheckRenewal method)
|
||||
- Notification dispatcher: `internal/scheduler/scheduler.go` (notificationTicker)
|
||||
- Status transitions: `internal/service/certificate.go` (auto status update logic)
|
||||
- Audit trail CLI export: `certctl-cli audit export --format csv` / `--format json`
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **SIEM Export** — Real-time audit event streaming to SIEM systems (via NATS event bus with JetStream sink)
|
||||
- **Anomaly Rules Engine** — Configurable rules (e.g., "alert if certificate revoked by non-admin", "alert if >10 certs issued in < 1 hour")
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Integrate audit trail into your SIEM / log analysis platform
|
||||
- Define alerting rules and thresholds for anomalies (e.g., "revocation of critical cert", "mass issuance")
|
||||
- Establish a formal incident response workflow (audit trail shows *what* happened; you must decide *what to do* about it)
|
||||
- Regularly review audit logs (e.g., monthly compliance audit of who accessed what)
|
||||
- Configure email/Slack/Teams integration so on-call teams are notified of cert expirations immediately
|
||||
- Encrypt audit trail backups (ACID guarantees don't prevent theft of database backups)
|
||||
|
||||
---
|
||||
|
||||
### CC7.3 — Incident Response
|
||||
|
||||
**Requirement**: The entity detects, investigates, and responds to incidents by executing a defined incident response and management process that includes preparation, detection and analysis, containment, eradication, recovery, and post-incident activities.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Revocation API** — `POST /api/v1/certificates/{id}/revoke` with RFC 5280 reason codes:
|
||||
- `unspecified` — catch-all
|
||||
- `keyCompromise` — private key was exposed
|
||||
- `caCompromise` — CA itself was compromised (rare)
|
||||
- `affiliationChanged` — certificate no longer applies to the organization
|
||||
- `superseded` — newer cert is in use
|
||||
- `cessationOfOperation` — service is shutting down
|
||||
- `certificateHold` — temporary revocation (can be "unhold" by reissue)
|
||||
- `privilegeWithdrawn` — access rights revoked
|
||||
Revocation is **immediate** (no approval workflow). The certificate is marked `Revoked` in inventory, an audit event is logged, and optional issuer notification is best-effort. All revoked certs are excluded from active deployments.
|
||||
- **CRL Endpoint** — `GET /api/v1/crl` returns a JSON-formatted Certificate Revocation List (serial, reason, timestamp for each revoked cert). `GET /api/v1/crl/{issuer_id}` returns a DER-encoded X.509 CRL signed by the issuing CA (useful for legacy clients that don't support OCSP).
|
||||
- **OCSP Responder** — `GET /api/v1/ocsp/{issuer_id}/{serial}` returns a signed OCSP response indicating whether a cert is good, revoked, or unknown. Clients (browsers, TLS libraries) query this endpoint to verify cert validity in real-time.
|
||||
- **Revocation Notifications** — When a cert is revoked, notifications are sent to:
|
||||
- Certificate owner (email)
|
||||
- Configured webhooks (if you have a SIEM that subscribes)
|
||||
- Slack/Teams channels (if notifiers are configured)
|
||||
- **Short-Lived Cert Exemption** — Certificates with TTL < 1 hour (configured in profile) skip CRL/OCSP publication. Expiry is the revocation mechanism for short-lived certs (e.g., Kubernetes pod certs, session tokens).
|
||||
- **Deployment Rollback** — If a revoked cert is still deployed (shouldn't happen, but race conditions exist), operators can manually redeploy a previous version via the GUI. Rollback is audited.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Revocation API: `internal/api/handler/certificates.go`, `POST /api/v1/certificates/{id}/revoke`
|
||||
- Revocation domain model: `internal/domain/revocation.go` (RevocationReason type with RFC 5280 mapping)
|
||||
- CRL generation: `internal/service/certificate.go` (GenerateDERCRL method)
|
||||
- OCSP signing: `internal/service/certificate.go` (GetOCSPResponse method)
|
||||
- Revocation notifications: `internal/service/notification.go` (SendRevocationNotification)
|
||||
- Short-lived exemption: `internal/domain/revocation.go` (IsShortLivedCert check)
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **Bulk Revocation** — Revoke all certs issued by a specific profile, owner, or agent in a single API call (useful for large-scale incidents like CA compromise)
|
||||
- **Revocation Automation** — Trigger revocation based on external events (e.g., employee termination, security breach alert from CT Log monitoring)
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Establish an incident response policy (e.g., "keyCompromise → immediate deployment to new cert + notify CISO")
|
||||
- Ensure CRL/OCSP are accessible to all systems using the certs (e.g., CDN or highly-available endpoints if you host on-premises)
|
||||
- Test revocation workflow in staging (verify that revoked certs are actually blocked by clients)
|
||||
- Document justification for revocation (audit trail records *that* a cert was revoked, but not *why* — you must document it separately)
|
||||
- Integrate revocation notifications into your on-call rotation (don't let revocation alerts get lost)
|
||||
|
||||
---
|
||||
|
||||
### CC7.4 — Identify and Develop Risk Mitigation Activities
|
||||
|
||||
**Requirement**: The entity identifies, develops, and implements risk mitigation activities for risks arising from potential business disruptions.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Renewal Job Tracking** — Renewal jobs track the certificate, target agents, and issuance outcome. Failed renewals are retried (configurable backoff). Job state diagram: Pending → Running → Completed (or Failed). Failed jobs trigger notifications.
|
||||
- **Agent Health Monitoring** — Health check loop (every 2m) pings all agents via heartbeat. If an agent misses 3 consecutive heartbeats, it's marked as `Unhealthy`. Unhealthy agents are excluded from new deployments.
|
||||
- **Job Cancellation** — Operators can cancel pending jobs via `POST /api/v1/jobs/{id}/cancel`. Useful when a renewal is already in progress elsewhere (multi-instance deployments) or when a certificate is being phased out.
|
||||
- **Interactive Approval** — Renewal/issuance jobs can be put in `AwaitingApproval` status. An authorized operator reviews the pending cert and approves or rejects it. Rejection records a reason in the audit trail. This provides a separation of duty between requestor and approver.
|
||||
- **Scheduled Scanning** — Agents scan configured directories for existing certs (M18b discovery). Operators triage discovered certs (claim = "we manage this now", dismiss = "this is unmanaged and we're OK with that"). Triage decisions are audited.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Job state machine: `internal/domain/job.go` (JobStatus enum)
|
||||
- Job retry logic: `internal/scheduler/scheduler.go` (jobProcessorTicker)
|
||||
- Agent health check: `internal/scheduler/scheduler.go` (healthCheckTicker)
|
||||
- Job cancellation: `internal/api/handler/jobs.go`, `POST /api/v1/jobs/{id}/cancel`
|
||||
- Approval workflow: `internal/api/handler/jobs.go`, `POST /api/v1/jobs/{id}/approve` / `reject`
|
||||
- Discovery scan results: `internal/api/handler/discovery.go`, `GET /api/v1/discovered-certificates`
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Monitor renewal job success rate (are certs being renewed before expiry?)
|
||||
- Set up alert for unhealthy agents (missing 3+ heartbeats = broken agent, take action)
|
||||
- Establish a formal approval policy (who can approve certs? do they need to involve CISO?)
|
||||
- Test job cancellation and recovery flows in staging
|
||||
- Review discovered certs regularly (are there unmanaged certs that should be managed?)
|
||||
- Document your disaster recovery process (what if control plane database is corrupted?)
|
||||
|
||||
---
|
||||
|
||||
## A1: Availability
|
||||
|
||||
### A1.1/A1.2 — Availability and Recovery
|
||||
|
||||
**Requirement**: The entity obtains or generates, uses, retains, and disposes of information to enable the entity to meet its objectives and respond to its responsibility to provide information.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Health Probes** — `/health` and `/ready` endpoints support container orchestration (Docker Compose, Kubernetes, etc.). Docker Compose defines health checks for the server and database. Kubernetes would use liveness/readiness probes pointing to these endpoints.
|
||||
- **Database Migrations (Idempotent)** — PostgreSQL migrations use `IF NOT EXISTS` and `ON CONFLICT ... DO NOTHING` patterns. Migrations can be safely reapplied — no risk of doubling data or dropping tables mid-migration.
|
||||
- **Agent Panic Recovery** — Agent binary includes panic recovery in job execution loops. If an agent crashes during a deployment, the control plane marks the job as failed and can retry on a healthy agent.
|
||||
- **Exponential Backoff** — Agent-to-server communication uses exponential backoff (starting at 1s, capped at 5m) to handle transient network failures. This prevents thundering herd when the control plane is temporarily down.
|
||||
- **Docker Compose Deployment** — Includes health checks for server and database. Services auto-restart on failure.
|
||||
- **PostgreSQL Connection Pooling** — Server uses `database/sql` with configurable `MaxOpenConns` and `MaxIdleConns` (default 25/5). Prevents connection exhaustion.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Health endpoints: `internal/api/handler/health.go`
|
||||
- Database migrations: `migrations/` directory (all use `IF NOT EXISTS`, idempotent patterns)
|
||||
- Agent panic recovery: `cmd/agent/main.go` (defer recover() in job execution)
|
||||
- Exponential backoff: `cmd/agent/main.go` (heartbeat and work poll backoff logic)
|
||||
- Connection pooling: `cmd/server/main.go` (SetMaxOpenConns, SetMaxIdleConns)
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **Multi-Region HA** — Control plane federation with etcd consensus (operator can run N replicas)
|
||||
- **PostgreSQL HA** — Replication standby with automatic failover (operator responsibility to configure)
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Configure PostgreSQL backups (e.g., WAL archiving, daily full backups). Certctl stores certificates but *also* stores renewal policies, audit trail, deployment history.
|
||||
- Test backup/restore process in staging (broken backups are discovered during incidents)
|
||||
- Monitor disk usage (PostgreSQL will fail if `/var` fills up)
|
||||
- Plan capacity (how many certs, agents, jobs can your PostgreSQL handle? Certctl is tested with 10k+ certs, 100+ agents, but your infra may differ)
|
||||
- Set up high-availability PostgreSQL if you need zero-downtime upgrades
|
||||
- Implement network segmentation (only authorized services can reach certctl API and database)
|
||||
|
||||
---
|
||||
|
||||
## CC8: Change Management
|
||||
|
||||
### CC8.1 — Change Control
|
||||
|
||||
**Requirement**: The entity identifies, selects, and develops risk mitigation activities for risks arising from potential business disruptions.
|
||||
|
||||
**certctl Implementation** (V2):
|
||||
|
||||
- **Certificate Profiles** — Named profiles define allowed key types, max TTL, required SANs, and permitted EKUs. Changes to profiles are common (e.g., "increase max TTL from 1 year to 3 years"). All profile changes are audited (who changed what, when). Profile updates are versioned.
|
||||
- **Policy Engine** — Renewal policies define alert thresholds and approval workflows. Policy changes (e.g., "lower alert threshold from 30 days to 14 days") are audited. Policies have violation rules (e.g., "flag certs longer than 3 years") — violations are recorded in the audit trail.
|
||||
- **Target Configuration** — When a new target (NGINX server, HAProxy load balancer) is added, it's registered with a name and configuration (JSON). Target deletions require confirmation (to prevent accidental removal). All target changes are audited.
|
||||
- **Immutable Audit Trail** — Every change (profile, policy, target, cert, agent, owner, team, approval, revocation, deployment) is recorded in `audit_events`. Audit records are append-only; no retroactive modification is possible. Audit trail is encrypted at rest (operator responsibility).
|
||||
- **GitHub Actions CI** — Pull requests must pass:
|
||||
- Go unit tests (`go test ./...`) with coverage gates (service layer ≥30%, handler layer ≥50%)
|
||||
- Go vet (static analysis)
|
||||
- Frontend TypeScript type checking (`tsc`)
|
||||
- Frontend Vitest unit tests
|
||||
- Frontend Vite build (ensures no broken imports)
|
||||
Only after all checks pass can the PR be merged and deployed.
|
||||
|
||||
**Evidence Locations**:
|
||||
|
||||
- Profile CRUD: `internal/api/handler/profiles.go`, `GET /api/v1/profiles` / `POST` / `PUT` / `DELETE`
|
||||
- Policy CRUD: `internal/api/handler/policies.go`
|
||||
- Target CRUD: `internal/api/handler/targets.go`
|
||||
- Audit trail: `internal/api/handler/audit.go`, `GET /api/v1/audit` (records action, actor, resource_id, timestamp)
|
||||
- CI configuration: `.github/workflows/ci.yml` (test, vet, coverage gates, build checks)
|
||||
|
||||
**V3 Enhancement**:
|
||||
|
||||
- **Change Approval Workflow** — Optional approval gate before profile/policy changes go live
|
||||
- **Feature Flags** — Enable/disable new features without redeployment (backward compatibility during rolling upgrades)
|
||||
|
||||
**Operator Responsibility**:
|
||||
|
||||
- Implement formal change control (ticket system, approval, peer review)
|
||||
- Document the business justification for profile/policy changes
|
||||
- Test changes in a non-production environment before deploying to production
|
||||
- Have a rollback plan (can you revert a profile change instantly if it breaks issuance?)
|
||||
- Include certctl configuration changes in your change log (for audits and incident investigations)
|
||||
- Version control your certctl configuration (Docker Compose file, environment variables) so you can track changes
|
||||
|
||||
---
|
||||
|
||||
## Evidence Summary Table
|
||||
|
||||
| SOC 2 Criterion | certctl Feature | Evidence Location | V2 (Free) | V3 (Pro) | Operator Responsibility |
|
||||
|---|---|---|---|---|---|
|
||||
| **CC6.1** Logical Access Security | API Key Authentication (SHA-256 hashed, constant-time comparison) | `internal/api/middleware/auth.go` | ✅ | Enhanced | API key generation, distribution, rotation |
|
||||
| | GUI Login with API Key | `web/src/pages/LoginPage.tsx` | ✅ | Enhanced (OIDC) | NA |
|
||||
| | CORS Allowlist | `CERTCTL_CORS_ORIGINS` env var | ✅ | ✅ | Configure appropriately |
|
||||
| | Token Bucket Rate Limiting | `internal/api/middleware/rate_limit.go` | ✅ | ✅ | Monitor for brute-force attempts |
|
||||
| **CC6.2** Prior to Issuing System Credentials | Ownership Attribution | `GET /api/v1/owners`, audit trail records owner assignment | ✅ | Enhanced (RBAC) | Map to org structure, remove on departure |
|
||||
| | Team Assignment | `GET /api/v1/teams` | ✅ | ✅ | NA |
|
||||
| | Actor Attribution in Audit Trail | `GET /api/v1/audit` (actor field) | ✅ | ✅ | Justify all changes via separate documentation |
|
||||
| **CC6.3** Authentication Policies | API Key Enforcement | `CERTCTL_AUTH_TYPE=api-key` (default) | ✅ | Enhanced (OIDC, MFA) | Document policy, test failures, integrate into IAM audit |
|
||||
| | Agent Authentication | Separate API keys for agents | ✅ | ✅ | Rotate agent keys, monitor compromise |
|
||||
| | Agent-Side Key Generation | `CERTCTL_KEYGEN_MODE=agent` (default) | ✅ | ✅ | Protect agent filesystem keys via encryption/backup |
|
||||
| | Private Key Policy | Server-side keygen logs warning, disabled in production | ✅ | ✅ | Never use server-side keygen in production |
|
||||
| **CC6.7** Information Transmission Protection | TLS for Control Plane | Deploy behind TLS-terminating reverse proxy | ✅ | ✅ | Enable TLS in production via reverse proxy |
|
||||
| | Agent-to-Server HTTPS | Agents use HTTPS for all API calls | ✅ | ✅ | Enforce TLS via firewall rules |
|
||||
| | Private Key Isolation | Agent-side keygen (ECDSA P-256), keys stored 0600 on agent FS | ✅ | ✅ | Encrypt agent filesystems, backup securely |
|
||||
| | Pull-Only Deployment | Server never initiates outbound to agents/targets | ✅ | Enhanced (HSM, proxy agents) | Encrypt agent↔target comms, isolate proxy agents |
|
||||
| **CC7.1** System Monitoring | Health Endpoint | `GET /health`, `GET /ready` | ✅ | ✅ | Integrate into monitoring (Prometheus, DataDog) |
|
||||
| | Metrics JSON Endpoint | `GET /api/v1/metrics` (gauges, counters, uptime) | ✅ | ✅ | Set thresholds, configure alerting |
|
||||
| | Stats API (time-series) | `GET /api/v1/stats/*` (summary, status, expiration, jobs, issuance) | ✅ | ✅ | Integrate into dashboards, SLO tracking |
|
||||
| | Structured Logging | `slog` middleware with request IDs | ✅ | ✅ | Aggregate logs to SIEM, define retention policy |
|
||||
| | Background Scheduler | 5 loops (renewal 1h, jobs 30s, health 2m, notifications 1m, short-lived 30s) | ✅ | ✅ | Alert on scheduler loop failures |
|
||||
| **CC7.2** Anomaly Detection | Immutable API Audit Trail | `internal/api/middleware/audit.go`, `GET /api/v1/audit` | ✅ | Enhanced (SIEM export) | Integrate into SIEM, search for anomalies, archive long-term |
|
||||
| | Expiration Threshold Alerting | Configurable per-policy (default 30/14/7/0 days) | ✅ | ✅ | Configure thresholds, integrate notifications |
|
||||
| | Status Auto-Transitions | Active → Expiring (30d) → Expired (0d) | ✅ | ✅ | Monitor status changes in audit trail |
|
||||
| | Notification Routing | Email, Slack, Teams, PagerDuty, OpsGenie | ✅ | ✅ | Configure notifiers, on-call integration |
|
||||
| | Deployment Rollback | Redeploy previous cert version via GUI | ✅ | ✅ | Audit rollback decisions |
|
||||
| **CC7.3** Incident Response | Revocation API (RFC 5280 reasons) | `POST /api/v1/certificates/{id}/revoke` | ✅ | Enhanced (bulk revocation) | Establish incident response policy |
|
||||
| | CRL Endpoint (JSON + DER) | `GET /api/v1/crl`, `GET /api/v1/crl/{issuer_id}` | ✅ | ✅ | Ensure CRL/OCSP accessible to all clients |
|
||||
| | OCSP Responder | `GET /api/v1/ocsp/{issuer_id}/{serial}` | ✅ | ✅ | Test revocation in staging |
|
||||
| | Revocation Notifications | Email, webhook, Slack/Teams on revocation | ✅ | ✅ | Integrate into on-call, document justification separately |
|
||||
| | Short-Lived Cert Exemption | TTL < 1h skip CRL/OCSP | ✅ | ✅ | Configure profiles appropriately |
|
||||
| **CC7.4** Risk Mitigation | Renewal Job Tracking | Job state machine (Pending → Running → Completed/Failed) | ✅ | ✅ | Monitor renewal success rate |
|
||||
| | Agent Health Monitoring | Health check loop (ping every 2m, mark unhealthy after 3 misses) | ✅ | ✅ | Alert on unhealthy agents, investigate |
|
||||
| | Job Cancellation | `POST /api/v1/jobs/{id}/cancel` | ✅ | ✅ | Test in staging |
|
||||
| | Interactive Approval | AwaitingApproval state, `POST /api/v1/jobs/{id}/approve\|reject` | ✅ | ✅ | Define approval policy, audit decisions |
|
||||
| | Certificate Discovery | Agents scan directories, triage (claim/dismiss) | ✅ | ✅ | Review discovered certs regularly |
|
||||
| **A1.1/A1.2** Availability and Recovery | Health Probes (Docker, Kubernetes) | `/health` and `/ready` endpoints | ✅ | ✅ | Use in container orchestration |
|
||||
| | Idempotent Migrations | `IF NOT EXISTS`, `ON CONFLICT ... DO NOTHING` | ✅ | ✅ | Test migration replay in staging |
|
||||
| | Agent Panic Recovery | Panic recovery in job loops | ✅ | ✅ | Monitor agent crashes in logs |
|
||||
| | Exponential Backoff | Agent heartbeat/work poll backoff (1s → 5m) | ✅ | ✅ | Monitor for control plane downtime |
|
||||
| | PostgreSQL Connection Pooling | MaxOpenConns=25, MaxIdleConns=5 (configurable) | ✅ | ✅ | Monitor connection usage |
|
||||
| **CC8.1** Change Control | Certificate Profiles | CRUD API + GUI, profile changes audited | ✅ | ✅ | Formal change control, test in staging |
|
||||
| | Policy Engine + Violations | CRUD API + GUI, policy changes audited | ✅ | ✅ | Document justification, implement approval workflow |
|
||||
| | Target Registration | CRUD API + GUI, changes audited | ✅ | ✅ | Confirm deletions, version control config |
|
||||
| | Immutable Audit Trail | Append-only `audit_events` table | ✅ | ✅ | Encrypt at rest, archive long-term, no manual edits |
|
||||
| | GitHub Actions CI | Unit tests, vet, coverage gates, build checks | ✅ | ✅ | Review PRs before merge, maintain test quality |
|
||||
|
||||
---
|
||||
|
||||
## What Requires Operator Action
|
||||
|
||||
**certctl is a tool, not a complete compliance solution.** Your organization must handle:
|
||||
|
||||
1. **Physical Security** — Protect the infrastructure (servers, network) running certctl. Certctl can't control who has physical access to your datacenter.
|
||||
|
||||
2. **Personnel Background Checks** — Before granting anyone API key access, conduct background checks per your policy. Certctl records *who* accessed *what*, but doesn't verify that people are trustworthy.
|
||||
|
||||
3. **Formal Incident Response Plan** — Certctl provides incident detection (anomalies in audit trail) and tools for response (revocation, rollback), but you must define *when* to use them and *who* decides.
|
||||
|
||||
4. **Access Review and Removal** — Certctl stores ownership, teams, and API keys. You must:
|
||||
- Regularly review who has access (quarterly or semi-annually)
|
||||
- Immediately revoke API keys for departing employees
|
||||
- Audit that removed access is actually removed (test that old keys fail)
|
||||
|
||||
5. **Log Retention and Archival** — Certctl logs to stdout (Docker) and stores audit events in PostgreSQL. You must:
|
||||
- Ship logs to a long-term archive (SIEM, S3, or equivalent)
|
||||
- Define retention policy (often 1-7 years per industry regulation)
|
||||
- Encrypt archived logs
|
||||
- Test that you can retrieve logs from archive (restoration drills)
|
||||
|
||||
6. **Encryption at Rest** — PostgreSQL data (including audit trail) is stored on disk. You must:
|
||||
- Enable transparent data encryption (TDE) on your database VM
|
||||
- Encrypt container persistent volumes (if using Kubernetes)
|
||||
- Encrypt database backups
|
||||
|
||||
7. **Network Segmentation** — Certctl API and database must be protected by network access controls. You must:
|
||||
- Firewall the control plane (only authorized services can connect)
|
||||
- Use VPN or private networks for agent-to-server communication
|
||||
- Isolate proxy agents (for F5, IIS, etc.) in the same network zone as their targets
|
||||
|
||||
8. **Capacity Planning** — Certctl's performance scales with your PostgreSQL. You must:
|
||||
- Estimate certificate inventory size (10k, 100k, 1M certs?)
|
||||
- Test Certctl with your expected scale in staging
|
||||
- Monitor disk usage, CPU, memory
|
||||
- Plan for growth (add PostgreSQL replicas, increase connection pool, etc.)
|
||||
|
||||
9. **Disaster Recovery** — Certctl data lives in PostgreSQL. You must:
|
||||
- Back up PostgreSQL regularly (daily or hourly, depending on RPO)
|
||||
- Test restore process in staging (broken backups discovered during incidents)
|
||||
- Have a runbook for failover to replica or recovery from backup
|
||||
- Document RTO/RPO targets (how long can cert management be down? how much data can you afford to lose?)
|
||||
|
||||
10. **Integration with Your IAM** — If using OIDC/SSO (V3), you must:
|
||||
- Configure your OIDC provider (Okta, Azure AD, Google)
|
||||
- Map user groups to Certctl roles (Admin, Operator, Viewer)
|
||||
- Manage MFA policy (enforce MFA if required)
|
||||
- Audit user provisioning/deprovisioning
|
||||
|
||||
11. **Documentation and Runbooks** — Certctl documents *what it does* (this guide), but you must document:
|
||||
- Your organization's certificate lifecycle policy (who requests, who approves, who deploys)
|
||||
- How to respond to specific incidents (cert compromise, CA compromise, agent down, renewal failed)
|
||||
- How to operate certctl (day-to-day tasks, escalation procedures)
|
||||
- Contact info for on-call teams
|
||||
|
||||
---
|
||||
|
||||
## V3 Enhancements
|
||||
|
||||
**certctl Pro (V3, paid edition) adds features that significantly strengthen SOC 2 evidence:**
|
||||
|
||||
- **OIDC / SSO Integration** — Integrate with Okta, Azure AD, Google to replace API keys with federated identity. Enables MFA enforcement and centralized access management. Auditors love federated identity (easier to remove access at source).
|
||||
|
||||
- **Role-Based Access Control (RBAC)** — Predefined roles (Admin: full access; Operator: issue/renew/revoke, no policy changes; Viewer: read-only) with profile-gated enforcement. Allows separation of duties (e.g., junior operator can't change global policy).
|
||||
|
||||
- **NATS Event Bus** — Real-time audit streaming to your SIEM. Hybrid model: HTTP for synchronous APIs, NATS for async events (cert.issued, cert.expiring, agent.heartbeat, job.completed). JetStream persistence for replay and durability.
|
||||
|
||||
- **SIEM Export** — Automated export of audit trail to Splunk, ELK, DataDog, etc. (webhooks, syslog, or pull-based APIs). Makes it easy for security teams to hunt for anomalies.
|
||||
|
||||
- **Advanced Search DSL** — `POST /api/v1/search` with tree-based filters (nested AND/OR, regex, field projection). Enables complex compliance queries (e.g., "all certs issued in the last 30 days by team X that are longer than 1 year").
|
||||
|
||||
- **Bulk Revocation** — Revoke all certs issued by a profile, owner, or agent in one operation. Critical for large-scale incidents (e.g., "a team's CA key was compromised, revoke all their certs").
|
||||
|
||||
- **Certificate Health Scores** — Composite risk scoring (e.g., "this cert has no short-lived TTL enforcement, extends past your policy max, and hasn't been renewed in 2 years" → health=30%). Helps prioritize remediation.
|
||||
|
||||
- **Compliance Scoring** — Audit readiness reporting per certificate (e.g., "compliance=95% — missing only a 3-year max-TTL constraint"). Exportable compliance report.
|
||||
|
||||
- **DigiCert Issuer Connector** — OV/EV certificate issuance for public-facing services (web servers, CDNs). Complements Local CA for internal use.
|
||||
|
||||
- **CT Log Monitoring** — Passive detection of unauthorized cert issuance. Monitors public CT logs for certs matching your domains and alerts if unexpected certs appear (e.g., attacker obtained a cert for your domain).
|
||||
|
||||
- **F5 BIG-IP Implementation** — Full target connector with iControl REST API. Agents can deploy certs to F5 load balancers.
|
||||
|
||||
- **IIS Implementation** — Dual-mode: agent-local PowerShell (default) for servers with agents, or proxy agent WinRM (agentless targets). Full Windows Server integration.
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
certctl provides a strong foundation for SOC 2 compliance with API key authentication, immutable audit logging, automated alerting, and revocation capabilities. However, SOC 2 audits require evidence across your entire infrastructure — certctl is one piece. Use this guide to map certctl features to your audit questionnaire, then work with your auditors to identify gaps that must be filled by your own organizational policies and controls.
|
||||
|
||||
For a deeper SOC 2 discussion or a mock audit against this guide, contact your certctl Pro support team.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Compliance Mapping Guides
|
||||
|
||||
certctl is a certificate lifecycle management tool, not a compliance product. It doesn't make you compliant — your organization, policies, and processes do that. What certctl provides is tooling that supports the technical controls auditors and evaluators look for when assessing certificate and key management practices.
|
||||
|
||||
These guides map certctl's features to three widely referenced compliance frameworks. They're designed for security engineers, IT auditors, and procurement teams evaluating certctl for environments with regulatory requirements.
|
||||
|
||||
## What's Covered
|
||||
|
||||
**[SOC 2 Type II](compliance-soc2.md)** — Maps certctl features to AICPA Trust Service Criteria. Covers logical access controls (CC6), system operations and monitoring (CC7), change management (CC8), and availability (A1). Most relevant for organizations undergoing SOC 2 audits where certificate management is in scope.
|
||||
|
||||
**[PCI-DSS 4.0](compliance-pci-dss.md)** — Maps certctl features to PCI Data Security Standard version 4.0 requirements. Covers data-in-transit protection (Req 4), cryptographic key management (Req 3), authentication (Req 8), audit logging (Req 10), secure development (Req 6), and access control (Req 7). Most relevant for organizations handling cardholder data where TLS certificates protect transmission channels.
|
||||
|
||||
**[NIST SP 800-57](compliance-nist.md)** — Maps certctl's key management practices to NIST Special Publication 800-57 Part 1 Rev 5 (2020). Covers key generation, storage, cryptoperiods, key state lifecycle, algorithm selection, key transport, and revocation. Most relevant for organizations aligning with US federal cryptographic guidance or using NIST as a key management baseline.
|
||||
|
||||
## What These Guides Are Not
|
||||
|
||||
These are mapping guides, not certification claims. certctl is not SOC 2 certified, PCI-DSS validated, or NIST-assessed. The guides document how certctl's technical implementation supports the controls these frameworks require — they do not replace your auditor's assessment, your organization's policies, or your security team's judgment.
|
||||
|
||||
The guides also clearly identify gaps where certctl's current implementation doesn't fully align with a framework's recommendations, features planned for future versions, and areas where operator action is required regardless of what certctl provides.
|
||||
|
||||
## How to Use These Guides
|
||||
|
||||
If you're evaluating certctl for a regulated environment, start with the framework your auditor cares about. Each guide includes an evidence summary table mapping specific compliance criteria to certctl features, API endpoints, and configuration — the kind of specifics your auditor will ask for.
|
||||
|
||||
If you're preparing for an audit and certctl is already deployed, use the "Operator Responsibilities" section of each guide to identify what your organization must manage beyond what certctl provides.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Framework | Primary Concern | Key certctl Features |
|
||||
|---|---|---|
|
||||
| SOC 2 Type II | Trust service criteria for SaaS/infrastructure | API audit trail, auth controls, monitoring, change management |
|
||||
| PCI-DSS 4.0 | Cardholder data protection | TLS lifecycle, key management, immutable logging, access control |
|
||||
| NIST SP 800-57 | Cryptographic key management | Agent-side keygen, key isolation, algorithm selection, revocation |
|
||||
|
||||
## certctl Pro (V3) Enhancements
|
||||
|
||||
Several compliance-relevant features are planned for certctl Pro:
|
||||
|
||||
- **OIDC/SSO** — Enterprise identity provider integration (SOC 2 CC6.1, PCI-DSS 8.3)
|
||||
- **RBAC** — Role-based access control with admin/operator/viewer roles (SOC 2 CC6.3, PCI-DSS 7.2)
|
||||
- **NATS Audit Streaming** — Real-time audit event streaming to SIEM systems (SOC 2 CC7.2, PCI-DSS 10.2)
|
||||
- **Bulk Revocation** — Fleet-wide incident response capability (NIST SP 800-57 Section 5.4)
|
||||
- **Health/Compliance Scoring** — Automated compliance posture assessment per certificate
|
||||
+6
-6
@@ -202,8 +202,8 @@ Each issuer handles revocation differently:
|
||||
|
||||
The following issuer connectors are planned for future milestones:
|
||||
|
||||
- **Vault PKI** — HashiCorp Vault's PKI secrets engine for organizations using Vault as their internal CA.
|
||||
- **DigiCert** — Commercial CA integration via DigiCert's REST API.
|
||||
- **Vault PKI** — HashiCorp Vault's PKI secrets engine for organizations using Vault as their internal CA (planned for V4.0+).
|
||||
- **DigiCert** — Commercial CA integration via DigiCert's REST API (planned for V3 paid release).
|
||||
|
||||
Note: ADCS (Active Directory Certificate Services) integration is handled via the **sub-CA mode** of the Local CA issuer, not as a separate connector. certctl operates as a subordinate CA with its signing certificate issued by ADCS, so all certctl-issued certs chain to the enterprise ADCS root. See the Local CA section above.
|
||||
|
||||
@@ -393,9 +393,9 @@ The combined PEM is built in this order: server certificate, intermediate/chain
|
||||
|
||||
Location: `internal/connector/target/haproxy/haproxy.go`
|
||||
|
||||
### Planned: F5 BIG-IP (Interface Only)
|
||||
### V3 (Paid): F5 BIG-IP (Interface Only)
|
||||
|
||||
The F5 BIG-IP target connector interface is built with the iControl REST flow mapped out, but the actual API calls are not yet implemented. F5 appliances can't run agents directly, so this connector uses the **proxy agent pattern**: a designated agent in the same network zone picks up F5 deployment jobs and calls the iControl REST API. The server assigns the work; the proxy agent executes it.
|
||||
The F5 BIG-IP target connector interface is built with the iControl REST flow mapped out, but the actual API calls are not yet implemented. F5 appliances can't run agents directly, so this connector uses the **proxy agent pattern**: a designated agent in the same network zone picks up F5 deployment jobs and calls the iControl REST API. The server assigns the work; the proxy agent executes it. Implementation is planned for the paid V3 release.
|
||||
|
||||
The planned flow is: authenticate via `POST /mgmt/shared/authn/login`, upload cert PEM via `POST /mgmt/tm/ltm/certificate`, update the SSL profile via `PATCH /mgmt/tm/ltm/profile/client-ssl/{profile}`, and validate deployment by checking profile status. Implementation is planned for a future release.
|
||||
|
||||
@@ -414,9 +414,9 @@ Note: F5 credentials are stored on the proxy agent, not on the control plane ser
|
||||
|
||||
Location: `internal/connector/target/f5/f5.go`
|
||||
|
||||
### Planned: IIS (Interface Only, Dual-Mode)
|
||||
### V3 (Paid): IIS (Interface Only, Dual-Mode)
|
||||
|
||||
The IIS target connector supports two deployment modes:
|
||||
The IIS target connector supports two deployment modes planned for the paid V3 release:
|
||||
|
||||
**Agent-local (recommended):** A Windows agent runs directly on the IIS server and deploys certificates using PowerShell — `Import-PfxCertificate` to install into the certificate store and `Set-WebBinding` to bind to the IIS site. This is the preferred approach: no remote access needed, no credential management, same pull-based model as NGINX/Apache/HAProxy.
|
||||
|
||||
|
||||
+254
-13
@@ -42,6 +42,109 @@ Each step corresponds to a real operation that certctl would perform in producti
|
||||
|
||||
---
|
||||
|
||||
## Alternative Issuers Reference
|
||||
|
||||
certctl ships with multiple issuer connectors. The demo uses the Local CA, but here's how to set up others:
|
||||
|
||||
### Sub-CA Mode (Local CA chained to enterprise root)
|
||||
|
||||
For enterprises with ADCS, root CAs, or intermediate CAs:
|
||||
|
||||
```bash
|
||||
# Place your CA certificate and key on the server
|
||||
export CERTCTL_CA_CERT_PATH="/etc/certctl/ca-cert.pem"
|
||||
export CERTCTL_CA_KEY_PATH="/etc/certctl/ca-key.pem"
|
||||
|
||||
# Restart the server. The Local CA connector loads the cert+key from disk
|
||||
# All issued certificates now chain to your enterprise root
|
||||
docker compose -f deploy/docker-compose.yml restart server
|
||||
```
|
||||
|
||||
The CA key can be RSA, ECDSA, or PKCS#8 format. The connector validates that the certificate has `IsCA=true` and `KeyUsageCertSign`.
|
||||
|
||||
### ACME with DNS-01 Challenges (Wildcard Certificates)
|
||||
|
||||
For Let's Encrypt or other ACME providers with wildcard support:
|
||||
|
||||
```bash
|
||||
# Configure ACME DNS-01 with a DNS provider script
|
||||
export CERTCTL_ACME_CHALLENGE_TYPE="dns-01"
|
||||
export CERTCTL_ACME_DNS_PRESENT_SCRIPT="/usr/local/bin/dns-present.sh"
|
||||
export CERTCTL_ACME_DNS_CLEANUP_SCRIPT="/usr/local/bin/dns-cleanup.sh"
|
||||
export CERTCTL_ACME_DNS_PROPAGATION_WAIT="10" # seconds to wait for DNS propagation
|
||||
|
||||
# Example dns-present.sh for Cloudflare:
|
||||
# #!/bin/bash
|
||||
# RECORD_NAME=$1
|
||||
# RECORD_VALUE=$2
|
||||
# curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
|
||||
# -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
|
||||
# -d "{\"type\":\"TXT\",\"name\":\"$RECORD_NAME\",\"content\":\"$RECORD_VALUE\"}"
|
||||
```
|
||||
|
||||
Then issue wildcard certificates:
|
||||
```bash
|
||||
curl -s -X POST $API/api/v1/certificates \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"id": "mc-wildcard-api",
|
||||
"name": "Wildcard API Certificate",
|
||||
"common_name": "*.api.example.com",
|
||||
"sans": ["*.api.example.com", "api.example.com"],
|
||||
"issuer_id": "iss-acme",
|
||||
"renewal_policy_id": "rp-default",
|
||||
"status": "Pending"
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
### step-ca (Smallstep Private CA)
|
||||
|
||||
For organizations running step-ca as their private CA:
|
||||
|
||||
```bash
|
||||
# Configure step-ca connector
|
||||
export CERTCTL_STEPCA_URL="https://ca.internal.example.com"
|
||||
export CERTCTL_STEPCA_FINGERPRINT="your-ca-fingerprint" # From `step ca bootstrap`
|
||||
export CERTCTL_STEPCA_PROVISIONER="certctl-admin" # Name of the JWK provisioner
|
||||
export CERTCTL_STEPCA_PROVISIONER_JWK="/etc/certctl/provisioner.json" # Path to JWK private key
|
||||
```
|
||||
|
||||
Then use step-ca as the issuer:
|
||||
```bash
|
||||
curl -s -X POST $API/api/v1/certificates \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"id": "mc-stepca-cert",
|
||||
"name": "Certificate from step-ca",
|
||||
"common_name": "service.internal.example.com",
|
||||
"issuer_id": "iss-stepca",
|
||||
"renewal_policy_id": "rp-default",
|
||||
"status": "Pending"
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
### OpenSSL / Custom CA (Script-based)
|
||||
|
||||
For custom signing workflows via shell scripts:
|
||||
|
||||
```bash
|
||||
# Configure OpenSSL connector with user-provided scripts
|
||||
export CERTCTL_OPENSSL_SIGN_SCRIPT="/usr/local/bin/custom-sign.sh"
|
||||
export CERTCTL_OPENSSL_REVOKE_SCRIPT="/usr/local/bin/custom-revoke.sh"
|
||||
export CERTCTL_OPENSSL_CRL_SCRIPT="/usr/local/bin/custom-crl.sh"
|
||||
export CERTCTL_OPENSSL_TIMEOUT_SECONDS="30"
|
||||
|
||||
# Example custom-sign.sh:
|
||||
# #!/bin/bash
|
||||
# CSR_PEM=$1
|
||||
# VALIDITY_DAYS=$2
|
||||
# # Do something custom with the CSR and return signed certificate
|
||||
# openssl ca -in <(echo "$CSR_PEM") -days $VALIDITY_DAYS -out /tmp/signed.pem
|
||||
# cat /tmp/signed.pem
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 1: Build the Organization Structure
|
||||
|
||||
### Create a new team
|
||||
@@ -101,12 +204,12 @@ You should see:
|
||||
{
|
||||
"id": "iss-local",
|
||||
"name": "Local Dev CA",
|
||||
"type": "GenericCA",
|
||||
"type": "local",
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
**How it works:** The issuer record was inserted during database seeding (`migrations/seed_demo.sql`). The `type` field (`GenericCA`) maps to a connector implementation. When the server starts, it registers connector instances in an `issuerRegistry` map keyed by issuer ID. When a certificate needs issuance, the service layer looks up the issuer ID in this registry to find the right connector.
|
||||
**How it works:** The issuer record was inserted during database seeding (`migrations/seed_demo.sql`). The `type` field (`local`) maps to a connector implementation. When the server starts, it registers connector instances in an `issuerRegistry` map keyed by issuer ID. When a certificate needs issuance, the service layer looks up the issuer ID in this registry to find the right connector.
|
||||
|
||||
**How the Local CA works internally:** The Local CA connector (`internal/connector/issuer/local/local.go`) generates a self-signed root CA certificate on first use using Go's `crypto/x509` package. The CA key pair lives in memory only — it's regenerated each time the server restarts, which means all certificates it issued become untrusted on restart (acceptable for dev/demo). When it receives an `IssuanceRequest` containing a CSR (Certificate Signing Request), it:
|
||||
|
||||
@@ -355,29 +458,47 @@ curl -s -X POST "$API/api/v1/agents/agent-nginx-prod/jobs/JOB_ID/status" \
|
||||
|
||||
---
|
||||
|
||||
## Part 6: View the Audit Trail
|
||||
## Part 6: View the Audit Trail (Immutable API Audit Log)
|
||||
|
||||
Every action you've taken has been recorded. Check the audit trail:
|
||||
Every API call and state change is recorded in an immutable, append-only audit trail. Check the recent audit events:
|
||||
|
||||
```bash
|
||||
curl -s $API/api/v1/audit | jq '.data[0:5]'
|
||||
# List recent audit events
|
||||
curl -s $API/api/v1/audit | jq '.data[0:10]'
|
||||
|
||||
# Filter by action (e.g., all certificate creations)
|
||||
curl -s "$API/api/v1/audit?action=certificate_created" | jq '.data[] | {actor, action, resource_id, timestamp}'
|
||||
|
||||
# Filter by resource (e.g., all actions on mc-demo-api)
|
||||
curl -s "$API/api/v1/audit?resource_id=mc-demo-api" | jq '.data[] | {actor, action, timestamp}'
|
||||
|
||||
# Filter by actor (e.g., all actions by a specific owner)
|
||||
curl -s "$API/api/v1/audit?actor=o-demo-user" | jq '.data[] | {action, resource_type, timestamp}'
|
||||
|
||||
# Time-range filter (e.g., last hour)
|
||||
curl -s "$API/api/v1/audit?created_after=2026-03-24T09:00:00Z" | jq '.data | length'
|
||||
|
||||
# Export audit trail (CSV format via GUI)
|
||||
# Available on the Audit page with applied filters
|
||||
```
|
||||
|
||||
**How it works:** The `audit_events` table is append-only — there is no `UPDATE` or `DELETE` in the `AuditRepository` interface. This is a deliberate design decision for compliance. Every service method that mutates state calls `AuditService.Create()` with:
|
||||
**How it works:** The `audit_events` table is append-only — there is no `UPDATE` or `DELETE` in the `AuditRepository` interface. Every API call (including this audit query) is recorded by the API audit middleware with:
|
||||
|
||||
| Field | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `actor` | The authenticated user or system component | `"o-demo-user"`, `"system"`, `"agent-prod-01"` |
|
||||
| `actor` | The authenticated user extracted from auth context | `"o-demo-user"`, `"system"`, `"agent-prod-01"`, `"anonymous"` |
|
||||
| `actor_type` | Category of the actor | `"User"`, `"System"`, `"Agent"` |
|
||||
| `action` | What happened | `"certificate_created"`, `"renewal_triggered"`, `"deployment_completed"` |
|
||||
| `resource_type` | What was affected | `"certificate"`, `"team"`, `"agent"` |
|
||||
| `action` | What happened | `"certificate_created"`, `"renewal_triggered"`, `"deployment_completed"`, `"api_call"` |
|
||||
| `resource_type` | What was affected | `"certificate"`, `"team"`, `"agent"`, `"audit"` |
|
||||
| `resource_id` | Specific resource | `"mc-demo-api"` |
|
||||
| `details` | Arbitrary JSON context | `{"environment": "staging", "issuer": "iss-local"}` |
|
||||
| `details` | Arbitrary JSON context | `{"environment": "staging", "issuer": "iss-local", "body_hash": "abc123..." }` |
|
||||
| `timestamp` | When it happened (server clock) | `"2026-03-14T10:30:00Z"` |
|
||||
|
||||
**Why immutable audit:** Compliance frameworks (SOC 2 Type II, PCI-DSS, ISO 27001) require tamper-evident audit logs. By making the repository interface append-only, even a compromised API server can't retroactively delete or modify audit records. In a production deployment, you'd also stream these to an external SIEM (Splunk, Datadog) for additional protection.
|
||||
The audit middleware (M19) records every HTTP request: method, path, status code, actor, request body SHA-256 hash, and latency. This creates a complete API audit trail without blocking responses (logging happens asynchronously).
|
||||
|
||||
**Check the dashboard.** The "Audit" view shows the full timeline of all actions across the system.
|
||||
**Why immutable audit:** Compliance frameworks (SOC 2 Type II, PCI-DSS, ISO 27001) require tamper-evident audit logs. By making the repository interface append-only and recording API calls, even a compromised API server can't retroactively delete or modify audit records. In a production deployment, you'd also stream these to an external SIEM (Splunk, Datadog) for additional protection.
|
||||
|
||||
**Check the dashboard.** The "Audit" view shows the full timeline of all actions across the system with filtering and CSV/JSON export.
|
||||
|
||||
---
|
||||
|
||||
@@ -410,6 +531,36 @@ flowchart TD
|
||||
|
||||
**Why graceful notifier fallback:** In demo mode, no SMTP server or webhook endpoint is configured. Rather than spamming error logs with "notifier not found" every 60 seconds (which was the original behavior — we fixed this), the service marks notifications as "sent" when no notifier is registered for the channel. This keeps the notification records visible in the dashboard without requiring external infrastructure.
|
||||
|
||||
### Configuring Notifier Connectors
|
||||
|
||||
In production, enable notifiers by setting environment variables:
|
||||
|
||||
**Slack:**
|
||||
```bash
|
||||
export CERTCTL_SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
|
||||
export CERTCTL_SLACK_CHANNEL="cert-alerts" # Optional, overrides channel in webhook
|
||||
export CERTCTL_SLACK_USERNAME="CertCTL" # Optional, defaults to "CertCTL"
|
||||
```
|
||||
|
||||
**Microsoft Teams:**
|
||||
```bash
|
||||
export CERTCTL_TEAMS_WEBHOOK_URL="https://outlook.webhook.office.com/webhookb2/..."
|
||||
```
|
||||
|
||||
**PagerDuty:**
|
||||
```bash
|
||||
export CERTCTL_PAGERDUTY_ROUTING_KEY="your-routing-key"
|
||||
export CERTCTL_PAGERDUTY_SEVERITY="warning" # Or: critical, error, info
|
||||
```
|
||||
|
||||
**OpsGenie:**
|
||||
```bash
|
||||
export CERTCTL_OPSGENIE_API_KEY="your-api-key"
|
||||
export CERTCTL_OPSGENIE_PRIORITY="P3" # Or: P1, P2, P4, P5
|
||||
```
|
||||
|
||||
When certificates expire, renewal fails, or policies are violated, certctl sends notifications via the configured channels. Each notifier connector implements the `Notifier` interface: `Send(ctx context.Context, recipient, subject, body string) error`. The notification processor handles retries and failure recording.
|
||||
|
||||
---
|
||||
|
||||
## Part 8: Create a Second Certificate and Compare
|
||||
@@ -675,7 +826,97 @@ curl -s "$API/api/v1/certificates/mc-demo-api/deployments" | jq .
|
||||
|
||||
---
|
||||
|
||||
## Part 14: Certificate Discovery (M18b)
|
||||
## Part 14: CLI Tool (M16b)
|
||||
|
||||
certctl includes a standalone CLI tool for command-line users:
|
||||
|
||||
```bash
|
||||
# Build the CLI
|
||||
cd cmd/cli && go build -o certctl-cli .
|
||||
|
||||
# Export credentials
|
||||
export CERTCTL_SERVER_URL="http://localhost:8443"
|
||||
export CERTCTL_API_KEY="test-key-123"
|
||||
|
||||
# List certificates (JSON or table format)
|
||||
./certctl-cli list-certs --format table
|
||||
|
||||
# Get certificate details
|
||||
./certctl-cli get-cert mc-demo-api
|
||||
|
||||
# Trigger renewal
|
||||
./certctl-cli renew-cert mc-demo-api
|
||||
|
||||
# Revoke a certificate with RFC 5280 reason
|
||||
./certctl-cli revoke-cert mc-demo-payments --reason keyCompromise
|
||||
|
||||
# List agents
|
||||
./certctl-cli list-agents
|
||||
|
||||
# List pending jobs
|
||||
./certctl-cli list-jobs
|
||||
|
||||
# Check system health
|
||||
./certctl-cli health
|
||||
|
||||
# Export metrics
|
||||
./certctl-cli metrics --format json
|
||||
|
||||
# Bulk import certificates from a PEM file
|
||||
./certctl-cli import /path/to/certificates.pem
|
||||
```
|
||||
|
||||
**How it works:** The CLI tool is a self-contained Go binary with zero external dependencies (just the stdlib: flag, net/http, encoding/json, text/tabwriter). It reads credentials from environment variables or command-line flags, calls the REST API endpoints, and formats output as JSON or ASCII tables. This makes it perfect for scripts, CI/CD pipelines, and automation workflows.
|
||||
|
||||
---
|
||||
|
||||
## Part 15: MCP Server for AI Integration (M18a)
|
||||
|
||||
certctl exposes all 76 API endpoints as tools via the Model Context Protocol (MCP), enabling seamless integration with Claude, Cursor, and other AI assistants:
|
||||
|
||||
```bash
|
||||
# Build the MCP server
|
||||
cd cmd/mcp-server && go build -o mcp-server .
|
||||
|
||||
# Export credentials
|
||||
export CERTCTL_SERVER_URL="http://localhost:8443"
|
||||
export CERTCTL_API_KEY="test-key-123"
|
||||
|
||||
# Start the MCP server (listens on stdin/stdout)
|
||||
./mcp-server
|
||||
```
|
||||
|
||||
**How it works:** The MCP server uses the official Model Context Protocol Go SDK to expose stateless HTTP proxies to all 76 API endpoints. Each MCP tool corresponds to one or more REST endpoints and includes:
|
||||
|
||||
- **Input schema** — typed arguments with JSON schema hints for LLM-friendly introspection
|
||||
- **Binary support** — handles DER-encoded CRL and OCSP responses without mangling
|
||||
- **Error translation** — converts HTTP errors to user-readable messages
|
||||
|
||||
**Example usage from Claude:**
|
||||
|
||||
```
|
||||
User: What certificates are expiring in the next 30 days?
|
||||
|
||||
Claude uses the MCP tools to:
|
||||
1. Call tools.listCertificates with filters: {status: "Expiring"}
|
||||
2. Parse the response
|
||||
3. Display: "mc-api-prod expires in 12 days. mc-cdn-prod expires in 8 days..."
|
||||
|
||||
User: Revoke mc-payments due to key compromise
|
||||
|
||||
Claude uses the MCP tools to:
|
||||
1. Call tools.revokeCertificate with id="mc-payments" reason="keyCompromise"
|
||||
2. Return the audit trail entry showing revocation recorded
|
||||
```
|
||||
|
||||
The MCP server is perfect for:
|
||||
- Compliance audits — "Show me all certificates with PCI tags and their revocation status"
|
||||
- Incident response — "Revoke all certificates issued by the OpenSSL CA issued before 2026-01-01"
|
||||
- Operational queries — "What's the renewal success rate over the last 30 days?"
|
||||
|
||||
---
|
||||
|
||||
## Part 16: Certificate Discovery (M18b)
|
||||
|
||||
Agents can automatically discover existing certificates already deployed in your infrastructure. This is useful for building a baseline inventory before you start managing everything with certctl.
|
||||
|
||||
|
||||
+91
-9
@@ -72,9 +72,9 @@ Click any certificate, then scroll to the deployment timeline. A visual 4-step t
|
||||
**11. "What about certificates already running in production?"**
|
||||
Enable discovery on agents by setting `CERTCTL_DISCOVERY_DIRS` to directories containing certificates (e.g., `/etc/nginx/certs`). Agents scan on startup and every 6 hours, report findings to the control plane. Click "Discovered Certificates" to see what agents found — claim unmanaged certs to bring them under certctl's management, or dismiss them.
|
||||
|
||||
## API Walkthrough
|
||||
## REST API Walkthrough
|
||||
|
||||
The dashboard is backed by a real REST API. Try these while the demo is running:
|
||||
The dashboard is backed by a real REST API (84 endpoints). Try these while the demo is running:
|
||||
|
||||
```bash
|
||||
# List all certificates
|
||||
@@ -83,13 +83,22 @@ curl -s http://localhost:8443/api/v1/certificates | jq .
|
||||
# Get expiring certs
|
||||
curl -s "http://localhost:8443/api/v1/certificates?status=expiring" | jq .
|
||||
|
||||
# Advanced query: sort by expiration, sparse fields, cursor pagination
|
||||
curl -s "http://localhost:8443/api/v1/certificates?sort=-expires_at&fields=id,common_name,expires_at" | jq .
|
||||
|
||||
# Time-range filter: certs expiring before June 2026
|
||||
curl -s "http://localhost:8443/api/v1/certificates?expires_before=2026-06-01T00:00:00Z" | jq .
|
||||
|
||||
# Get a specific certificate
|
||||
curl -s http://localhost:8443/api/v1/certificates/mc-api-prod | jq .
|
||||
|
||||
# Get deployment targets for a certificate
|
||||
curl -s http://localhost:8443/api/v1/certificates/mc-api-prod/deployments | jq .
|
||||
|
||||
# List agents
|
||||
curl -s http://localhost:8443/api/v1/agents | jq .
|
||||
|
||||
# View audit trail
|
||||
# View audit trail (immutable API audit log of all actions)
|
||||
curl -s http://localhost:8443/api/v1/audit | jq .
|
||||
|
||||
# View policy violations (replace POLICY_ID with a real policy ID, e.g. pr-require-owner)
|
||||
@@ -98,10 +107,12 @@ curl -s http://localhost:8443/api/v1/policies/pr-require-owner/violations | jq .
|
||||
# Check system health
|
||||
curl -s http://localhost:8443/health | jq .
|
||||
|
||||
# Dashboard stats
|
||||
# Dashboard stats and metrics
|
||||
curl -s http://localhost:8443/api/v1/stats/summary | jq .
|
||||
|
||||
# System metrics (cert totals, agent counts, job stats)
|
||||
curl -s http://localhost:8443/api/v1/stats/certificates-by-status | jq .
|
||||
curl -s http://localhost:8443/api/v1/stats/expiration-timeline | jq .
|
||||
curl -s http://localhost:8443/api/v1/stats/job-trends | jq .
|
||||
curl -s http://localhost:8443/api/v1/stats/issuance-rate | jq .
|
||||
curl -s http://localhost:8443/api/v1/metrics | jq .
|
||||
|
||||
# Certificate profiles
|
||||
@@ -115,6 +126,10 @@ curl -s -X POST http://localhost:8443/api/v1/certificates/mc-api-prod/revoke \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"reason": "superseded"}' | jq .
|
||||
|
||||
# CRL and OCSP endpoints
|
||||
curl -s http://localhost:8443/api/v1/crl | jq .
|
||||
curl -s http://localhost:8443/api/v1/crl/iss-local -o /tmp/crl.der
|
||||
|
||||
# List discovered certificates
|
||||
curl -s http://localhost:8443/api/v1/discovered-certificates | jq .
|
||||
|
||||
@@ -122,7 +137,72 @@ curl -s http://localhost:8443/api/v1/discovered-certificates | jq .
|
||||
curl -s http://localhost:8443/api/v1/discovery-summary | jq .
|
||||
```
|
||||
|
||||
## Demo Without Docker
|
||||
## CLI Tool
|
||||
|
||||
certctl ships with a command-line tool (`certctl-cli`) for terminal users:
|
||||
|
||||
```bash
|
||||
# Build the CLI
|
||||
cd cmd/cli && go build -o certctl-cli .
|
||||
|
||||
# Set credentials
|
||||
export CERTCTL_SERVER_URL="http://localhost:8443"
|
||||
export CERTCTL_API_KEY="test-key-123"
|
||||
|
||||
# List certificates (JSON or table format)
|
||||
./certctl-cli list-certs --format json
|
||||
./certctl-cli list-certs --format table
|
||||
|
||||
# Get certificate details
|
||||
./certctl-cli get-cert mc-api-prod
|
||||
|
||||
# Trigger renewal
|
||||
./certctl-cli renew-cert mc-api-prod
|
||||
|
||||
# Revoke a certificate (with RFC 5280 reason)
|
||||
./certctl-cli revoke-cert mc-api-prod --reason keyCompromise
|
||||
|
||||
# List agents
|
||||
./certctl-cli list-agents
|
||||
|
||||
# List pending jobs
|
||||
./certctl-cli list-jobs
|
||||
|
||||
# Bulk import certificates from PEM files
|
||||
./certctl-cli import /path/to/certs.pem
|
||||
|
||||
# Check health and metrics
|
||||
./certctl-cli health
|
||||
./certctl-cli metrics
|
||||
```
|
||||
|
||||
## MCP Server for AI Integration
|
||||
|
||||
certctl exposes its 76 API endpoints as tools via the Model Context Protocol (MCP), enabling integration with Claude, Cursor, and other AI assistants:
|
||||
|
||||
```bash
|
||||
# Build and run the MCP server
|
||||
cd cmd/mcp-server && go build -o mcp-server .
|
||||
|
||||
export CERTCTL_SERVER_URL="http://localhost:8443"
|
||||
export CERTCTL_API_KEY="test-key-123"
|
||||
|
||||
./mcp-server
|
||||
```
|
||||
|
||||
The MCP server:
|
||||
- Exposes all 76 API endpoints as MCP tools with typed schemas
|
||||
- Handles binary responses (DER CRL, OCSP responses)
|
||||
- Uses stdio transport for Claude/Cursor/OpenClaw integration
|
||||
- Zero external dependencies — pure Go with official MCP SDK
|
||||
|
||||
You can then ask Claude questions like:
|
||||
- "What certificates are expiring in the next 30 days?"
|
||||
- "Revoke the payments certificate due to key compromise"
|
||||
- "Show me the audit trail for the last 10 actions"
|
||||
- "List all certificates with PCI compliance tags"
|
||||
|
||||
## Dashboard Demo Mode
|
||||
|
||||
The dashboard includes a **Demo Mode** that works without any backend. Build and serve the frontend with Vite:
|
||||
|
||||
@@ -152,12 +232,14 @@ If you're demoing to a team or customer, here's a suggested flow:
|
||||
3. **Click into auth-production** — "Here's the full lifecycle: who owns it, where it's deployed, deployment timeline, when it was last renewed"
|
||||
4. **Show revocation** — "If a key is compromised, one click revokes the cert with an RFC 5280 reason code. CRL and OCSP are served automatically"
|
||||
5. **Show the failed VPN cert** — "The system tried 3 times, then alerted the team via Slack, Teams, PagerDuty, or OpsGenie"
|
||||
6. **Show agents and fleet overview** — "Agents run on your infrastructure, handle key generation locally. Fleet view shows OS, architecture, and version distribution"
|
||||
6. **Show agents and fleet overview** — "Agents run on your infrastructure, handle key generation locally (ECDSA P-256). Fleet view shows OS, architecture, and version distribution"
|
||||
7. **Show profiles** — "Certificate profiles enforce crypto constraints — key types, max TTL, compliance requirements"
|
||||
8. **Show policies** — "Guardrails prevent teams from going outside approved scope"
|
||||
9. **Show bulk operations** — "Select multiple certs, trigger renewal or revoke in bulk with progress tracking"
|
||||
10. **Show certificate discovery** — "Agents scan your infrastructure for existing certificates you're not managing yet. We automatically deduplicate by fingerprint, show you what we found, and let you claim them or dismiss them"
|
||||
11. **Show the API** — "Everything you see here is API-first. We also have a CLI tool and an MCP server for AI assistant integration"
|
||||
11. **Show the immutable audit trail** — "Every action in the system is recorded: who did it, what they did, when, what changed. Export to CSV/JSON for compliance"
|
||||
12. **Show advanced query features** — "Sort by any field, filter by date range, paginate efficiently with cursor-based pagination, select just the fields you need"
|
||||
13. **Show the CLI and MCP server** — "Terminal users get `certctl-cli` with 10 subcommands. AI assistants get MCP integration with 76 tools. Everything is API-first"
|
||||
|
||||
The whole walkthrough takes 5-10 minutes.
|
||||
|
||||
|
||||
+28
-8
@@ -229,13 +229,13 @@ Named enrollment profiles defining certificate issuance constraints.
|
||||
|
||||
### F5 BIG-IP (Stub)
|
||||
- **Protocol** — iControl REST API via proxy agent
|
||||
- **Status** — Interface only in V2; implementation planned for V2 or V3
|
||||
- **Status** — Interface only in V2; implementation in V3 (paid)
|
||||
- **Deployment Model** — Proxy agent + BIG-IP API client in same network zone
|
||||
- **Authentication** — iControl credentials stored in target config
|
||||
|
||||
### IIS (Stub)
|
||||
- **Dual-Mode Architecture** — Agent-local PowerShell (primary) or proxy agent WinRM (agentless)
|
||||
- **Status** — Interface only in V2; implementation planned for V2 or V3
|
||||
- **Status** — Interface only in V2; implementation in V3 (paid)
|
||||
- **Deployment Model** — Agent runs PowerShell cmdlets locally or proxy agent invokes WinRM
|
||||
- **Binding** — Bind certificate to IIS site by hostname
|
||||
|
||||
@@ -660,7 +660,7 @@ The web dashboard is the primary operational interface for certctl. Built with *
|
||||
|
||||
### OpenAPI 3.1 Specification
|
||||
- **File** — `api/openapi.yaml`
|
||||
- **Scope** — 78 operations (76 API endpoints + /health + /ready)
|
||||
- **Scope** — 85 operations (84 API + /health)
|
||||
- **Schemas** — Complete domain models with examples
|
||||
- **Enums** — Job types, states, policy rule types, notification types
|
||||
- **Pagination** — Standard envelope (data, total, page, per_page)
|
||||
@@ -858,6 +858,7 @@ The web dashboard is the primary operational interface for certctl. Built with *
|
||||
| `CERTCTL_AGENT_NAME` | string | (generated) | Agent display name |
|
||||
| `CERTCTL_KEY_DIR` | string | /var/lib/certctl/keys | Local private key storage directory |
|
||||
| `CERTCTL_AGENT_ID` | string | (env or generated) | Agent unique ID (mc-xxx prefix) |
|
||||
| `CERTCTL_DISCOVERY_DIRS` | string | (empty) | Comma-separated directories for cert discovery |
|
||||
|
||||
#### MCP Server
|
||||
| Variable | Type | Default | Purpose |
|
||||
@@ -867,6 +868,21 @@ The web dashboard is the primary operational interface for certctl. Built with *
|
||||
|
||||
---
|
||||
|
||||
## Compliance Mapping Documentation
|
||||
|
||||
Mapping guides that document how certctl's features align with compliance frameworks. These are not certifications — they help auditors and evaluators assess how certctl supports their organization's compliance posture.
|
||||
|
||||
| Guide | Framework | Key Sections |
|
||||
|-------|-----------|-------------|
|
||||
| [SOC 2 Type II](compliance-soc2.md) | AICPA Trust Service Criteria | CC6 (logical access), CC7 (system operations), CC8 (change management), A1 (availability) |
|
||||
| [PCI-DSS 4.0](compliance-pci-dss.md) | Payment Card Industry DSS | Req 3 (key management), Req 4 (data in transit), Req 8 (auth), Req 10 (audit logging) |
|
||||
| [NIST SP 800-57](compliance-nist.md) | Key Management Guidelines | Key generation, storage, cryptoperiods, key states, algorithms, revocation |
|
||||
| [Overview](compliance.md) | All three frameworks | Framework comparison, quick reference, V3 enhancement notes |
|
||||
|
||||
Each guide includes an evidence summary table mapping specific criteria to certctl API endpoints, configuration, and database evidence.
|
||||
|
||||
---
|
||||
|
||||
## Feature Matrix: V2 Free vs. V3 Paid (Roadmap)
|
||||
|
||||
| Feature | V2 | V3 (Paid) | Status |
|
||||
@@ -882,13 +898,17 @@ The web dashboard is the primary operational interface for certctl. Built with *
|
||||
| Revocation (RFC 5280, CRL, OCSP) | ✓ | ✓ | Shipped |
|
||||
| Dashboard + 19 pages | ✓ | ✓ | Shipped |
|
||||
| Observability (charts, metrics, stats) | ✓ | ✓ | Shipped |
|
||||
| REST API (77 endpoints) | ✓ | ✓ | Shipped |
|
||||
| REST API (84 endpoints) | ✓ | ✓ | Shipped |
|
||||
| MCP server (76 tools) | ✓ | ✓ | Shipped v2.1 |
|
||||
| CLI tool (10 subcommands) | ✓ | ✓ | Shipped |
|
||||
| Compliance mapping docs (SOC 2, PCI-DSS, NIST) | ✓ | ✓ | Shipped |
|
||||
| Filesystem cert discovery (M18b) | ✓ | ✓ | Shipped |
|
||||
| Enhanced query API (sort, filter, cursor, fields) | ✓ | ✓ | Shipped |
|
||||
| Immutable API audit log | ✓ | ✓ | Shipped |
|
||||
| **OIDC/SSO auth** | ✗ | ✓ | Planned V3 |
|
||||
| **RBAC (role-based access control)** | ✗ | ✓ | Planned V3 |
|
||||
| **F5 BIG-IP implementation** | Stub | ✓ | Stub in V2 |
|
||||
| **IIS implementation** | Stub | ✓ | Stub in V2 |
|
||||
| **F5 BIG-IP implementation** | Stub | ✓ | Planned V3 |
|
||||
| **IIS implementation** | Stub | ✓ | Planned V3 |
|
||||
| **NATS event bus** | ✗ | ✓ | Planned V3 |
|
||||
| **Real-time updates (SSE/WebSocket)** | ✗ | ✓ | Planned V3 |
|
||||
| **Advanced search DSL** | ✗ | ✓ | Planned V3 |
|
||||
@@ -916,9 +936,9 @@ The web dashboard is the primary operational interface for certctl. Built with *
|
||||
| **Certificate States** | 8 (Pending, Active, Expiring, Expired, RenewalInProgress, Failed, Revoked, Archived) |
|
||||
| **Revocation Reason Codes** | 8 (RFC 5280 compliant) |
|
||||
| **Discovery Statuses** | 3 (Unmanaged, Managed, Dismissed) |
|
||||
| **MCP Tools** | 83 (17 resource domains) |
|
||||
| **MCP Tools** | 76 (16 resource domains) |
|
||||
| **CLI Subcommands** | 10 |
|
||||
| **Database Tables** | 20+ |
|
||||
| **Test Suite** | 881+ tests |
|
||||
| **Test Suite** | 860+ tests (Go backend + frontend) |
|
||||
| **Environment Variables** | 41+ configuration options |
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# OpenAPI Specification Guide
|
||||
|
||||
certctl ships with a complete OpenAPI 3.1 specification at `api/openapi.yaml`. This spec documents all 78 API operations (76 resource endpoints + health + readiness), every request/response schema, pagination conventions, authentication requirements, and error formats. It's the single source of truth for the REST API.
|
||||
certctl ships with a complete OpenAPI 3.1 specification at `api/openapi.yaml`. This spec documents all 78 API operations currently specified, every request/response schema, pagination conventions, authentication requirements, and error formats. It's the single source of truth for the documented REST API. (Note: The spec will be updated to include 7 additional certificate discovery endpoints from M18b.)
|
||||
|
||||
This guide covers how to use the spec for API exploration, client SDK generation, and integration testing.
|
||||
|
||||
@@ -14,7 +14,7 @@ cat api/openapi.yaml
|
||||
|
||||
# Count operations
|
||||
grep "operationId:" api/openapi.yaml | wc -l
|
||||
# 78
|
||||
# 78 (includes health + ready, 7 discovery endpoints pending spec update)
|
||||
```
|
||||
|
||||
## Viewing with Swagger UI
|
||||
@@ -149,7 +149,7 @@ npx @apidevtools/swagger-cli validate api/openapi.yaml
|
||||
Import the spec directly into Postman:
|
||||
|
||||
1. Open Postman → Import → File → select `api/openapi.yaml`
|
||||
2. Postman creates a collection with all 78 operations organized by tag
|
||||
2. Postman creates a collection with all 78 documented operations organized by tag
|
||||
3. Set the `baseUrl` variable to `http://localhost:8443`
|
||||
4. Add an `Authorization: Bearer your-api-key` header to the collection
|
||||
|
||||
|
||||
Reference in New Issue
Block a user