Files
certctl/docs/quickstart.md
T
shankar0123 4f90be9311 feat: add network certificate discovery (M21) and Prometheus metrics (M22)
M21 adds server-side active TLS scanning of CIDR ranges with concurrent
probing, sentinel agent pattern for pipeline reuse, and full CRUD API for
scan targets. M22 adds Prometheus exposition format endpoint alongside
existing JSON metrics. Comprehensive documentation audit updates all docs
to reflect 91 endpoints, 19 tables, 6 scheduler loops, and 900+ tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 23:37:47 -04:00

12 KiB

Quick Start Guide

Get certctl running locally and managing certificates in under 5 minutes. With TLS certificate lifespans dropping to 47 days by 2029, automated lifecycle management isn't optional — it's infrastructure. This guide gets you hands-on with certctl's automation loop: tracking, renewing, and deploying certificates without manual intervention.

New to certificates? Read the Concepts Guide first — it explains TLS, CAs, and private keys in plain language.

Prerequisites

You need Docker and Docker Compose installed. That's it.

On macOS:

brew install --cask docker

On Linux, follow the official Docker install guide for your distribution.

Start Everything

git clone https://github.com/shankar0123/certctl.git
cd certctl
docker compose -f deploy/docker-compose.yml up -d --build

The --build flag is important — it builds the server image including the React frontend. Without it, Docker may use a stale cached image that doesn't include the dashboard.

For production deployments, copy deploy/.env.example to deploy/.env and customize the credentials:

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 and the server to boot. Check that everything is healthy:

docker compose -f deploy/docker-compose.yml ps

You should see:

NAME                 STATUS
certctl-postgres     Up (healthy)
certctl-server       Up (healthy)
certctl-agent        Up

Verify the server responds:

