mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 17:02:43 +00:00
d9fd0a147e
Three new GUI surfaces closing the backend-to-frontend gap for V2: - Discovery triage page: summary stats bar, DataTable with claim/dismiss actions, status/agent filters, collapsible scan history panel - Network scan target management: CRUD with create modal, enable/disable toggle, Scan Now button, last scan results display - Jobs page approval workflow: Approve/Reject buttons for AwaitingApproval jobs, rejection reason modal, pending approval banner with count, AwaitingApproval/AwaitingCSR added to status filter dropdown Also adds 13 new frontend tests, 4 API types, 12 API client functions, 2 sidebar nav items, 2 routes, and discovery status badge styles. Docs updated: README, architecture, quickstart, demo-advanced, CLAUDE.md, roadmap. Version bumped to v2.0.4. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
405 lines
16 KiB
Markdown
405 lines
16 KiB
Markdown
# Quick Start Guide
|
|
|
|
Certificate lifespans are dropping to **47 days by 2029**. At that cadence, a team managing 100 certificates is processing 7+ renewals per week — every week, forever. Manual processes break. certctl automates the entire lifecycle: issuance, renewal, deployment, revocation, and audit — with zero human intervention.
|
|
|
|
This guide gets you running in 5 minutes and walks you through everything certctl does.
|
|
|
|
New to certificates? Read the [Concepts Guide](concepts.md) first — it explains TLS, CAs, and private keys in plain language.
|
|
|
|
## Contents
|
|
|
|
1. [Prerequisites](#prerequisites)
|
|
2. [Start Everything](#start-everything)
|
|
3. [Open the Dashboard](#open-the-dashboard)
|
|
4. [Explore the API](#explore-the-api)
|
|
- [Core operations](#core-operations)
|
|
- [Sorting, filtering, and pagination](#sorting-filtering-and-pagination)
|
|
- [Stats and metrics](#stats-and-metrics)
|
|
5. [Create Your First Certificate](#create-your-first-certificate)
|
|
- [Revoke a certificate](#revoke-a-certificate)
|
|
- [Interactive approval workflow](#interactive-approval-workflow)
|
|
6. [Certificate Discovery](#certificate-discovery)
|
|
- [Filesystem discovery (agent-based)](#filesystem-discovery-agent-based)
|
|
- [Network discovery (agentless)](#network-discovery-agentless)
|
|
- [Triage discovered certificates](#triage-discovered-certificates)
|
|
7. [CLI Tool](#cli-tool)
|
|
8. [MCP Server (AI Integration)](#mcp-server-ai-integration)
|
|
9. [Demo Data Reference](#demo-data-reference)
|
|
10. [Dashboard Demo Mode](#dashboard-demo-mode)
|
|
11. [Presenting to Stakeholders](#presenting-to-stakeholders)
|
|
12. [Tear Down](#tear-down)
|
|
13. [What's Next](#whats-next)
|
|
|
|
## Prerequisites
|
|
|
|
You need **Docker** and **Docker Compose** installed. That's it.
|
|
|
|
On macOS:
|
|
```bash
|
|
brew install --cask docker
|
|
```
|
|
|
|
On Linux, follow the official Docker install guide for your distribution.
|
|
|
|
## Start Everything
|
|
|
|
```bash
|
|
git clone https://github.com/shankar0123/certctl.git
|
|
cd certctl
|
|
docker compose -f deploy/docker-compose.yml up -d --build
|
|
```
|
|
|
|
The `--build` flag builds the server image including the React frontend. Without it, Docker may use a stale cached image.
|
|
|
|
**For production deployments**, copy `deploy/.env.example` to `deploy/.env` and customize the credentials:
|
|
```bash
|
|
cp deploy/.env.example deploy/.env
|
|
# Edit deploy/.env to set secure POSTGRES_PASSWORD and CERTCTL_API_KEY values
|
|
docker compose -f deploy/docker-compose.yml up -d --build
|
|
```
|
|
|
|
Wait about 30 seconds for PostgreSQL to initialize, then verify:
|
|
|
|
```bash
|
|
docker compose -f deploy/docker-compose.yml ps
|
|
```
|
|
|
|
You should see:
|
|
```
|
|
NAME STATUS
|
|
certctl-postgres Up (healthy)
|
|
certctl-server Up (healthy)
|
|
certctl-agent Up
|
|
```
|
|
|
|
```bash
|
|
curl http://localhost:8443/health
|
|
```
|
|
```json
|
|
{"status":"healthy"}
|
|
```
|
|
|
|
## Open the Dashboard
|
|
|
|
Open **http://localhost:8443** in your browser.
|
|
|
|
The dashboard comes pre-loaded with 15 demo certificates across multiple teams, environments, and statuses — expiring certs, expired certs, active certs, failed renewals. A realistic snapshot of what certificate management looks like in a real organization.
|
|
|
|
### What you're looking at
|
|
|
|
The main dashboard shows total certificates, how many are expiring soon, how many have expired, the renewal success rate, and four charts: an **expiration heatmap** (90-day weekly buckets), **renewal success rate trends** (30-day line chart), **certificate status distribution** (donut chart), and **issuance rate** (30-day bar chart).
|
|
|
|
Explore the sidebar: Certificates, Agents, Policies, Jobs, Audit Trail, Notifications, Profiles, Teams, Owners, Agent Groups, Fleet Overview, Short-Lived Credentials, Discovery, and Network Scans.
|
|
|
|
### Scenarios to walk through
|
|
|
|
**"We're about to have an outage"** — Filter certificates by status → Expiring. You'll see `auth-production` (12 days), `cdn-production` (8 days), and `mail-production` (5 days). At 47-day lifespans, this is every other week. certctl catches these automatically and triggers renewal before they expire.
|
|
|
|
**"A renewal failed"** — Look at `vpn-production` — status: Failed. Click it to see the audit trail showing the ACME challenge failure after 3 retry attempts. The system sent a webhook notification to the ops channel. No one had to notice manually.
|
|
|
|
**"Who owns this cert?"** — Click any certificate. Owner, team, environment, tags. Clear accountability. Notifications route to the owner's email automatically.
|
|
|
|
**"Can I revoke a compromised cert?"** — Click any active certificate, then "Revoke." A modal with RFC 5280 reason codes (Key Compromise, Superseded, Cessation of Operation). After revocation, CRL and OCSP are served automatically — clients stop trusting the cert immediately.
|
|
|
|
**"What about certificates already in production?"** — Click "Discovered Certificates." Agents scan local filesystems for existing certs. The server probes TLS endpoints on configured CIDR ranges. Both feed into a triage workflow: claim unmanaged certs to bring them under automation, or dismiss them.
|
|
|
|
**"Show me the agent fleet"** — Click "Agents." Four agents online, one offline. Click "Fleet Overview" for OS/architecture grouping, version distribution, and per-platform listing. Agents generate ECDSA P-256 keys locally — private keys never leave your infrastructure.
|
|
|
|
**"What about bulk operations?"** — On the Certificates page, select multiple certificates with checkboxes. A bulk action bar appears: trigger renewal, revoke with reason codes, or reassign ownership — all with progress tracking. At 47-day lifespans with hundreds of certs, bulk operations aren't optional.
|
|
|
|
**"Short-lived credentials?"** — Click "Short-Lived" in the sidebar. Live countdown timers for certificates with TTL under 1 hour. Auto-refresh every 10 seconds. These are for service-to-service auth where rapid expiry replaces revocation.
|
|
|
|
## Explore the API
|
|
|
|
Everything you see in the dashboard is backed by the REST API. All endpoints live under `/api/v1/` and return JSON.
|
|
|
|
### Core operations
|
|
|
|
```bash
|
|
# List all certificates
|
|
curl -s http://localhost:8443/api/v1/certificates | jq .
|
|
|
|
# Filter by status
|
|
curl -s "http://localhost:8443/api/v1/certificates?status=Expiring" | jq .
|
|
|
|
# Filter by environment
|
|
curl -s "http://localhost:8443/api/v1/certificates?environment=production" | jq .
|
|
|
|
# Get a specific certificate
|
|
curl -s http://localhost:8443/api/v1/certificates/mc-api-prod | jq .
|
|
|
|
# Get deployment targets for a certificate
|
|
curl -s http://localhost:8443/api/v1/certificates/mc-api-prod/deployments | jq .
|
|
|
|
# List agents
|
|
curl -s http://localhost:8443/api/v1/agents | jq .
|
|
|
|
# Check agent pending work
|
|
curl -s http://localhost:8443/api/v1/agents/ag-web-prod/work | jq .
|
|
|
|
# View audit trail
|
|
curl -s http://localhost:8443/api/v1/audit | jq .
|
|
|
|
# View policies and violations
|
|
curl -s http://localhost:8443/api/v1/policies | jq .
|
|
curl -s http://localhost:8443/api/v1/policies/pr-require-owner/violations | jq .
|
|
|
|
# Notifications
|
|
curl -s http://localhost:8443/api/v1/notifications | jq .
|
|
|
|
# Profiles and agent groups
|
|
curl -s http://localhost:8443/api/v1/profiles | jq .
|
|
curl -s http://localhost:8443/api/v1/agent-groups | jq .
|
|
```
|
|
|
|
### Sorting, filtering, and pagination
|
|
|
|
```bash
|
|
# Sort by expiration date (ascending)
|
|
curl -s "http://localhost:8443/api/v1/certificates?sort=notAfter" | jq .
|
|
|
|
# Sort descending (prefix with -)
|
|
curl -s "http://localhost:8443/api/v1/certificates?sort=-createdAt" | jq .
|
|
|
|
# Time-range filters (RFC3339)
|
|
curl -s "http://localhost:8443/api/v1/certificates?expires_before=2026-05-01T00:00:00Z" | jq .
|
|
curl -s "http://localhost:8443/api/v1/certificates?created_after=2026-03-01T00:00:00Z" | jq .
|
|
|
|
# Sparse fields — request only what you need
|
|
curl -s "http://localhost:8443/api/v1/certificates?fields=id,common_name,status,expires_at" | jq .
|
|
|
|
# Cursor pagination — efficient for large inventories
|
|
curl -s "http://localhost:8443/api/v1/certificates?page_size=5" | jq '{next_cursor: .next_cursor, count: (.data | length)}'
|
|
curl -s "http://localhost:8443/api/v1/certificates?cursor=<next_cursor_value>&page_size=5" | jq .
|
|
```
|
|
|
|
Supported sort fields: `notAfter`, `expiresAt`, `createdAt`, `updatedAt`, `commonName`, `name`, `status`, `environment`.
|
|
|
|
### Stats and metrics
|
|
|
|
```bash
|
|
# Dashboard summary
|
|
curl -s http://localhost:8443/api/v1/stats/summary | jq .
|
|
|
|
# Certificates by status
|
|
curl -s http://localhost:8443/api/v1/stats/certificates-by-status | jq .
|
|
|
|
# Expiration timeline (next 90 days)
|
|
curl -s "http://localhost:8443/api/v1/stats/expiration-timeline?days=90" | jq .
|
|
|
|
# Job trends (last 30 days)
|
|
curl -s "http://localhost:8443/api/v1/stats/job-trends?days=30" | jq .
|
|
|
|
# JSON metrics
|
|
curl -s http://localhost:8443/api/v1/metrics | jq .
|
|
|
|
# Prometheus format (for Prometheus, Grafana Agent, Datadog)
|
|
curl -s http://localhost:8443/api/v1/metrics/prometheus
|
|
```
|
|
|
|
## Create Your First Certificate
|
|
|
|
Create a certificate record that certctl will track, renew, and deploy automatically.
|
|
|
|
```bash
|
|
curl -s -X POST http://localhost:8443/api/v1/certificates \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"name": "My First Certificate",
|
|
"common_name": "myapp.example.com",
|
|
"sans": ["myapp.example.com", "www.myapp.example.com"],
|
|
"environment": "staging",
|
|
"owner_id": "o-alice",
|
|
"team_id": "t-platform",
|
|
"issuer_id": "iss-local",
|
|
"renewal_policy_id": "rp-default",
|
|
"status": "Pending",
|
|
"tags": {"purpose": "quickstart-demo"}
|
|
}' | jq .
|
|
```
|
|
|
|
Save the certificate ID (or provide your own `id` in the request body, e.g. `"id": "mc-my-first"`):
|
|
```bash
|
|
CERT_ID="<paste the id from the response>"
|
|
```
|
|
|
|
Trigger renewal:
|
|
```bash
|
|
curl -s -X POST http://localhost:8443/api/v1/certificates/$CERT_ID/renew | jq .
|
|
```
|
|
|
|
Check the result:
|
|
```bash
|
|
curl -s http://localhost:8443/api/v1/certificates/$CERT_ID | jq .
|
|
```
|
|
|
|
Refresh the dashboard at http://localhost:8443 — your new certificate appears in the inventory.
|
|
|
|
### Revoke a certificate
|
|
|
|
When a private key is compromised or a service is decommissioned:
|
|
|
|
```bash
|
|
curl -s -X POST http://localhost:8443/api/v1/certificates/$CERT_ID/revoke \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"reason": "superseded"}' | jq .
|
|
```
|
|
|
|
Supported RFC 5280 reason codes: `unspecified`, `keyCompromise`, `caCompromise`, `affiliationChanged`, `superseded`, `cessationOfOperation`, `certificateHold`, `privilegeWithdrawn`.
|
|
|
|
Confirm via CRL:
|
|
```bash
|
|
curl -s http://localhost:8443/api/v1/crl | jq .
|
|
```
|
|
|
|
### Interactive approval workflow
|
|
|
|
For high-value certificates where you want human oversight:
|
|
|
|
```bash
|
|
# Approve a pending job
|
|
curl -s -X POST http://localhost:8443/api/v1/jobs/JOB_ID/approve \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"reason": "Approved for production deployment"}' | jq .
|
|
|
|
# Reject a pending job
|
|
curl -s -X POST http://localhost:8443/api/v1/jobs/JOB_ID/reject \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"reason": "Key type does not meet compliance requirements"}' | jq .
|
|
```
|
|
|
|
## Certificate Discovery
|
|
|
|
Find certificates already running in your infrastructure — ones you didn't issue through certctl.
|
|
|
|
### Filesystem discovery (agent-based)
|
|
|
|
```bash
|
|
# Configure agent to scan directories
|
|
export CERTCTL_DISCOVERY_DIRS="/etc/nginx/certs,/etc/ssl/certs,/var/lib/certs"
|
|
# Agent scans on startup + every 6 hours
|
|
```
|
|
|
|
### Network discovery (agentless)
|
|
|
|
```bash
|
|
# Enable network scanning
|
|
export CERTCTL_NETWORK_SCAN_ENABLED=true
|
|
|
|
# Create a scan target
|
|
curl -s -X POST http://localhost:8443/api/v1/network-scan-targets \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"name": "Internal Network",
|
|
"cidrs": ["10.0.1.0/24"],
|
|
"ports": [443, 8443],
|
|
"enabled": true,
|
|
"scan_interval_hours": 6,
|
|
"timeout_ms": 5000
|
|
}' | jq .
|
|
|
|
# Trigger an immediate scan
|
|
curl -s -X POST http://localhost:8443/api/v1/network-scan-targets/nst-internal-network/scan | jq .
|
|
```
|
|
|
|
### Triage discovered certificates
|
|
|
|
```bash
|
|
# List discovered certs
|
|
curl -s "http://localhost:8443/api/v1/discovered-certificates?agent_id=agent-nginx-prod" | jq .
|
|
|
|
# Summary counts
|
|
curl -s http://localhost:8443/api/v1/discovery-summary | jq .
|
|
|
|
# Claim a discovered cert (bring under management)
|
|
curl -s -X POST "http://localhost:8443/api/v1/discovered-certificates/DISCOVERY_ID/claim" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"managed_certificate_id": "mc-api-prod"}' | jq .
|
|
```
|
|
|
|
## CLI Tool
|
|
|
|
```bash
|
|
cd cmd/cli && go build -o certctl-cli .
|
|
|
|
export CERTCTL_SERVER_URL="http://localhost:8443"
|
|
export CERTCTL_API_KEY="test-key-123"
|
|
|
|
./certctl-cli certs list # List certificates
|
|
./certctl-cli certs get mc-api-prod # Certificate details
|
|
./certctl-cli certs renew mc-api-prod # Trigger renewal
|
|
./certctl-cli certs revoke mc-api-prod --reason keyCompromise
|
|
./certctl-cli agents list # List agents
|
|
./certctl-cli jobs list # List jobs
|
|
./certctl-cli import /path/to/certs.pem # Bulk import
|
|
./certctl-cli status # Health + stats
|
|
```
|
|
|
|
## MCP Server (AI Integration)
|
|
|
|
```bash
|
|
cd cmd/mcp-server && go build -o mcp-server .
|
|
|
|
export CERTCTL_SERVER_URL="http://localhost:8443"
|
|
export CERTCTL_API_KEY="test-key-123"
|
|
|
|
./mcp-server
|
|
```
|
|
|
|
Exposes 78 MCP tools covering the REST API via stdio transport. Ask Claude: "What certificates are expiring in the next 30 days?", "Revoke the payments cert due to key compromise", "Show me the audit trail."
|
|
|
|
## Demo Data Reference
|
|
|
|
| Resource | Count | Examples |
|
|
|----------|-------|---------|
|
|
| Teams | 5 | Platform, Security, Payments, Frontend, Data |
|
|
| Owners | 5 | Alice, Bob, Carol, Dave, Eve |
|
|
| Issuers | 4 | Local Dev CA, Let's Encrypt Staging, step-ca Internal, DigiCert (disabled) |
|
|
| Agents | 5 | ag-web-prod, ag-web-staging, ag-lb-prod, ag-iis-prod, ag-data-prod |
|
|
| Targets | 5 | NGINX (prod/staging/data), F5 LB, IIS |
|
|
| Certificates | 15 | Various statuses: Active, Expiring, Expired, Failed, Wildcard |
|
|
| Policies | 4 | Required owner, allowed environments, max lifetime, min renewal window |
|
|
| Profiles | 3 | Default TLS, Short-Lived, High-Security |
|
|
| Agent Groups | 5 | Linux agents, ARM agents, Production subnet, etc. |
|
|
|
|
## Dashboard Demo Mode
|
|
|
|
The dashboard works without a backend for screenshots and presentations:
|
|
|
|
```bash
|
|
cd web && npm install && npm run dev
|
|
# Dashboard at http://localhost:5173
|
|
```
|
|
|
|
When the API is unreachable, the dashboard loads realistic mock data with a "Demo Mode" badge.
|
|
|
|
## Presenting to Stakeholders
|
|
|
|
A suggested 5-minute flow:
|
|
|
|
1. **Dashboard** — "Certificate inventory at a glance. Real-time charts show expiration trends and renewal health."
|
|
2. **Expiring certs** — "These three would have caused outages. At 47-day lifespans, this happens every other week."
|
|
3. **Certificate detail** — "Full lifecycle: who owns it, where it's deployed, deployment timeline, version history with rollback."
|
|
4. **Revocation** — "One click revokes with an RFC 5280 reason code. CRL and OCSP served automatically."
|
|
5. **Failed renewal** — "System tried 3 times, then alerted the team via Slack, Teams, PagerDuty, or OpsGenie."
|
|
6. **Agent fleet** — "Agents handle key generation locally (ECDSA P-256). Private keys never leave your infrastructure."
|
|
7. **Discovery** — "Agents scan filesystems, server probes TLS endpoints. We find what you're not managing yet."
|
|
8. **Bulk operations** — "Select multiple certs, renew or revoke in bulk. At 47-day lifespans with hundreds of certs, this is essential."
|
|
9. **Audit trail** — "Every action recorded. Export to CSV/JSON for compliance."
|
|
10. **CLI + MCP** — "Terminal users get `certctl-cli`. AI assistants get MCP integration. Everything is API-first."
|
|
|
|
## Tear Down
|
|
|
|
```bash
|
|
docker compose -f deploy/docker-compose.yml down -v
|
|
```
|
|
|
|
The `-v` flag removes the PostgreSQL data volume for a clean slate.
|
|
|
|
## What's Next
|
|
|
|
- **[Advanced Demo](demo-advanced.md)** — Issue a real certificate via the Local CA end-to-end
|
|
- **[Architecture](architecture.md)** — How the control plane, agents, and connectors work together
|
|
- **[Connector Guide](connectors.md)** — Build custom connectors for your infrastructure
|
|
- **[Concepts Guide](concepts.md)** — TLS certificates, CAs, and private keys explained from scratch
|