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
| Aspect | Manual Management | cert-ctrl |
|---|---|---|
| Initial Setup | 2-3 hours per domain | 15 minutes (one-time) |
| Renewal | 1-2 hours every 90 days | Automatic (0 hours) |
| Downtime | 5-30 minutes per renewal | Zero downtime |
| Error Rate | High (human mistakes) | Near zero (automated) |
| Scalability | Poor (linear effort) | Excellent (constant effort) |
| Multi-Server | Manual copy to each | Automatic distribution |
| Monitoring | Manual calendar | Built-in alerts |
| Security | Unencrypted keys on disk | Encrypted with device keys |
| Audit Trail | None | Full 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.