curl http://localhost:8443/health
{"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. You'll see expiring certs, expired certs, active certs, failed renewals — a realistic snapshot of what a certificate inventory looks like in a real organization.

Explore the sidebar: Certificates, Agents, Policies, Jobs, Audit Trail, Notifications. Everything you see in the dashboard is backed by the REST API.

Explore the API

The dashboard reads from the same REST API you can call directly. All endpoints live under /api/v1/ and return JSON.

List all certificates

curl -s http://localhost:8443/api/v1/certificates | jq .

The response has this shape:

{
  "data": [
    {
      "id": "mc-api-prod",
      "name": "API Production",
      "common_name": "api.example.com",
      "sans": ["api.example.com", "api-v2.example.com"],
      "environment": "production",
      "owner_id": "o-alice",
      "team_id": "t-platform",
      "issuer_id": "iss-local",
      "status": "Active",
      "expires_at": "2026-05-28T00:00:00Z",
      "tags": {"service": "api-gateway", "tier": "critical"},
      "created_at": "2026-03-14T00:00:00Z",
      "updated_at": "2026-03-14T00:00:00Z"
    }
  ],
  "total": 15,
  "page": 1,
  "per_page": 50
}

Filter by status

# Get only expiring certificates
curl -s "http://localhost:8443/api/v1/certificates?status=Expiring" | jq .

# Get only production certificates
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 .

List agents

curl -s http://localhost:8443/api/v1/agents | jq .

Check agent pending work

# Replace with an actual agent ID from the list above
curl -s http://localhost:8443/api/v1/agents/agent-nginx-prod/work | jq .

View audit trail

curl -s http://localhost:8443/api/v1/audit | jq .

View policy rules

curl -s http://localhost:8443/api/v1/policies | jq .

View notifications

curl -s http://localhost:8443/api/v1/notifications | jq .

Create Your First Certificate

Let's create a new managed certificate from scratch using the API. This will create a certificate record that certctl will track, renew, and deploy.

Step 1: Create a certificate

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 .

The server returns the created certificate. Since we didn't include an id field, the server auto-generates one using the name and a timestamp:

{
  "id": "My First Certificate-1710403200000000000",
  "name": "My First Certificate",
  "common_name": "myapp.example.com",
  "status": "Pending",
  "created_at": "2026-03-14T..."
}

Save the certificate ID (or provide your own id in the request body, e.g. "id": "mc-my-first"):

CERT_ID="<paste the id from the response>"

Step 2: Trigger renewal

curl -s -X POST http://localhost:8443/api/v1/certificates/$CERT_ID/renew | jq .

This creates a renewal job that will be processed by the scheduler.

Step 3: Check the certificate

curl -s http://localhost:8443/api/v1/certificates/$CERT_ID | jq .

Step 4: Check the audit trail

curl -s http://localhost:8443/api/v1/audit | jq '.data[0:3]'

Refresh the dashboard at http://localhost:8443 — your new certificate appears in the inventory.

Step 5: Revoke a certificate

If a certificate's private key is compromised or the service is decommissioned, revoke it:

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. If you omit the reason, it defaults to unspecified.

Check the CRL to confirm:

curl -s http://localhost:8443/api/v1/crl | jq .

Understanding the Demo Data

The demo comes pre-loaded with realistic data so you can explore certctl's features immediately:

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 nginx-prod, nginx-staging, f5-prod, iis-prod, data-agent
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.

Certificates have varied statuses so you can see what each state looks like in the dashboard: healthy certs with 45+ days remaining, certs about to expire (5-12 days), certs that already expired, and a failed renewal.

Advanced API Features

Sorting and filtering

# Sort certificates 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 format)
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 .

Supported sort fields: notAfter, expiresAt, createdAt, updatedAt, commonName, name, status, environment.

Sparse field selection

Request only the fields you need to reduce response size:

curl -s "http://localhost:8443/api/v1/certificates?fields=id,common_name,status,expires_at" | jq .

Cursor-based pagination

For large datasets, cursor pagination is more efficient than page-based:

# First page
curl -s "http://localhost:8443/api/v1/certificates?page_size=5" | jq '{next_cursor: .next_cursor, count: (.data | length)}'

# Next page (use the next_cursor from the previous response)
curl -s "http://localhost:8443/api/v1/certificates?cursor=<next_cursor_value>&page_size=5" | jq .

Stats and metrics

# 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 .

# System metrics (JSON)
curl -s http://localhost:8443/api/v1/metrics | jq .

# System metrics (Prometheus format — for scraping by Prometheus, Grafana Agent, Datadog)
curl -s http://localhost:8443/api/v1/metrics/prometheus

Certificate profiles

# List all profiles
curl -s http://localhost:8443/api/v1/profiles | jq .

# Get a specific profile
curl -s http://localhost:8443/api/v1/profiles/prof-default | jq .

Certificate deployments

# View deployment targets for a certificate
curl -s http://localhost:8443/api/v1/certificates/mc-api-prod/deployments | jq .

Interactive approval workflow

# 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 .

Tear Down

docker compose -f deploy/docker-compose.yml down -v

The -v flag removes the PostgreSQL data volume so you get a clean slate next time.

Certificate Discovery

Agents can scan your infrastructure for existing certificates you're not yet managing:

# 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, reports findings to control plane

Query discovered certificates:

# List all discovered certs from a specific agent
curl -s "http://localhost:8443/api/v1/discovered-certificates?agent_id=agent-nginx-prod" | jq .

# Get discovery summary (counts by status)
curl -s http://localhost:8443/api/v1/discovery-summary | jq .

# Claim a discovered cert (link to managed cert)
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 .

Network Certificate Discovery

The server can also discover certificates by scanning TLS endpoints directly — no agent required:

# Enable network scanning (set in environment or docker-compose)
export CERTCTL_NETWORK_SCAN_ENABLED=true

# Create a scan target (e.g., scan your internal network on port 443)
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 .

# List scan targets with results
curl -s http://localhost:8443/api/v1/network-scan-targets | jq .

Discovered network certificates appear in the same GET /api/v1/discovered-certificates list as filesystem-discovered certs, with agent_id=server-scanner and source_format=network.

What's Next

  • Advanced Demo — Issue a real certificate via the Local CA and watch it appear in the dashboard
  • Demo Walkthrough — Guided 5-minute stakeholder presentation
  • Architecture — How the control plane, agents, and connectors work together
  • Connector Guide — Build custom connectors for your infrastructure
  • CLI Reference — Manage certificates from your terminal