mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 14:11:31 +00:00
Fix runtime bugs, implement service layer, and overhaul documentation
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>
This commit is contained in:
+148
-452
@@ -1,36 +1,32 @@
|
||||
# Certctl Quick Start Guide
|
||||
# Quick Start Guide
|
||||
|
||||
Get a working certctl deployment from zero to managing certificates in 10 minutes.
|
||||
Get certctl running locally and managing certificates in under 5 minutes.
|
||||
|
||||
New to certificates? Read the [Concepts Guide](concepts.md) first — it explains TLS, CAs, and private keys in plain language.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Docker** and **Docker Compose** (recommended), or:
|
||||
- Go 1.22+
|
||||
- PostgreSQL 14+
|
||||
- psql CLI tool
|
||||
You need **Docker** and **Docker Compose** installed. That's it.
|
||||
|
||||
## Option 1: Docker Compose (Fastest)
|
||||
On macOS:
|
||||
```bash
|
||||
brew install --cask docker
|
||||
```
|
||||
|
||||
### 1. Clone & Setup
|
||||
On Linux, follow the official Docker install guide for your distribution.
|
||||
|
||||
## Start Everything
|
||||
|
||||
```bash
|
||||
git clone https://github.com/shankar0123/certctl.git
|
||||
cd certctl
|
||||
|
||||
# Copy environment template
|
||||
cp .env.example .env
|
||||
|
||||
# Optional: edit .env for custom settings
|
||||
# nano .env
|
||||
docker compose -f deploy/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
### 2. Start the Stack
|
||||
Wait about 30 seconds for PostgreSQL to initialize and the server to boot. Check that everything is healthy:
|
||||
|
||||
```bash
|
||||
make docker-up
|
||||
|
||||
# Wait for services to be healthy (~30 seconds)
|
||||
docker-compose -f deploy/docker-compose.yml ps
|
||||
docker compose -f deploy/docker-compose.yml ps
|
||||
```
|
||||
|
||||
You should see:
|
||||
@@ -41,486 +37,186 @@ certctl-server Up (healthy)
|
||||
certctl-agent Up
|
||||
```
|
||||
|
||||
### 3. Verify Health
|
||||
|
||||
Verify the server responds:
|
||||
```bash
|
||||
# Server health check
|
||||
curl http://localhost:8443/health
|
||||
# Expected: {"status":"healthy"}
|
||||
|
||||
# Container logs
|
||||
make docker-logs-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Option 2: Manual Build & Run
|
||||
|
||||
### 1. Clone & Dependencies
|
||||
|
||||
```bash
|
||||
git clone https://github.com/shankar0123/certctl.git
|
||||
cd certctl
|
||||
|
||||
go mod download
|
||||
```
|
||||
|
||||
### 2. Setup PostgreSQL
|
||||
|
||||
```bash
|
||||
# Create database and user
|
||||
psql -U postgres -h localhost << EOF
|
||||
CREATE USER certctl WITH PASSWORD 'certctl';
|
||||
CREATE DATABASE certctl OWNER certctl;
|
||||
GRANT ALL PRIVILEGES ON DATABASE certctl TO certctl;
|
||||
EOF
|
||||
|
||||
# Verify connection
|
||||
psql -h localhost -U certctl -d certctl -c "SELECT 1"
|
||||
```
|
||||
|
||||
### 3. Run Migrations
|
||||
|
||||
```bash
|
||||
# Install migrate tool
|
||||
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
||||
|
||||
# Set database URL
|
||||
export DB_URL="postgres://certctl:certctl@localhost:5432/certctl?sslmode=disable"
|
||||
|
||||
# Run migrations
|
||||
make migrate-up
|
||||
```
|
||||
|
||||
### 4. Start Server
|
||||
|
||||
```bash
|
||||
# Terminal 1: Server
|
||||
make run
|
||||
|
||||
# Expected output:
|
||||
# 2024-03-14T10:30:00Z server starting version=1.0.0 server_port=8443
|
||||
```
|
||||
|
||||
### 5. Start Agent (Optional)
|
||||
|
||||
```bash
|
||||
# Terminal 2: Agent
|
||||
export SERVER_URL=http://localhost:8443
|
||||
export API_KEY=default-api-key
|
||||
./bin/agent
|
||||
|
||||
# Expected output: Agent connecting to http://localhost:8443
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Walk-Through: Create Your First Certificate
|
||||
|
||||
### Step 1: Verify API Access
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8443/health
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{"status":"healthy"}
|
||||
```
|
||||
|
||||
### Step 2: Create a Team (Optional)
|
||||
## Open the Dashboard
|
||||
|
||||
Teams organize ownership and auditing. For this quick start, we'll use a default team.
|
||||
Open **http://localhost:8443** in your browser.
|
||||
|
||||
The dashboard comes pre-loaded with 14 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
|
||||
|
||||
```bash
|
||||
TEAM_ID="default"
|
||||
curl -s http://localhost:8443/api/v1/certificates | jq .
|
||||
```
|
||||
|
||||
### Step 3: Register an ACME Issuer
|
||||
|
||||
Create a certificate issuer configuration (Let's Encrypt staging for this demo):
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8443/api/v1/issuers \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "default",
|
||||
"name": "lets-encrypt-staging",
|
||||
"type": "acme",
|
||||
"config": {
|
||||
"directory_url": "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||
"email": "admin@example.com"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
Response (save the `issuer_id`):
|
||||
The response has this shape:
|
||||
```json
|
||||
{
|
||||
"id": "issuer-abc123",
|
||||
"name": "lets-encrypt-staging",
|
||||
"type": "acme",
|
||||
"created_at": "2024-03-14T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Store the issuer ID:
|
||||
```bash
|
||||
ISSUER_ID="issuer-abc123"
|
||||
```
|
||||
|
||||
### Step 4: Register an Agent
|
||||
|
||||
Agents handle certificate requests and deployment. Register one:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8443/api/v1/agents \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "default",
|
||||
"name": "quickstart-agent",
|
||||
"description": "Local development agent"
|
||||
}'
|
||||
```
|
||||
|
||||
Response (save the `api_key` and `id`):
|
||||
```json
|
||||
{
|
||||
"id": "agent-xyz789",
|
||||
"name": "quickstart-agent",
|
||||
"api_key": "ey...",
|
||||
"registered_at": "2024-03-14T10:30:00Z",
|
||||
"status": "registered"
|
||||
}
|
||||
```
|
||||
|
||||
Store the agent details:
|
||||
```bash
|
||||
AGENT_ID="agent-xyz789"
|
||||
AGENT_API_KEY="ey..."
|
||||
```
|
||||
|
||||
### Step 5: Create a Deployment Target
|
||||
|
||||
Targets are where certificates will be deployed (NGINX, F5, etc.). For this demo, we'll skip actual deployment:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8443/api/v1/targets \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "default",
|
||||
"agent_id": "'$AGENT_ID'",
|
||||
"name": "example-nginx",
|
||||
"type": "nginx",
|
||||
"config": {
|
||||
"host": "nginx.example.com",
|
||||
"ssh_user": "deploy",
|
||||
"ssh_key": "/path/to/key",
|
||||
"cert_path": "/etc/nginx/ssl"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"id": "target-def456",
|
||||
"name": "example-nginx",
|
||||
"agent_id": "agent-xyz789",
|
||||
"type": "nginx",
|
||||
"status": "pending_validation"
|
||||
}
|
||||
```
|
||||
|
||||
Store the target ID:
|
||||
```bash
|
||||
TARGET_ID="target-def456"
|
||||
```
|
||||
|
||||
### Step 6: Create a Managed Certificate
|
||||
|
||||
Now the main event—request a certificate to be issued and managed:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8443/api/v1/certificates \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "default",
|
||||
"domain": "api.example.com",
|
||||
"issuer_id": "'$ISSUER_ID'",
|
||||
"target_ids": ["'$TARGET_ID'"],
|
||||
"renewal_days_before": 30,
|
||||
"auto_deploy": true
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"id": "cert-ghi012",
|
||||
"domain": "api.example.com",
|
||||
"issuer_id": "issuer-abc123",
|
||||
"status": "pending",
|
||||
"created_at": "2024-03-14T10:30:00Z",
|
||||
"expires_at": null,
|
||||
"renewal_at": null
|
||||
}
|
||||
```
|
||||
|
||||
Store the certificate ID:
|
||||
```bash
|
||||
CERT_ID="cert-ghi012"
|
||||
```
|
||||
|
||||
### Step 7: Check Certificate Status
|
||||
|
||||
Poll the certificate status as issuance progresses:
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8443/api/v1/certificates/$CERT_ID \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
Response (will change over time):
|
||||
```json
|
||||
{
|
||||
"id": "cert-ghi012",
|
||||
"domain": "api.example.com",
|
||||
"status": "issued",
|
||||
"expires_at": "2024-06-12T10:30:00Z",
|
||||
"issued_by": "issuer-abc123",
|
||||
"deployed_to": [
|
||||
"data": [
|
||||
{
|
||||
"target_id": "target-def456",
|
||||
"status": "success",
|
||||
"deployed_at": "2024-03-14T10:30:30Z"
|
||||
"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": 14,
|
||||
"page": 1,
|
||||
"per_page": 50
|
||||
}
|
||||
```
|
||||
|
||||
### Step 8: View Audit Trail
|
||||
|
||||
See all actions related to your certificate:
|
||||
### Filter by status
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8443/api/v1/audit/logs?resource_id=$CERT_ID" \
|
||||
-H "Content-Type: application/json"
|
||||
# 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 .
|
||||
```
|
||||
|
||||
Response:
|
||||
### Get a specific certificate
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8443/api/v1/certificates/mc-api-prod | jq .
|
||||
```
|
||||
|
||||
### List agents
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8443/api/v1/agents | jq .
|
||||
```
|
||||
|
||||
### View audit trail
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8443/api/v1/audit | jq .
|
||||
```
|
||||
|
||||
### View policy rules
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8443/api/v1/policies | jq .
|
||||
```
|
||||
|
||||
### View notifications
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```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 .
|
||||
```
|
||||
|
||||
The server returns the created certificate with an auto-generated ID:
|
||||
```json
|
||||
{
|
||||
"logs": [
|
||||
{
|
||||
"id": "audit-001",
|
||||
"timestamp": "2024-03-14T10:30:00Z",
|
||||
"actor": {
|
||||
"type": "api",
|
||||
"id": "client-001"
|
||||
},
|
||||
"action": "certificate_created",
|
||||
"resource": {
|
||||
"type": "certificate",
|
||||
"id": "cert-ghi012"
|
||||
},
|
||||
"status": "success"
|
||||
},
|
||||
{
|
||||
"id": "audit-002",
|
||||
"timestamp": "2024-03-14T10:30:10Z",
|
||||
"actor": {
|
||||
"type": "agent",
|
||||
"id": "agent-xyz789"
|
||||
},
|
||||
"action": "certificate_issued",
|
||||
"resource": {
|
||||
"type": "certificate",
|
||||
"id": "cert-ghi012"
|
||||
},
|
||||
"status": "success",
|
||||
"details": {
|
||||
"issuer": "lets-encrypt-staging",
|
||||
"expiry": "2024-06-12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "audit-003",
|
||||
"timestamp": "2024-03-14T10:30:25Z",
|
||||
"actor": {
|
||||
"type": "system",
|
||||
"id": "scheduler"
|
||||
},
|
||||
"action": "certificate_deployed",
|
||||
"resource": {
|
||||
"type": "certificate",
|
||||
"id": "cert-ghi012"
|
||||
},
|
||||
"status": "success",
|
||||
"details": {
|
||||
"deployed_to": "example-nginx"
|
||||
}
|
||||
}
|
||||
]
|
||||
"id": "a1b2c3d4-...",
|
||||
"name": "My First Certificate",
|
||||
"common_name": "myapp.example.com",
|
||||
"status": "Pending",
|
||||
"created_at": "2026-03-14T..."
|
||||
}
|
||||
```
|
||||
|
||||
### Step 9: Trigger Manual Renewal (Optional)
|
||||
|
||||
To manually trigger certificate renewal:
|
||||
|
||||
Save the certificate ID:
|
||||
```bash
|
||||
curl -X POST http://localhost:8443/api/v1/certificates/$CERT_ID/renew \
|
||||
-H "Content-Type: application/json"
|
||||
CERT_ID="<paste the id from the response>"
|
||||
```
|
||||
|
||||
The scheduler will automatically check for renewals every hour. Certificates within 30 days of expiry are renewed automatically.
|
||||
|
||||
---
|
||||
|
||||
## Development Mode
|
||||
|
||||
For development with hot reload and database browser:
|
||||
### Step 2: Trigger renewal
|
||||
|
||||
```bash
|
||||
# Install tools
|
||||
make install-tools
|
||||
|
||||
# Start dev stack (includes PgAdmin at localhost:5050)
|
||||
make docker-up-dev
|
||||
|
||||
# View logs
|
||||
make docker-logs-server
|
||||
make docker-logs-agent
|
||||
|
||||
# Admin credentials for PgAdmin:
|
||||
# Email: admin@example.com (default, see .env)
|
||||
# Password: admin (default, see .env)
|
||||
|
||||
# Access PgAdmin: http://localhost:5050
|
||||
# Add server: postgres, port 5432, user certctl, password certctl
|
||||
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.
|
||||
|
||||
## Testing the Flow End-to-End
|
||||
|
||||
Here's a complete script to test the full flow:
|
||||
### Step 3: Check the certificate
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
API="http://localhost:8443"
|
||||
TEAM="default"
|
||||
|
||||
echo "1. Creating ACME issuer..."
|
||||
ISSUER=$(curl -s -X POST $API/api/v1/issuers \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "'$TEAM'",
|
||||
"name": "letsencrypt-staging",
|
||||
"type": "acme",
|
||||
"config": {
|
||||
"directory_url": "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||
"email": "test@example.com"
|
||||
}
|
||||
}' | jq -r '.id')
|
||||
|
||||
echo " Issuer: $ISSUER"
|
||||
|
||||
echo "2. Registering agent..."
|
||||
AGENT=$(curl -s -X POST $API/api/v1/agents \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "'$TEAM'",
|
||||
"name": "test-agent"
|
||||
}' | jq -r '.id')
|
||||
|
||||
echo " Agent: $AGENT"
|
||||
|
||||
echo "3. Creating certificate..."
|
||||
CERT=$(curl -s -X POST $API/api/v1/certificates \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"team_id": "'$TEAM'",
|
||||
"domain": "test-'$(date +%s)'.example.com",
|
||||
"issuer_id": "'$ISSUER'",
|
||||
"renewal_days_before": 30
|
||||
}' | jq -r '.id')
|
||||
|
||||
echo " Certificate: $CERT"
|
||||
|
||||
echo "4. Checking status..."
|
||||
curl -s -X GET $API/api/v1/certificates/$CERT | jq '.status'
|
||||
|
||||
echo "5. Viewing audit trail..."
|
||||
curl -s -X GET "$API/api/v1/audit/logs?resource_id=$CERT" | jq '.logs | length'
|
||||
|
||||
echo "Done!"
|
||||
curl -s http://localhost:8443/api/v1/certificates/$CERT_ID | jq .
|
||||
```
|
||||
|
||||
Save as `test.sh`, make executable, and run:
|
||||
```bash
|
||||
chmod +x test.sh
|
||||
./test.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Server Won't Start
|
||||
### Step 4: Check the audit trail
|
||||
|
||||
```bash
|
||||
# Check database connection
|
||||
psql -h localhost -U certctl -d certctl -c "SELECT 1"
|
||||
|
||||
# View logs
|
||||
make docker-logs-server
|
||||
|
||||
# Check environment
|
||||
env | grep DB_
|
||||
curl -s http://localhost:8443/api/v1/audit | jq '.data[0:3]'
|
||||
```
|
||||
|
||||
### Agent Can't Connect
|
||||
Refresh the dashboard at http://localhost:8443 — your new certificate appears in the inventory.
|
||||
|
||||
## 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 | 3 | Local Dev CA, Let's Encrypt Staging, DigiCert |
|
||||
| Agents | 5 | nginx-prod, nginx-staging, f5-prod, iis-prod, data-agent |
|
||||
| Targets | 5 | NGINX (prod/staging/data), F5 LB, IIS |
|
||||
| Certificates | 14 | Various statuses: Active, Expiring, Expired, Failed |
|
||||
| Policies | 4 | Required owner, allowed environments, max lifetime, min renewal window |
|
||||
|
||||
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.
|
||||
|
||||
## Tear Down
|
||||
|
||||
```bash
|
||||
# Verify server is running
|
||||
curl http://localhost:8443/health
|
||||
|
||||
# Check agent logs
|
||||
docker logs certctl-agent
|
||||
|
||||
# Verify API key is correct
|
||||
echo $AGENT_API_KEY
|
||||
docker compose -f deploy/docker-compose.yml down -v
|
||||
```
|
||||
|
||||
### Certificate Stays "Pending"
|
||||
The `-v` flag removes the PostgreSQL data volume so you get a clean slate next time.
|
||||
|
||||
```bash
|
||||
# Check if agent is registered
|
||||
curl http://localhost:8443/api/v1/agents
|
||||
## What's Next
|
||||
|
||||
# Check agent logs for errors
|
||||
make docker-logs-agent
|
||||
|
||||
# View certificate details
|
||||
curl http://localhost:8443/api/v1/certificates/$CERT_ID
|
||||
|
||||
# Check audit trail
|
||||
curl "http://localhost:8443/api/v1/audit/logs?resource_id=$CERT_ID"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Read** [docs/architecture.md](architecture.md) to understand the design
|
||||
2. **Explore** the [API](../README.md#api-overview) for more operations
|
||||
3. **Build** a [custom connector](connectors.md) for your infrastructure
|
||||
4. **Deploy** to production using [docs/k8s-deployment.md](k8s-deployment.md) (coming soon)
|
||||
|
||||
---
|
||||
|
||||
For more help, see [README.md](../README.md#troubleshooting) or open an issue on GitHub.
|
||||
- **[Advanced Demo](demo-advanced.md)** — Issue a real certificate via the Local CA and watch it appear in the dashboard
|
||||
- **[Demo Walkthrough](demo-guide.md)** — Guided 5-minute stakeholder presentation
|
||||
- **[Architecture](architecture.md)** — How the control plane, agents, and connectors work together
|
||||
- **[Connector Guide](connectors.md)** — Build custom connectors for your infrastructure
|
||||
|
||||
Reference in New Issue
Block a user