mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-11 05:18:51 +00:00
Complete M1, M1.1, M2: end-to-end lifecycle, agent deployment, ACME v2
- Wire issuer connector end-to-end with IssuerConnectorAdapter (dependency inversion)
- Renewal/issuance job processor: RSA key + CSR generation, Local CA signing, cert version storage
- Agent work API (GET /agents/{id}/work) and job status API (POST /agents/{id}/jobs/{job_id}/status)
- Agent-side deployment: WorkItem enrichment with target type/config, NGINX/F5/IIS connector invocation
- Full ACME v2 implementation: HTTP-01 challenge solving, account registration, order lifecycle
- Update all docs (README, architecture, connectors, demo-advanced, quickstart) for M1-M2
- Fix go vet warning in deployment.go (non-constant format string)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+37
-12
@@ -215,13 +215,13 @@ Expected response:
|
||||
|
||||
The `202 Accepted` status code is deliberate. Certificate issuance can take seconds (Local CA) to minutes (ACME DNS challenges). The API doesn't block the caller — it creates a job and returns. The job processor loop (runs every 30 seconds) picks up pending jobs and executes them.
|
||||
|
||||
**What happens during a real renewal (production flow):**
|
||||
**What happens during renewal (V1 flow with Local CA):**
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant S as Scheduler
|
||||
participant DB as PostgreSQL
|
||||
participant SVC as CertificateService
|
||||
participant SVC as RenewalService
|
||||
participant ISS as IssuerConnector
|
||||
participant A as Agent
|
||||
|
||||
@@ -233,23 +233,25 @@ sequenceDiagram
|
||||
S->>DB: SELECT pending jobs
|
||||
DB-->>S: [job-123: Renewal for mc-demo-api]
|
||||
|
||||
S->>A: Notify: generate CSR for demo-api.internal.example.com
|
||||
A->>A: Generate RSA-2048 key pair locally
|
||||
A->>A: Create CSR with CN + SANs
|
||||
A->>SVC: POST /api/v1/agents/{id}/csr {csr_pem: "..."}
|
||||
|
||||
SVC->>ISS: IssueCertificate(CSR)
|
||||
SVC->>SVC: Generate RSA-2048 key + CSR (server-side in V1)
|
||||
SVC->>ISS: IssueCertificate(commonName, sans, csrPEM)
|
||||
ISS-->>SVC: {cert_pem, chain_pem, serial, not_after}
|
||||
|
||||
SVC->>DB: INSERT certificate_version
|
||||
SVC->>DB: INSERT certificate_version (PEM chain + fingerprint)
|
||||
SVC->>DB: UPDATE managed_certificates SET status='Active'
|
||||
SVC->>DB: INSERT audit_event (certificate_renewed)
|
||||
SVC->>DB: CREATE deployment jobs for all targets
|
||||
|
||||
SVC-->>A: {certificate_pem, chain_pem}
|
||||
A->>A: Store cert + chain locally (key never leaves)
|
||||
Note over A: Agent polls GET /agents/{id}/work
|
||||
A->>SVC: GET /api/v1/agents/{id}/work
|
||||
SVC-->>A: [deployment job for mc-demo-api]
|
||||
A->>SVC: GET /api/v1/agents/{id}/certificates/{certId}
|
||||
SVC-->>A: {certificate PEM chain}
|
||||
A->>A: Deploy to target system
|
||||
A->>SVC: POST /api/v1/agents/{id}/jobs/{jobId}/status {Completed}
|
||||
```
|
||||
|
||||
The critical security property: the private key is generated by the agent in step 3 and never transmitted. The CSR contains only the public key. The control plane forwards the CSR to the issuer and returns the signed certificate — it never has access to the private key material.
|
||||
**V1 note:** In V1 with the Local CA, key generation happens server-side in `RenewalService.ProcessRenewalJob`. In V2+, agents will generate keys locally and submit CSRs, ensuring private keys never touch the control plane.
|
||||
|
||||
Check the jobs list:
|
||||
|
||||
@@ -322,6 +324,29 @@ Check for deployment jobs:
|
||||
curl -s "$API/api/v1/jobs" | jq '.data[] | select(.certificate_id == "mc-demo-api")'
|
||||
```
|
||||
|
||||
### Agent Work Polling & Status Reporting
|
||||
|
||||
In production, agents poll for work and report results. You can simulate this manually:
|
||||
|
||||
```bash
|
||||
# Poll for pending deployment work (as an agent)
|
||||
curl -s "$API/api/v1/agents/agent-nginx-prod/work" | jq .
|
||||
```
|
||||
|
||||
This returns pending deployment jobs assigned to the agent. The agent would then fetch the certificate, deploy it, and report back:
|
||||
|
||||
```bash
|
||||
# Report job completion (replace JOB_ID with an actual job ID from the work response)
|
||||
curl -s -X POST "$API/api/v1/agents/agent-nginx-prod/jobs/JOB_ID/status" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"status": "Completed",
|
||||
"error": ""
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
**How it works:** The `GET /api/v1/agents/{id}/work` endpoint returns all pending deployment jobs. The agent processes each one, then calls `POST /api/v1/agents/{id}/jobs/{job_id}/status` with either `"Completed"` or `"Failed"` (with an error message). The control plane updates the job record and logs an audit event.
|
||||
|
||||
---
|
||||
|
||||
## Part 6: View the Audit Trail
|
||||
|
||||
Reference in New Issue
Block a user