diff --git a/README.md b/README.md index 8e935ce..2e4848e 100644 --- a/README.md +++ b/README.md @@ -278,6 +278,8 @@ GET /ready Readiness check |--------|--------|------| | Local CA (self-signed) | Implemented | `GenericCA` | | ACME v2 (Let's Encrypt, Sectigo) | Implemented (HTTP-01) | `ACME` | +| step-ca | Planned (V2) | — | +| OpenSSL / Custom CA | Planned (V2) | — | | Vault PKI | Planned | — | | DigiCert | Planned | — | @@ -285,8 +287,8 @@ GET /ready Readiness check | Target | Status | Type | |--------|--------|------| | NGINX | Implemented | `NGINX` | -| F5 BIG-IP | Implemented | `F5` | -| Microsoft IIS | Implemented | `IIS` | +| F5 BIG-IP | Interface only (V2) | `F5` | +| Microsoft IIS | Interface only (V2) | `IIS` | | Kubernetes Secrets | Planned | — | ### Notifiers @@ -349,7 +351,7 @@ All nine development milestones (M1–M9) are complete. The backend covers the f Remaining before the v1.0.0 tag: dashboard screenshots in README, tagged Docker images published, final error-handling audit to confirm no panics or unhandled error paths. ### V2: Operational Maturity -- **V2.0: Operational Workflows** — ACME DNS-01 challenges (wildcard certs, custom validation scripts), renewal approval UI, bulk cert operations, deployment timeline, real-time updates (SSE/WebSocket), target config wizard +- **V2.0: Operational Workflows** — ACME DNS-01 challenges (wildcard certs, custom validation scripts), step-ca and OpenSSL/custom CA issuer connectors, F5 BIG-IP and IIS target connector implementations, renewal approval UI, bulk cert operations, deployment timeline, real-time updates (SSE/WebSocket), target config wizard - **V2.1: Team Adoption** — OIDC/SSO, RBAC, CLI tool, Slack/Teams notifiers, bulk cert import - **V2.2: Observability** — expiration calendar, health scores, Prometheus metrics, deployment rollback diff --git a/docs/architecture.md b/docs/architecture.md index 4f68702..d92eb85 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -40,13 +40,15 @@ flowchart TB subgraph "Issuer Backends" CA1["Local CA\n(crypto/x509)"] CA2["ACME\n(Let's Encrypt)"] - CA3["Vault PKI\n(future)"] + CA3["step-ca\n(planned)"] + CA4["OpenSSL / Custom CA\n(planned)"] + CA5["Vault PKI\n(planned)"] end subgraph "Target Systems" - T1["NGINX\n(SSH + reload)"] - T2["F5 BIG-IP\n(REST API)"] - T3["IIS\n(WinRM)"] + T1["NGINX\n(file write + reload)"] + T2["F5 BIG-IP\n(iControl REST, planned)"] + T3["IIS\n(WinRM, planned)"] end DASH --> API @@ -345,15 +347,17 @@ flowchart TB II["IssuerConnector Interface\nIssueCertificate() | RenewCertificate()\nRevokeCertificate() | GetOrderStatus()"] II --> LC["Local CA"] II --> ACME["ACME v2"] - II --> VP["Vault PKI (future)"] + II --> SC["step-ca (planned)"] + II --> OC["OpenSSL / Custom CA (planned)"] + II --> VP["Vault PKI (planned)"] end subgraph "Target Connectors" direction TB TI["TargetConnector Interface\nDeployCertificate()\nValidateDeployment()"] TI --> NG["NGINX"] - TI --> F5["F5 BIG-IP"] - TI --> IIS["IIS"] + TI --> F5["F5 BIG-IP (interface only)"] + TI --> IIS["IIS (interface only)"] end subgraph "Notifier Connectors" diff --git a/docs/connectors.md b/docs/connectors.md index 3755b91..0456c37 100644 --- a/docs/connectors.md +++ b/docs/connectors.md @@ -6,8 +6,8 @@ Connectors extend certctl to integrate with external systems for certificate iss Three types of connectors: -1. **Issuer Connector** — Obtains certificates from CAs (ACME, Local CA, Vault, DigiCert) -2. **Target Connector** — Deploys certificates to infrastructure (NGINX, F5, IIS) +1. **Issuer Connector** — Obtains certificates from CAs (Local CA, ACME; step-ca, OpenSSL, Vault, DigiCert planned) +2. **Target Connector** — Deploys certificates to infrastructure (NGINX implemented; F5, IIS interface only) 3. **Notifier Connector** — Sends alerts about certificate events (Email, Webhooks, Slack) All connectors accept JSON configuration at initialization, support config validation, and are registered in the service layer. Issuer connectors run on the control plane; target connectors run on agents. @@ -120,6 +120,15 @@ The connector is registered in the issuer registry under `iss-acme-staging` and Location: `internal/connector/issuer/acme/acme.go` +### Planned Issuers (V2) + +The following issuer connectors are planned for V2: + +- **step-ca** — Smallstep's private CA and ACME server. Would allow certctl to issue certificates from a self-hosted step-ca instance via its ACME or provisioner APIs. +- **OpenSSL / Custom CA** — Support for external CAs that use OpenSSL-based signing workflows, including custom script hooks for organizations with existing CA tooling. +- **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. + ### Building a Custom Issuer Here's the structure for a HashiCorp Vault PKI issuer: @@ -270,31 +279,28 @@ The `reload_command` defaults to `systemctl reload nginx` but can be overridden Location: `internal/connector/target/nginx/nginx.go` -### Built-in: F5 BIG-IP +### Planned: F5 BIG-IP (Interface Only) -Deploys certificates to F5 BIG-IP load balancers via the iControl REST API. This is the standard integration path for organizations using F5 for TLS offloading. The connector uploads the certificate and private key to the F5 SSL certificate store, then updates the SSL profile on the virtual server to reference the new certificate. +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. 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 V2. -Configuration: +Configuration (defined, not yet functional): ```json { "host": "f5.internal.example.com", "username": "admin", "password": "...", "partition": "Common", - "virtual_server": "/Common/vs_api", "ssl_profile": "/Common/clientssl_api" } ``` -The connector authenticates to the F5 REST API at `https://{host}/mgmt/tm/`, uploads the certificate via `POST /mgmt/tm/sys/crypto/cert`, uploads the key via `POST /mgmt/tm/sys/crypto/key`, and binds them to the specified SSL profile. The F5's native REST API handles certificate chain assembly. Agent credentials for the F5 API are stored locally on the agent, never on the control plane. - Location: `internal/connector/target/f5/f5.go` -### Built-in: IIS +### Planned: IIS (Interface Only) -Deploys certificates to Microsoft IIS web servers via WinRM (Windows Remote Management). This connector is for organizations running Windows-based infrastructure where IIS terminates TLS. The connector executes PowerShell commands over WinRM to import a PFX certificate into the Windows certificate store and bind it to an IIS site. +The IIS target connector interface is built with the WinRM/PowerShell flow mapped out, but the actual remote execution is not yet implemented. The planned flow is: transfer a PFX bundle to the Windows server via WinRM, run `Import-PfxCertificate` to install it into the certificate store, and run `Set-WebBinding` to bind the certificate to the IIS site. Implementation is planned for V2. -Configuration: +Configuration (defined, not yet functional): ```json { "host": "iis-server.internal.example.com", @@ -306,8 +312,6 @@ Configuration: } ``` -The deployment flow: the connector combines the certificate and private key into a PFX (PKCS#12) bundle, transfers it to the Windows server via WinRM, runs `Import-PfxCertificate` to install it into the specified certificate store (typically `WebHosting` or `My`), then runs `Set-WebBinding` to bind the new certificate to the IIS site. Old certificate bindings are updated in-place so there is no downtime window. - Location: `internal/connector/target/iis/iis.go` ## Notifier Connector diff --git a/docs/demo-advanced.md b/docs/demo-advanced.md index 08ed73d..b05e954 100644 --- a/docs/demo-advanced.md +++ b/docs/demo-advanced.md @@ -116,7 +116,7 @@ You should see: The result is a structurally valid X.509 certificate — browsers won't trust it (no root CA in their trust store), but it exercises the exact same code paths that a production ACME or Vault issuer would. -**Why pluggable issuers:** Different organizations use different CAs. Some use Let's Encrypt (ACME protocol), some use internal PKI (Vault, ADCS), some use commercial CAs (DigiCert, Sectigo). The connector interface means certctl doesn't care — it calls `IssueCertificate()` and gets back a signed cert regardless of the backend. +**Why pluggable issuers:** Different organizations use different CAs. Some use Let's Encrypt (ACME protocol), some use step-ca or internal PKI (Vault, ADCS), some use commercial CAs (DigiCert, Sectigo), and some have custom OpenSSL-based workflows. The connector interface means certctl doesn't care — it calls `IssueCertificate()` and gets back a signed cert regardless of the backend. V1 ships with Local CA and ACME (HTTP-01); step-ca, OpenSSL/custom CA, Vault PKI, and DigiCert are planned for V2. ```mermaid flowchart TD @@ -129,8 +129,10 @@ flowchart TD A --> E["Local CA\n(crypto/x509)"] A --> F["ACME\n(Let's Encrypt)"] - A --> G["Vault PKI\n(future)"] - A --> H["DigiCert API\n(future)"] + A --> G["step-ca\n(planned)"] + A --> H["OpenSSL / Custom CA\n(planned)"] + A --> I["Vault PKI\n(planned)"] + A --> J["DigiCert API\n(planned)"] ``` ---