Skip to main content

cert-ctrl Use Case Diagrams

Use Case 1: Development Environment with Self-Signed CA

Problem: Manual CA Distribution

Developer needs HTTPS on localhost

Generate self-signed CA

😫 Manual steps on EVERY machine:

┌────────────────────────────────┐
│ 1. Copy CA cert file │
│ 2. Install in trust store │
│ • Windows: certmgr.msc │
│ • Linux: update-ca-trust │
│ • macOS: Keychain Access │
│ 3. Configure each app │
│ 4. Repeat when CA changes │
└────────────────────────────────┘

Still doesn't work in WSL/Docker? 😭
Repeat everything again!

Solution: Automated CA Distribution

┌──────────────────────────────────────┐
│ cert-ctrl Server │
│ • Generates self-signed CA │
│ • Serves CA to authenticated agents │
│ • Issues dev certificates │
└──────┬───────────────────────────────┘

│ Agents authenticate & pull CA

├─────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│Windows│ │ WSL │ │ SSH │ │Docker │
│ Host │ │Ubuntu │ │Remote │ │ VM │
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
│ │ │ │
┌───▼────────────▼──────────────▼──────────────▼───┐
│ All trust CA automatically! │
│ • Browser: ✅ https://app.localhost.dev │
│ • curl: ✅ curl https://api.localhost.dev │
│ • Python: ✅ requests.get(https://...) │
│ • Node: ✅ fetch(https://...) │
└──────────────────────────────────────────────────┘

Sequence Diagram: First-Time Setup

Developer        cert-ctrl        Agent           OS Trust
Server (Windows) Store
│ │ │ │
│ 1. Start │ │ │
│──────────────>│ │ │
│ │ │ │
│ 2. Install agent │ │
│──────────────────────────────>│ │
│ │ │ │
│ │ 3. Register │ │
│ │<───────────────│ │
│ │ │ │
│ │ 4. Send CA │ │
│ │────────────────>│ │
│ │ │ │
│ │ │ 5. Install CA │
│ │ │───────────────>│
│ │ │ │
│ │ │ 6. CA trusted │
│ │ │<───────────────│
│ │ │ │
│ │ 7. Ack success │ │
│ │<───────────────│ │
│ │ │ │
│ 8. Browse https://app.localhost.dev ✅ │
│────────────────────────────────────────────────>│

Use Case 2: Production Certificate Distribution

Problem: Manual Certificate Deployment

Certificate from Let's Encrypt

😫 Every 90 days, on EVERY server:

┌──────────────────────────────┐
│ ssh server1.example.com │
│ sudo certbot renew │
│ sudo cp cert to nginx │
│ sudo nginx -s reload │
│ │
│ ssh server2.example.com │
│ sudo certbot renew │
│ ... repeat ... │
│ │
│ ssh server10.example.com │
│ ... exhausted ... │
└──────────────────────────────┘

Forgot one server? Site down! 💥

Solution: Centralized Certificate Management

┌────────────────────────────────────────────┐
│ cert-ctrl Server │
│ 1. Talk to Let's Encrypt/ZeroSSL │
│ 2. Solve DNS-01 challenge automatically │
│ 3. Store cert + private key (encrypted) │
│ 4. Track expiry, auto-renew │
└────────┬───────────────────────────────────┘

│ Agents poll for updates

├─────────┬─────────┬─────────┬─────────┐
▼ ▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ Web1 │ │ Web2 │ │ API │ │ LB │ │ CDN │
│ Nginx │ │ Nginx │ │Node.js││HAProxy│ │Origin │
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
│ │ │ │ │
└─────────┴─────────┴─────────┴─────────┘
All servers get cert automatically! ✅

Sequence Diagram: Certificate Renewal Flow

cert-ctrl     Let's Encrypt    Cloudflare    Agent(Web1)   Agent(Web2)
Server API DNS
│ │ │ │ │
│ 1. Check expiry (Day 60) │ │ │
│────────────────>│ │ │ │
│ │ │ │ │
│ 2. Request new cert │ │ │
│────────────────>│ │ │ │
│ │ │ │ │
│ │ 3. DNS challenge │ │
│ │───────────────>│ │ │
│ │ │ │ │
│ 4. Set TXT record │ │ │
│────────────────────────────────>│ │ │
│ │ │ │ │
│ │ 5. Verify │ │ │
│ │<──────────────>│ │ │
│ │ │ │ │
│ 6. Issue cert │ │ │ │
│<───────────────│ │ │ │
│ │ │ │ │
│ 7. Store & encrypt cert │ │ │
│ │ │ │ │
│ │ │ 8. Poll for updates │
│ │ │<────────────│ │
│ │ │ │ │
│ 9. New cert available │ │ │
│────────────────────────────────>│ │ │
│ │ │ │ │
│ │ │ 10. Deploy & reload │
│ │ │─────────────>nginx │
│ │ │ ✅ │
│ │ │ │ │
│ │ │ │ 11. Poll │
│ │ │ │<────────────│
│ │ │ │ │
│ 12. New cert available │ │ │
│────────────────────────────────────────────────────────────>│
│ │ │ │ │
│ │ │ │ 13. Deploy │
│ │ │ │─────────────>nginx
│ │ │ │ ✅

Timeline: 90-Day Certificate Lifecycle

Day 0    │ Certificate issued (valid 90 days)
│ ✅ cert.example.com (expires Day 90)

Day 30 │ First renewal check
│ ℹ️ Still valid, no action

Day 60 │ Auto-renewal triggered
│ 🔄 cert-ctrl contacts Let's Encrypt
│ 🔄 DNS challenge solved automatically
│ ✅ New cert issued (valid until Day 150)
│ 🚀 Agents deploy to all servers
│ 🔄 Nginx/Apache reloaded (zero downtime)

Day 90 │ Old cert expires
│ ✅ Already replaced! No one noticed!

Day 120 │ Next renewal check
│ 🔄 Repeat cycle...

Comparison Table

AspectManual Managementcert-ctrl
Initial Setup2-3 hours per domain15 minutes (one-time)
Renewal1-2 hours every 90 daysAutomatic (0 hours)
Downtime5-30 minutes per renewalZero downtime
Error RateHigh (human mistakes)Near zero (automated)
ScalabilityPoor (linear effort)Excellent (constant effort)
Multi-ServerManual copy to eachAutomatic distribution
MonitoringManual calendarBuilt-in alerts
SecurityUnencrypted keys on diskEncrypted with device keys
Audit TrailNoneFull audit log

Security Architecture: Device-Specific Encryption

How Private Keys Stay Safe

┌─────────────────────────────────────────────────────┐
│ cert-ctrl Server │
│ │
│ 1. Certificate issued │
│ Private Key: ────────┐ │
│ ▼ │
│ 2. Wrap with Master Key (AES-256) │
│ Encrypted Blob: [XXXXXXXXX] │
│ │ │
│ 3. Assign to Device │ │
│ ▼ │
│ 4. Wrap with Device Public Key (X25519) │
│ Device-Specific Blob: [YYYYYYYYY] │
└──────────────────────────┬──────────────────────────┘

│ Over HTTPS

┌─────────────────┐
│ Agent (Web1) │
│ │
│ Has: Device │
│ Secret Key │
│ │ │
│ ▼ │
│ Decrypt blob │
│ │ │
│ ▼ │
│ Private Key │
│ (in memory │
│ only!) │
│ │ │
│ ▼ │
│ Install to │
│ /etc/nginx/ssl/│
└─────────────────┘

❌ Web2's agent CANNOT decrypt Web1's blob
✅ Each device has unique encryption key
✅ Server never stores unencrypted private keys
✅ Private keys only exist in memory during install

Agent Polling Mechanism

Long-Polling for Real-Time Updates

Agent                              cert-ctrl Server
│ │
│ 1. Poll (long-timeout: 60s) │
│─────────────────────────────────────>│
│ │
│ ... connection held open ... │
│ │
│ │ 2. New cert issued
│ │ (Day 60 auto-renewal)
│ │
│ 3. Response: "New cert available" │
│<─────────────────────────────────────│
│ │
│ 4. Fetch cert │
│─────────────────────────────────────>│
│ │
│ 5. Encrypted cert bundle │
│<─────────────────────────────────────│
│ │
│ 6. Decrypt & install │
│ 7. Reload nginx │
│ │
│ 8. Poll again │
│─────────────────────────────────────>│
│ ... connection held open ... │

Advantages over webhooks:

  • No firewall configuration needed
  • Works behind NAT/proxies
  • Agent initiates connection (secure)
  • Automatic retry on failure

Multi-Cloud Deployment Example

                    ┌────────────────────┐
│ cert-ctrl Server │
│ (Your infra) │
└─────────┬──────────┘

┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ AWS │ │ GCP │ │ Azure │
│ │ │ │ │ │
│ EC2 (Nginx) │ │ GCE (Node) │ │ VM (IIS) │
│ Agent ✅ │ │ Agent ✅ │ │ Agent ✅ │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└─────────────────┼─────────────────┘

All use same certificate!
Auto-renewed every 60 days

This works because:

  • Agents pull certificates (outbound only, no firewall holes)
  • Same certificate can be deployed to any provider
  • Device-specific encryption keeps keys safe
  • No provider lock-in

Development vs Production Workflows

Development Workflow

┌──────────────────────────────────────────────────┐
│ Step 1: Start local cert-ctrl server │
│ docker-compose up │
│ Server generates self-signed CA automatically │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 2: Install agent on dev machine │
│ certctrl-agent install --server localhost:8443│
│ Agent trusts CA in system │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 3: Request dev certificate │
│ Dashboard → New Certificate │
│ Domain: myapp.localhost.dev │
│ Type: Self-signed (CA) │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 4: Use in your app │
│ nginx conf: │
│ ssl_certificate /var/certctrl/cert.pem; │
│ ssl_certificate_key /var/certctrl/key.pem; │
│ │
│ Browse: https://myapp.localhost.dev ✅ │
└──────────────────────────────────────────────────┘

Production Workflow

┌──────────────────────────────────────────────────┐
│ Step 1: Deploy cert-ctrl to production server │
│ Kubernetes / Docker / VM │
│ Configure DNS provider credentials │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 2: Request public certificate │
│ Dashboard → New Certificate │
│ Domain: example.com │
│ DNS: Cloudflare (API token) │
│ CA: Let's Encrypt (production) │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 3: Install agents on production servers │
│ ssh web1 && certctrl-agent install │
│ ssh web2 && certctrl-agent install │
│ ssh api1 && certctrl-agent install │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 4: Assign certificate to devices │
│ Dashboard → Assign │
│ ☑ web1, web2, api1 │
│ Agents auto-deploy & reload │
└──────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────┐
│ Step 5: Forget about it! │
│ • Auto-renewal on Day 60 │
│ • Zero-downtime deployment │
│ • Email alerts if issues │
└──────────────────────────────────────────────────┘

These diagrams illustrate the complete workflows for both use cases, making it easy to understand how cert-ctrl simplifies certificate management in development and production environments.