mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-12 15:28:52 +00:00
9918f2f5cb
Runtime fixes: - Fix env var mismatch (CERTCTL_DB_URL → CERTCTL_DATABASE_URL) - Fix table name mismatches (certificates → managed_certificates, notifications → notification_events) - Add renewal_policy_id to certificate queries - Remove non-existent created_at from notification queries - Add env var fallback for agent CLI flags - Graceful degradation for missing notifiers/issuers in demo mode - Copy web/ directory in Dockerfile for dashboard serving Service layer: - Implement handler-service interface pattern across all services - Wire up certificate, agent, job, policy, team, owner, audit, notification services Documentation: - Add concepts.md: beginner-friendly guide to TLS, CAs, private keys - Rewrite quickstart.md with accurate API examples matching actual handlers - Add demo-advanced.md: interactive demo with cert issuance and automated script - Update architecture.md with correct table names and connector interfaces - Update connectors.md to match actual Go interface signatures - Update demo-guide.md with cross-references to new docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
356 lines
11 KiB
Markdown
356 lines
11 KiB
Markdown
# Advanced Demo: Certificate Lifecycle End-to-End
|
|
|
|
This demo goes beyond browsing pre-loaded data. You'll create a team, register an owner, set up an issuer, create a certificate, trigger renewal, and watch everything appear in the dashboard in real time. By the end, you'll understand the full certificate lifecycle as certctl manages it.
|
|
|
|
**Time**: 10-15 minutes
|
|
**Prerequisites**: certctl running via Docker Compose (see [Quick Start](quickstart.md))
|
|
|
|
## Setup
|
|
|
|
Make sure certctl is running:
|
|
|
|
```bash
|
|
docker compose -f deploy/docker-compose.yml up -d
|
|
# Wait for healthy status
|
|
docker compose -f deploy/docker-compose.yml ps
|
|
```
|
|
|
|
Open **http://localhost:8443** in your browser alongside your terminal. You'll watch changes appear in the dashboard as you make API calls.
|
|
|
|
Set up a base variable for convenience:
|
|
|
|
```bash
|
|
API="http://localhost:8443"
|
|
```
|
|
|
|
## Part 1: Build the Organization Structure
|
|
|
|
### Create a new team
|
|
|
|
```bash
|
|
curl -s -X POST $API/api/v1/teams \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"id": "t-demo",
|
|
"name": "Demo Team",
|
|
"description": "Team created during advanced demo walkthrough"
|
|
}' | jq .
|
|
```
|
|
|
|
### Register an owner
|
|
|
|
```bash
|
|
curl -s -X POST $API/api/v1/owners \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"id": "o-demo-user",
|
|
"name": "Demo User",
|
|
"email": "demo@example.com",
|
|
"team_id": "t-demo"
|
|
}' | jq .
|
|
```
|
|
|
|
Verify both exist:
|
|
|
|
```bash
|
|
curl -s $API/api/v1/teams/t-demo | jq .
|
|
curl -s $API/api/v1/owners/o-demo-user | jq .
|
|
```
|
|
|
|
## Part 2: Configure the Issuer
|
|
|
|
The demo ships with a Local CA issuer (`iss-local`) that can sign certificates immediately — no external CA needed. Let's verify it's available:
|
|
|
|
```bash
|
|
curl -s $API/api/v1/issuers/iss-local | jq .
|
|
```
|
|
|
|
You should see:
|
|
```json
|
|
{
|
|
"id": "iss-local",
|
|
"name": "Local Dev CA",
|
|
"type": "GenericCA",
|
|
"enabled": true
|
|
}
|
|
```
|
|
|
|
This Local CA generates real X.509 certificates using Go's `crypto/x509` library. The certificates are self-signed (not trusted by browsers in production), but structurally identical to production certificates — they have serial numbers, validity periods, SANs, key usage extensions, and a proper certificate chain.
|
|
|
|
## Part 3: Create a Managed Certificate
|
|
|
|
Now the main event. Let's create a certificate for a fictional internal API:
|
|
|
|
```bash
|
|
curl -s -X POST $API/api/v1/certificates \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"id": "mc-demo-api",
|
|
"name": "Demo API Certificate",
|
|
"common_name": "demo-api.internal.example.com",
|
|
"sans": ["demo-api.internal.example.com", "demo-api-v2.internal.example.com"],
|
|
"environment": "staging",
|
|
"owner_id": "o-demo-user",
|
|
"team_id": "t-demo",
|
|
"issuer_id": "iss-local",
|
|
"renewal_policy_id": "rp-default",
|
|
"status": "Pending",
|
|
"tags": {
|
|
"service": "demo-api",
|
|
"created_by": "advanced-demo",
|
|
"tier": "internal"
|
|
}
|
|
}' | jq .
|
|
```
|
|
|
|
**Check the dashboard now.** Click "Certificates" in the sidebar. You'll see your new "Demo API Certificate" with status "Pending" alongside the pre-loaded demo certificates. Click on it to see the full details: owner, team, environment, tags, and timeline.
|
|
|
|
### Verify via API
|
|
|
|
```bash
|
|
curl -s $API/api/v1/certificates/mc-demo-api | jq '{id, name, common_name, status, environment, owner_id, team_id}'
|
|
```
|
|
|
|
## Part 4: Trigger Certificate Renewal
|
|
|
|
In production, the scheduler automatically triggers renewal when certificates approach expiry. For this demo, we'll trigger it manually:
|
|
|
|
```bash
|
|
curl -s -X POST $API/api/v1/certificates/mc-demo-api/renew | jq .
|
|
```
|
|
|
|
Expected response:
|
|
```json
|
|
{
|
|
"status": "renewal_triggered"
|
|
}
|
|
```
|
|
|
|
This creates a renewal job. Check the jobs list:
|
|
|
|
```bash
|
|
curl -s "$API/api/v1/jobs" | jq '.data[] | select(.certificate_id == "mc-demo-api") | {id, type, status, certificate_id}'
|
|
```
|
|
|
|
**Check the dashboard.** Go to the "Jobs" view — you'll see the renewal job for your certificate.
|
|
|
|
## Part 5: Deploy the Certificate
|
|
|
|
Trigger deployment to see the deployment workflow:
|
|
|
|
```bash
|
|
curl -s -X POST $API/api/v1/certificates/mc-demo-api/deploy | jq .
|
|
```
|
|
|
|
Expected response:
|
|
```json
|
|
{
|
|
"status": "deployment_triggered"
|
|
}
|
|
```
|
|
|
|
Check for deployment jobs:
|
|
|
|
```bash
|
|
curl -s "$API/api/v1/jobs" | jq '.data[] | select(.certificate_id == "mc-demo-api")'
|
|
```
|
|
|
|
## Part 6: View the Audit Trail
|
|
|
|
Every action you've taken has been recorded. Check the audit trail:
|
|
|
|
```bash
|
|
curl -s $API/api/v1/audit | jq '.data[0:5]'
|
|
```
|
|
|
|
You'll see events for certificate creation, renewal trigger, and deployment trigger — each with actor, action, resource type, and timestamp.
|
|
|
|
**Check the dashboard.** The "Audit" view shows the full timeline of all actions across the system.
|
|
|
|
## Part 7: Check Notifications
|
|
|
|
Certctl sends notifications for certificate lifecycle events. Check what notifications were generated:
|
|
|
|
```bash
|
|
curl -s $API/api/v1/notifications | jq '.data[0:5]'
|
|
```
|
|
|
|
In demo mode, notifications are marked as "sent" even without a real email/webhook backend. In production, these would go out via SMTP or HTTP webhooks.
|
|
|
|
## Part 8: Create a Second Certificate and Compare
|
|
|
|
Let's create another certificate in production to see how the dashboard handles multiple environments:
|
|
|
|
```bash
|
|
curl -s -X POST $API/api/v1/certificates \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"id": "mc-demo-payments",
|
|
"name": "Demo Payments Gateway",
|
|
"common_name": "payments.example.com",
|
|
"sans": ["payments.example.com", "checkout.example.com"],
|
|
"environment": "production",
|
|
"owner_id": "o-demo-user",
|
|
"team_id": "t-demo",
|
|
"issuer_id": "iss-local",
|
|
"renewal_policy_id": "rp-default",
|
|
"status": "Active",
|
|
"expires_at": "2026-04-01T00:00:00Z",
|
|
"tags": {
|
|
"service": "payments",
|
|
"pci": "true",
|
|
"tier": "critical"
|
|
}
|
|
}' | jq .
|
|
```
|
|
|
|
This certificate expires in about 18 days from the demo date, so it should show up as "Expiring" in the dashboard when the scheduler runs. **Refresh the dashboard** — you'll see it in the certificate list.
|
|
|
|
Now filter the dashboard by environment or status to see how the filtering works with your new certificates mixed in with the demo data.
|
|
|
|
## Part 9: Policy Violations
|
|
|
|
Let's see what happens when a certificate doesn't meet policy requirements. Check existing policy rules:
|
|
|
|
```bash
|
|
curl -s $API/api/v1/policies | jq '.data[] | {id, name, type, enabled}'
|
|
```
|
|
|
|
The demo includes rules for required owner metadata, allowed environments, maximum certificate lifetime, and minimum renewal windows. Check existing violations:
|
|
|
|
```bash
|
|
curl -s "$API/api/v1/policies/pr-max-certificate-lifetime/violations" | jq .
|
|
```
|
|
|
|
**In the dashboard**, click "Policies" in the sidebar to see all active rules and which certificates are violating them.
|
|
|
|
## Full Automated Script
|
|
|
|
Here's a single script that runs the entire demo end-to-end. Save it as `demo.sh` and run it:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
API="http://localhost:8443"
|
|
BLUE='\033[0;34m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
echo -e "${BLUE}=== certctl Advanced Demo ===${NC}"
|
|
echo ""
|
|
|
|
# Step 1: Health check
|
|
echo -e "${YELLOW}Step 1: Checking server health...${NC}"
|
|
HEALTH=$(curl -s $API/health | jq -r '.status')
|
|
if [ "$HEALTH" != "healthy" ]; then
|
|
echo "Server is not healthy. Run: docker compose -f deploy/docker-compose.yml up -d"
|
|
exit 1
|
|
fi
|
|
echo -e "${GREEN}Server is healthy${NC}"
|
|
echo ""
|
|
|
|
# Step 2: Create team
|
|
echo -e "${YELLOW}Step 2: Creating demo team...${NC}"
|
|
curl -s -X POST $API/api/v1/teams \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"id":"t-demo-auto","name":"Automated Demo Team","description":"Created by demo script"}' | jq -r '.id'
|
|
echo -e "${GREEN}Team created${NC}"
|
|
echo ""
|
|
|
|
# Step 3: Create owner
|
|
echo -e "${YELLOW}Step 3: Registering demo owner...${NC}"
|
|
curl -s -X POST $API/api/v1/owners \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"id":"o-demo-auto","name":"Demo Script","email":"demo-script@example.com","team_id":"t-demo-auto"}' | jq -r '.id'
|
|
echo -e "${GREEN}Owner registered${NC}"
|
|
echo ""
|
|
|
|
# Step 4: Create certificate
|
|
echo -e "${YELLOW}Step 4: Creating managed certificate...${NC}"
|
|
CERT_ID="mc-demo-$(date +%s)"
|
|
curl -s -X POST $API/api/v1/certificates \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"id":"'$CERT_ID'",
|
|
"name":"Demo Auto Certificate",
|
|
"common_name":"auto-demo.internal.example.com",
|
|
"sans":["auto-demo.internal.example.com"],
|
|
"environment":"staging",
|
|
"owner_id":"o-demo-auto",
|
|
"team_id":"t-demo-auto",
|
|
"issuer_id":"iss-local",
|
|
"renewal_policy_id":"rp-default",
|
|
"status":"Pending",
|
|
"tags":{"created_by":"demo-script","automated":"true"}
|
|
}' | jq '{id, name, status}'
|
|
echo -e "${GREEN}Certificate created: $CERT_ID${NC}"
|
|
echo ""
|
|
|
|
# Step 5: Trigger renewal
|
|
echo -e "${YELLOW}Step 5: Triggering certificate renewal...${NC}"
|
|
curl -s -X POST $API/api/v1/certificates/$CERT_ID/renew | jq .
|
|
echo -e "${GREEN}Renewal triggered${NC}"
|
|
echo ""
|
|
|
|
# Step 6: Trigger deployment
|
|
echo -e "${YELLOW}Step 6: Triggering certificate deployment...${NC}"
|
|
curl -s -X POST $API/api/v1/certificates/$CERT_ID/deploy | jq .
|
|
echo -e "${GREEN}Deployment triggered${NC}"
|
|
echo ""
|
|
|
|
# Step 7: Check certificate status
|
|
echo -e "${YELLOW}Step 7: Checking certificate status...${NC}"
|
|
curl -s $API/api/v1/certificates/$CERT_ID | jq '{id, name, status, common_name, environment}'
|
|
echo ""
|
|
|
|
# Step 8: Check jobs
|
|
echo -e "${YELLOW}Step 8: Checking jobs...${NC}"
|
|
curl -s "$API/api/v1/jobs" | jq "[.data[] | select(.certificate_id == \"$CERT_ID\") | {id, type, status}]"
|
|
echo ""
|
|
|
|
# Step 9: View recent audit events
|
|
echo -e "${YELLOW}Step 9: Recent audit events...${NC}"
|
|
curl -s $API/api/v1/audit | jq '.data[0:3] | .[] | {action, resource_type, resource_id, timestamp}'
|
|
echo ""
|
|
|
|
# Step 10: Summary
|
|
echo -e "${BLUE}=== Demo Complete ===${NC}"
|
|
echo ""
|
|
echo "What happened:"
|
|
echo " 1. Created a team and owner for accountability"
|
|
echo " 2. Created a managed certificate tracked by certctl"
|
|
echo " 3. Triggered renewal (would contact the Local CA in production flow)"
|
|
echo " 4. Triggered deployment (would push to NGINX/F5/IIS targets)"
|
|
echo " 5. All actions recorded in the audit trail"
|
|
echo ""
|
|
echo -e "Open ${GREEN}http://localhost:8443${NC} to see everything in the dashboard."
|
|
echo "Look for certificate: $CERT_ID"
|
|
```
|
|
|
|
Make it executable and run:
|
|
|
|
```bash
|
|
chmod +x demo.sh
|
|
./demo.sh
|
|
```
|
|
|
|
## What to Show Stakeholders
|
|
|
|
If you're using this demo to present certctl to decision-makers, here's the narrative:
|
|
|
|
1. **Start with the dashboard** — "This is your certificate inventory. Every TLS certificate across your infrastructure, in one place."
|
|
2. **Point to expiring certs** — "These certificates would have caused outages. Certctl catches them automatically."
|
|
3. **Show the cert you just created** — "I just created this via the API. It's already tracked, assigned to a team, and will be renewed automatically."
|
|
4. **Show the audit trail** — "Complete traceability. Every action, every change, every deployment — timestamped and attributed."
|
|
5. **Show policies** — "Guardrails. We enforce that every certificate has an owner, uses approved CAs, and stays within allowed environments."
|
|
6. **Show agents** — "Private keys never touch the control plane. Agents handle cryptographic operations locally on your infrastructure."
|
|
7. **Show the API** — "Everything is API-first. The dashboard is just one consumer. You can integrate with CI/CD, Terraform, or custom tooling."
|
|
|
|
## Teardown
|
|
|
|
```bash
|
|
docker compose -f deploy/docker-compose.yml down -v
|
|
```
|