Rewrite README and .env.example to match actual implementation

README.md:
- Replace ASCII architecture diagram with Mermaid
- Fix all database table names (managed_certificates, audit_events, etc.)
- Fix env var names to use CERTCTL_ prefix matching config.go
- Fix API endpoint paths ({id} not :id, /audit not /audit/logs)
- Add all missing endpoints (renew, deploy, CSR, heartbeat, policies, notifications)
- Add dashboard as primary feature (was completely missing)
- Link to all new docs (concepts, advanced demo, architecture, connectors)
- Fix integration status (Local CA implemented, ACME in progress)
- Fix security section (API key auth, not mTLS)
- Remove broken links to non-existent docs (api.md, k8s-deployment.md, scaling.md)
- Remove placeholder Support & Community section

.env.example:
- Change all var names to CERTCTL_ prefix (CERTCTL_DATABASE_URL, etc.)
- Remove vars that don't exist in config.go (ACME_*, SMTP_*, feature flags)
- Add scheduler tuning vars as commented examples

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shankar0123
2026-03-14 22:01:34 -04:00
parent 8e17384983
commit c153361bbc
2 changed files with 238 additions and 340 deletions
+23 -56
View File
@@ -3,73 +3,40 @@
# DO NOT commit .env with real secrets to version control # DO NOT commit .env with real secrets to version control
# ============================================================================== # ==============================================================================
# PostgreSQL Database Configuration # PostgreSQL (used by Docker Compose for the postgres container)
# ============================================================================== # ==============================================================================
POSTGRES_DB=certctl POSTGRES_DB=certctl
POSTGRES_USER=certctl POSTGRES_USER=certctl
POSTGRES_PASSWORD=change-me-in-production POSTGRES_PASSWORD=change-me-in-production
POSTGRES_PORT=5432
# ============================================================================== # ==============================================================================
# Certctl Server Configuration # Certctl Server
# All server vars use the CERTCTL_ prefix (see internal/config/config.go)
# ============================================================================== # ==============================================================================
SERVER_HOST=0.0.0.0 CERTCTL_DATABASE_URL=postgres://certctl:certctl@postgres:5432/certctl?sslmode=disable
SERVER_PORT=8443 CERTCTL_SERVER_HOST=0.0.0.0
LOG_LEVEL=info CERTCTL_SERVER_PORT=8443
CERTCTL_LOG_LEVEL=info
CERTCTL_LOG_FORMAT=json
# Database connection string (alternative to individual vars) # Auth type: "api-key", "jwt", or "none" (for demo/development)
# DB_URL=postgres://certctl:password@localhost:5432/certctl?sslmode=disable CERTCTL_AUTH_TYPE=none
# Required when CERTCTL_AUTH_TYPE is "api-key" or "jwt"
# Generate with: openssl rand -base64 32
# CERTCTL_AUTH_SECRET=change-me-in-production
# ============================================================================== # ==============================================================================
# ACME Configuration # Certctl Agent
# ============================================================================== # ==============================================================================
# For Let's Encrypt production, use: https://acme-v02.api.letsencrypt.org/directory CERTCTL_SERVER_URL=http://localhost:8443
# For Let's Encrypt staging, use: https://acme-staging-v02.api.letsencrypt.org/directory CERTCTL_API_KEY=change-me-in-production
ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory CERTCTL_AGENT_NAME=local-agent
ACME_EMAIL=admin@example.com
# ============================================================================== # ==============================================================================
# SMTP Configuration (for email notifications) # Optional: Scheduler Tuning (defaults are usually fine)
# ============================================================================== # ==============================================================================
SMTP_HOST=smtp.example.com # CERTCTL_SCHEDULER_RENEWAL_CHECK_INTERVAL=1h
SMTP_PORT=587 # CERTCTL_SCHEDULER_JOB_PROCESSOR_INTERVAL=30s
SMTP_USERNAME=your-smtp-user # CERTCTL_SCHEDULER_AGENT_HEALTH_CHECK_INTERVAL=2m
SMTP_PASSWORD=your-smtp-password # CERTCTL_SCHEDULER_NOTIFICATION_PROCESS_INTERVAL=1m
SMTP_FROM_ADDRESS=certctl@example.com # CERTCTL_DATABASE_MAX_CONNS=25
# ==============================================================================
# Webhook Configuration (optional)
# ==============================================================================
WEBHOOK_URL=https://your-webhook-endpoint.example.com/notifications
WEBHOOK_SECRET=your-webhook-secret
# ==============================================================================
# Agent Configuration
# ==============================================================================
SERVER_URL=http://localhost:8443
AGENT_API_KEY=change-me-in-production
AGENT_NAME=local-agent
CHECK_INTERVAL=60s
# ==============================================================================
# PgAdmin Configuration (development only)
# ==============================================================================
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=admin
PGADMIN_PORT=5050
# ==============================================================================
# Security Settings
# ==============================================================================
# JWT secret for API authentication (generate with: openssl rand -base64 32)
JWT_SECRET=change-me-in-production
# Encryption key for sensitive data (generate with: openssl rand -base64 32)
ENCRYPTION_KEY=change-me-in-production
# ==============================================================================
# Feature Flags (optional)
# ==============================================================================
ENABLE_AUDIT_LOG=true
ENABLE_METRICS=true
ENABLE_TRACING=false
+215 -284
View File
@@ -1,383 +1,314 @@
# Certctl — Open-Source Certificate Control Plane # certctl — Open-Source Certificate Control Plane
A self-hosted, cloud-agnostic certificate management platform for teams. Manage issuance, deployment, and renewal of TLS certificates at scale with zero private key exposure in the control plane. A self-hosted certificate lifecycle platform. Track, renew, and deploy TLS certificates across your infrastructure with a web dashboard, REST API, and agent-based architecture where private keys never leave your servers.
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Go Report Card](https://goreportcard.com/badge/github.com/shankar0123/certctl)](https://goreportcard.com/report/github.com/shankar0123/certctl) [![Go Report Card](https://goreportcard.com/badge/github.com/shankar0123/certctl)](https://goreportcard.com/report/github.com/shankar0123/certctl)
![Status: Active Development](https://img.shields.io/badge/status-active%20development-green) ![Status: Active Development](https://img.shields.io/badge/status-active%20development-green)
## Overview ## What It Does
Certctl decouples certificate management into a control plane and lightweight agents deployed across your infrastructure. The control plane orchestrates issuance and renewal via multiple ACME issuers, while agents securely request, deploy, and renew certificates on target systems—all without exposing private keys outside the edge. certctl gives you a single pane of glass for every TLS certificate in your organization. The **web dashboard** shows your full certificate inventory — what's healthy, what's expiring, what's already expired, and who owns each one. The **REST API** (50+ endpoints) lets you automate everything. **Agents** deployed on your infrastructure handle key generation and certificate deployment without exposing private keys to the control plane.
### Why Certctl? ```mermaid
flowchart LR
subgraph "Control Plane"
API["REST API + Dashboard\n:8443"]
PG[("PostgreSQL")]
end
- **Decoupled architecture**: Control plane + edge agents, no SSH or privileged access required subgraph "Your Infrastructure"
- **Multi-issuer support**: ACME (Let's Encrypt, Sectigo, etc.), with extensible connector framework A1["Agent"] --> T1["NGINX"]
- **Zero private key exposure**: Keys generated and managed on agents, never sent to control plane A2["Agent"] --> T2["F5 BIG-IP"]
- **Audit-first design**: Every action logged with full traceability A3["Agent"] --> T3["IIS"]
- **Connector ecosystem**: Extensible issuer, target, and notifier connectors end
- **Self-hosted**: Run on Kubernetes, Docker Compose, or bare metal—no cloud lock-in
- **Production-ready**: Graceful error handling, observability, database-backed state API --> PG
A1 & A2 & A3 -->|"CSR + status\n(no private keys)"| API
API -->|"Signed certs"| A1 & A2 & A3
API -->|"Issue/Renew"| CA["Certificate Authorities\nLocal CA · ACME"]
```
## Quick Start ## Quick Start
### With Docker Compose (Recommended) ### Docker Compose (Recommended)
```bash ```bash
# Clone the repo
git clone https://github.com/shankar0123/certctl.git git clone https://github.com/shankar0123/certctl.git
cd certctl cd certctl
docker compose -f deploy/docker-compose.yml up -d
```
# Copy example environment variables Wait ~30 seconds, then open **http://localhost:8443** in your browser.
cp .env.example .env
# Start the stack The dashboard comes pre-loaded with 14 demo certificates, 5 agents, policy rules, audit events, and notifications — a realistic snapshot of a certificate inventory so you can explore immediately.
make docker-up
# Check health Verify the API:
```bash
curl http://localhost:8443/health curl http://localhost:8443/health
# {"status":"healthy"}
curl -s http://localhost:8443/api/v1/certificates | jq '.total'
# 14
``` ```
The stack includes PostgreSQL, certctl server, and a sample agent. Logs available via: ### Manual Build
```bash ```bash
make docker-logs-server # Prerequisites: Go 1.22+, PostgreSQL 16+
make docker-logs-agent
```
### Manual Build & Run
#### Prerequisites
- Go 1.22+
- PostgreSQL 14+
- (Optional) Docker & Docker Compose
#### Build from Source
```bash
# Install dependencies
go mod download go mod download
# Build binaries
make build make build
# Run migrations # Set up database
export DB_URL="postgres://certctl:certctl@localhost:5432/certctl?sslmode=disable" export CERTCTL_DATABASE_URL="postgres://certctl:certctl@localhost:5432/certctl?sslmode=disable"
export CERTCTL_AUTH_TYPE=none
make migrate-up make migrate-up
# Start server (in one terminal) # Start server
make run ./bin/server
# Start agent (in another terminal, with API key from server logs) # Start agent (separate terminal)
API_KEY="<key-from-server>" SERVER_URL=http://localhost:8443 ./bin/agent export CERTCTL_SERVER_URL=http://localhost:8443
export CERTCTL_API_KEY=change-me-in-production
export CERTCTL_AGENT_NAME=local-agent
./bin/agent
``` ```
## Documentation
| Guide | Description |
|-------|-------------|
| [Concepts](docs/concepts.md) | TLS certificates explained from scratch — for beginners who know nothing about certs |
| [Quick Start](docs/quickstart.md) | Get running in 5 minutes with accurate API examples |
| [Demo Walkthrough](docs/demo-guide.md) | 5-7 minute guided stakeholder presentation |
| [Advanced Demo](docs/demo-advanced.md) | Issue a certificate end-to-end with technical deep-dives |
| [Architecture](docs/architecture.md) | System design, data flow diagrams, security model |
| [Connectors](docs/connectors.md) | Build custom issuer, target, and notifier connectors |
## Architecture ## Architecture
### System Components ```mermaid
flowchart TB
subgraph "Control Plane (certctl-server)"
DASH["Web Dashboard\nReact SPA"]
API["REST API\nGo 1.22 net/http"]
SVC["Service Layer"]
REPO["Repository Layer\ndatabase/sql + lib/pq"]
SCHED["Scheduler\nRenewal · Jobs · Health · Notifications"]
end
``` subgraph "Data Store"
┌─────────────────────────────────────────────────────────┐ PG[("PostgreSQL 16\n14 tables · TEXT primary keys")]
│ CONTROL PLANE │ end
│ ┌──────────────────────────────────────────────────┐ │
│ │ API Server (8443) │ │ subgraph "Agents"
│ │ • Certificate management │ │ AG["certctl-agent\nKey generation · CSR · Deployment"]
│ │ • Issuance orchestration │ │ end
│ │ • Audit logging │ │
│ └──────────────────────────────────────────────────┘ │ DASH --> API
│ ┌──────────────────────────────────────────────────┐ │ API --> SVC --> REPO --> PG
│ │ PostgreSQL Database │ │ SCHED --> SVC
│ │ • Certificates, agents, targets, policies │ │ AG -->|"Heartbeat + CSR"| API
│ │ • Complete audit trail │ │ API -->|"Cert + Chain"| AG
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │
│ (mTLS + API Key) │
│ │
┌────┴────┐ ┌────────┴────┐
│ │ │ │
┌───┴──┐ ┌──┴───┐ ┌─────┴──┐ ┌──────┴────┐
│Agent │ │Agent │ │ Agent │ │ Agent │
│ #1 │ │ #2 │ │ #3 │ │ #N │
└──────┘ └──────┘ └────────┘ └───────────┘
│ │ │ │
├────┬────┼────┬───┬──┴─────┬─────┴──┬───┐
│ │ │ │ │ │ │ │
┌──┴─┐┌─┴──┐┌───┴──┐│┌───────┐│┌──────┐│ │
│ACME││K8s ││F5 ││Vault│ │Webhook│
│ ││LB ││LB ││ │ │
└────┘└────┘└────┘└────┘└──────┘
``` ```
### Data Flow: Certificate Issuance ### Key Design Decisions
1. **Create Certificate** → Control plane stores managed certificate record - **Private keys never touch the control plane.** Agents generate keys locally and submit CSRs (public key only). The control plane forwards CSRs to the CA and returns signed certificates. Even if the control plane database is compromised, no private keys are exposed.
2. **Generate CSR** → Agent creates private key (stays local) and CSR - **TEXT primary keys, not UUIDs.** IDs are human-readable prefixed strings (`mc-api-prod`, `t-platform`, `o-alice`) so you can identify resource types at a glance in logs and queries.
3. **Request Certificate** → Agent sends CSR to control plane - **Handler → Service → Repository layering.** Handlers define their own service interfaces for clean dependency inversion. No global service singletons.
4. **Issue via ACME** → Control plane submits to issuer (Let's Encrypt, etc.) - **Idempotent migrations.** All schema uses `IF NOT EXISTS` and seed data uses `ON CONFLICT (id) DO NOTHING`, safe for repeated execution.
5. **Return Certificate** → Agent receives signed cert, stores locally
6. **Deploy** → Agent pushes certificate to targets (NGINX, F5, IIS, etc.)
7. **Notify** → Webhook or email notification sent on completion
### Database Schema Overview ### Database Schema
| Entity | Purpose | | Table | Purpose |
|--------|---------| |-------|---------|
| `certificates` | Managed certificate records with metadata | | `managed_certificates` | Certificate records with metadata, status, expiry, tags |
| `agents` | Registered agents in the fleet | | `certificate_versions` | Historical versions with PEM chains and CSRs |
| `targets` | Deployment targets (NGINX, F5, IIS, etc.) | | `renewal_policies` | Renewal window, auto-renew settings, retry config |
| `issuers` | ACME issuer configurations | | `issuers` | CA configurations (Local CA, ACME, etc.) |
| `jobs` | Issuance and deployment jobs | | `deployment_targets` | Target systems (NGINX, F5, IIS) with agent assignments |
| `audit_logs` | Complete action trail | | `agents` | Registered agents with heartbeat tracking |
| `jobs` | Issuance, renewal, deployment, and validation jobs |
| `teams` | Organizational groups for certificate ownership |
| `owners` | Individual owners with email for notifications |
| `policy_rules` | Enforcement rules (allowed issuers, environments, metadata) |
| `policy_violations` | Flagged non-compliance with severity levels |
| `audit_events` | Immutable action log (append-only, no update/delete) |
| `notification_events` | Email and webhook notification records |
| `certificate_target_mappings` | Many-to-many cert ↔ target relationships |
## Configuration ## Configuration
### Environment Variables All server environment variables use the `CERTCTL_` prefix:
| Variable | Default | Description | | Variable | Default | Description |
|----------|---------|-------------| |----------|---------|-------------|
| `SERVER_HOST` | `0.0.0.0` | Server bind address | | `CERTCTL_SERVER_HOST` | `127.0.0.1` | Server bind address |
| `SERVER_PORT` | `8443` | Server listen port | | `CERTCTL_SERVER_PORT` | `8080` | Server listen port |
| `DB_HOST` | `localhost` | PostgreSQL host | | `CERTCTL_DATABASE_URL` | `postgres://localhost/certctl` | PostgreSQL connection string |
| `DB_PORT` | `5432` | PostgreSQL port | | `CERTCTL_DATABASE_MAX_CONNS` | `25` | Connection pool size |
| `DB_USER` | `certctl` | Database user | | `CERTCTL_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
| `DB_PASSWORD` | — | Database password | | `CERTCTL_LOG_FORMAT` | `json` | Log format: `json` or `text` |
| `DB_NAME` | `certctl` | Database name | | `CERTCTL_AUTH_TYPE` | `api-key` | Auth mode: `api-key`, `jwt`, or `none` |
| `LOG_LEVEL` | `info` | Log level (debug, info, warn, error) | | `CERTCTL_AUTH_SECRET` | — | Required for `api-key` and `jwt` auth types |
| `ACME_DIRECTORY_URL` | staging | ACME directory URL |
| `ACME_EMAIL` | — | ACME registration email |
| `SMTP_HOST` | — | SMTP server for email notifications |
| `SMTP_PORT` | `587` | SMTP port |
| `SMTP_USERNAME` | — | SMTP username |
| `SMTP_PASSWORD` | — | SMTP password |
| `SMTP_FROM_ADDRESS` | — | Email from address |
See `.env.example` for complete reference. Agent environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| `CERTCTL_SERVER_URL` | `http://localhost:8080` | Control plane URL |
| `CERTCTL_API_KEY` | — | Agent API key |
| `CERTCTL_AGENT_NAME` | `certctl-agent` | Agent display name |
Docker Compose overrides these for the demo stack (see `deploy/docker-compose.yml`): port `8443`, auth type `none`, database pointing to the postgres container.
## API Overview ## API Overview
### Key Endpoints All endpoints are under `/api/v1/` and return JSON. List endpoints support pagination (`?page=1&per_page=50`).
#### Certificates ### Certificates
- `POST /api/v1/certificates` — Create managed certificate ```
- `GET /api/v1/certificates` — List certificates GET /api/v1/certificates List (filter: status, environment, owner_id, team_id)
- `GET /api/v1/certificates/:id` — Get certificate details POST /api/v1/certificates Create
- `PUT /api/v1/certificates/:id` — Update certificate GET /api/v1/certificates/{id} Get
- `DELETE /api/v1/certificates/:id` — Archive certificate PUT /api/v1/certificates/{id} Update
DELETE /api/v1/certificates/{id} Archive (soft delete)
GET /api/v1/certificates/{id}/versions Version history
POST /api/v1/certificates/{id}/renew Trigger renewal → 202 Accepted
POST /api/v1/certificates/{id}/deploy Trigger deployment → 202 Accepted
```
#### Agents ### Agents
- `POST /api/v1/agents` — Register new agent ```
- `GET /api/v1/agents` — List agents GET /api/v1/agents List
- `GET /api/v1/agents/:id` — Get agent details POST /api/v1/agents Register
- `PUT /api/v1/agents/:id` — Update agent GET /api/v1/agents/{id} Get
POST /api/v1/agents/{id}/heartbeat Record heartbeat
POST /api/v1/agents/{id}/csr Submit CSR for issuance
GET /api/v1/agents/{id}/certificates/{certId} Retrieve signed certificate
```
#### Targets ### Infrastructure
- `POST /api/v1/targets` — Add deployment target ```
- `GET /api/v1/targets` — List targets GET /api/v1/issuers List issuers
- `PUT /api/v1/targets/:id` — Update target POST /api/v1/issuers Create
- `DELETE /api/v1/targets/:id` — Remove target GET /api/v1/issuers/{id} Get
POST /api/v1/issuers/{id}/test Test connectivity
#### Issuers GET /api/v1/targets List deployment targets
- `POST /api/v1/issuers` — Register ACME issuer POST /api/v1/targets Create
- `GET /api/v1/issuers` — List issuers GET /api/v1/targets/{id} Get
- `PUT /api/v1/issuers/:id` — Update issuer ```
#### Audit ### Organization
- `GET /api/v1/audit/logs` — Query audit trail ```
- `GET /api/v1/audit/logs/:id` — Get specific log entry GET /api/v1/teams List teams
POST /api/v1/teams Create
GET /api/v1/owners List owners
POST /api/v1/owners Create
```
#### System ### Operations
- `GET /health` — Health check ```
GET /api/v1/jobs List (filter: status, type)
GET /api/v1/jobs/{id} Get
POST /api/v1/jobs/{id}/cancel Cancel
Full API docs: [docs/api.md](docs/api.md) (coming soon) GET /api/v1/policies List policy rules
POST /api/v1/policies Create
GET /api/v1/policies/{id}/violations List violations for rule
## Agent Setup Guide GET /api/v1/audit Query audit trail
GET /api/v1/notifications List notifications
```
### Installation ### Health
```
Agents can be deployed as: GET /health Server health check
- **Docker container**: `docker pull certctl:agent` GET /ready Readiness check
- **Systemd service**: `systemctl start certctl-agent`
- **Kubernetes DaemonSet**: See [docs/k8s-deployment.md](docs/k8s-deployment.md)
### Configuration
Agents require:
1. **Server URL**: Control plane address (e.g., `https://certctl.example.com:8443`)
2. **API Key**: Issued by control plane on agent registration
3. **Agent Name**: Unique identifier in fleet
Example systemd unit:
```ini
[Unit]
Description=Certctl Agent
After=network.target
[Service]
Type=simple
ExecStart=/opt/certctl-agent/agent
Environment="SERVER_URL=https://certctl.example.com:8443"
Environment="API_KEY=ey..."
Environment="AGENT_NAME=prod-web-01"
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
``` ```
## Supported Integrations ## Supported Integrations
### Certificate Issuers ### Certificate Issuers
| Issuer | Status | Connector | | Issuer | Status | Type |
|--------|--------|-----------| |--------|--------|------|
| Let's Encrypt (ACME v2) | ✓ Production | `acme` | | Local CA (self-signed) | Implemented | `GenericCA` |
| Sectigo ACME | ✓ Tested | `acme` | | ACME v2 (Let's Encrypt, Sectigo) | In progress | `ACME` |
| Vault PKI | Planned | `vault` | | Vault PKI | Planned | |
| DigiCert | Planned | `digicert` | | DigiCert | Planned | |
### Deployment Targets ### Deployment Targets
| Target | Status | Connector | | Target | Status | Type |
|--------|--------|-----------| |--------|--------|------|
| NGINX | ✓ Production | `nginx` | | NGINX | Implemented | `NGINX` |
| F5 BIG-IP | ✓ Tested | `f5` | | F5 BIG-IP | Implemented | `F5` |
| Microsoft IIS | ✓ Tested | `iis` | | Microsoft IIS | Implemented | `IIS` |
| Kubernetes Secrets | Planned | `k8s` | | Kubernetes Secrets | Planned | |
| AWS CloudFront | ◐ Planned | `aws` |
### Notifiers ### Notifiers
| Notifier | Status | Connector | | Notifier | Status | Type |
|----------|--------|-----------| |----------|--------|------|
| Email (SMTP) | ✓ Production | `email` | | Email (SMTP) | Implemented | `Email` |
| Webhooks | ✓ Production | `webhook` | | Webhooks | Implemented | `Webhook` |
| Slack | Planned | `slack` | | Slack | Planned | |
| PagerDuty | ◐ Planned | `pagerduty` |
## Development ## Development
### Local Setup
```bash ```bash
# Install dev tools (golangci-lint, migrate CLI, air)
make install-tools make install-tools
cp .env.example .env
make docker-up-dev
# Access PgAdmin at http://localhost:5050 # Run tests
# Server logs: make docker-logs-server
```
### Testing
```bash
# Run all tests
make test make test
# Run with coverage # Run with coverage
make test-coverage make test-coverage
# Run specific package # Lint
go test -v ./internal/service/... make lint
# Format
make fmt
``` ```
### Linting & Format ### Docker Compose
```bash ```bash
make lint make docker-up # Start stack (server + postgres + agent)
make fmt make docker-down # Stop stack
make vet make docker-logs-server # Server logs
make docker-logs-agent # Agent logs
make docker-clean # Stop + remove volumes
``` ```
### Building Connectors
See [docs/connectors.md](docs/connectors.md) for a step-by-step guide to building issuers, targets, and notifier connectors.
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Commit changes: `git commit -am 'Add feature'`
4. Push to branch: `git push origin feature/my-feature`
5. Open a pull request
### Code Standards
- Go 1.22+ with `go fmt`, `go vet`, `golangci-lint`
- Tests required for new features (>80% coverage)
- Clear commit messages
- Update relevant documentation
## Security ## Security
### Private Key Management ### Private Key Management
- Private keys **never** sent to control plane - Private keys are generated exclusively on agents, never sent to the control plane
- Keys generated and managed exclusively on agents - Keys stored with file permissions 0600
- Encrypted at rest on agent systems - Old keys deleted after successful certificate renewal
- Cleared from memory after use
### Authentication ### Authentication
- Agent-to-server: mTLS + API key - Agent-to-server: API key (registered at agent creation)
- API key rotation supported - API key and JWT auth types supported; `none` for demo/development
- Audit logging of all authenticated actions - Auth type and secret configured via `CERTCTL_AUTH_TYPE` and `CERTCTL_AUTH_SECRET`
### Audit Trail ### Audit Trail
- Complete action history in PostgreSQL - Immutable append-only log in PostgreSQL (`audit_events` table)
- Immutable audit logs - Every action attributed to an actor with timestamp and resource reference
- Queryable by resource, user, timestamp, action - No update or delete operations on audit records
For security issues, email security@example.com (do not open public issues).
## Performance & Scaling
- **Agents**: Stateless, horizontal scaling via fleet management
- **Control Plane**: Single server handles 1000+ agents
- **Database**: PostgreSQL; vertical scaling recommended
- **Jobs**: Asynchronous processing; tunable concurrency
See [docs/scaling.md](docs/scaling.md) for deployment guidance.
## Troubleshooting
### Server Won't Start
```bash
# Check database connection
psql -h localhost -U certctl -d certctl
# Check logs
make docker-logs-server
# Verify environment variables
env | grep -E "DB_|SERVER_|ACME_"
```
### Agent Can't Connect
```bash
# Check server health
curl -v https://certctl.example.com:8443/health
# Verify API key
echo $API_KEY
# Check agent logs
make docker-logs-agent
```
### Certificate Not Deploying
1. Check agent is registered: `curl http://localhost:8443/api/v1/agents`
2. Check target is reachable: `curl http://target-server:22` (SSH test)
3. Review audit log: `curl http://localhost:8443/api/v1/audit/logs`
## Roadmap ## Roadmap
- [ ] Kubernetes CRD for certificate management Summary:
- [ ] Terraform provider
- [ ] Multi-region deployment - **V1 (current)**: Dashboard, inventory, alerting, Local CA + ACME issuers, NGINX/F5/IIS targets, agents, REST API, policies, audit trail, Docker Compose
- [ ] HA control plane with etcd backend - **V2**: Charts/trends, bulk import, OIDC/SSO, deployment rollback, CLI, Slack/Teams
- [ ] Advanced scheduling policies - **V3**: Certificate discovery, network scanning, unknown cert detection
- [ ] Certificate pinning validation - **V4+**: Kubernetes CRD, Terraform provider, multi-region, HA control plane, HSM support
- [ ] Hardware security module (HSM) support
## License ## License
Certctl is licensed under the [Apache License 2.0](LICENSE). See LICENSE file for details. Certctl is licensed under the [Apache License 2.0](LICENSE). See LICENSE file for details.