mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 22:21:30 +00:00
527 lines
10 KiB
Markdown
527 lines
10 KiB
Markdown
# Certctl Quick Start Guide
|
|
|
|
Get a working certctl deployment from zero to managing certificates in 10 minutes.
|
|
|
|
## Prerequisites
|
|
|
|
- **Docker** and **Docker Compose** (recommended), or:
|
|
- Go 1.22+
|
|
- PostgreSQL 14+
|
|
- psql CLI tool
|
|
|
|
## Option 1: Docker Compose (Fastest)
|
|
|
|
### 1. Clone & Setup
|
|
|
|
```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
|
|
```
|
|
|
|
### 2. Start the Stack
|
|
|
|
```bash
|
|
make docker-up
|
|
|
|
# Wait for services to be healthy (~30 seconds)
|
|
docker-compose -f deploy/docker-compose.yml ps
|
|
```
|
|
|
|
You should see:
|
|
```
|
|
NAME STATUS
|
|
certctl-postgres Up (healthy)
|
|
certctl-server Up (healthy)
|
|
certctl-agent Up
|
|
```
|
|
|
|
### 3. Verify Health
|
|
|
|
```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)
|
|
|
|
Teams organize ownership and auditing. For this quick start, we'll use a default team.
|
|
|
|
```bash
|
|
TEAM_ID="default"
|
|
```
|
|
|
|
### 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`):
|
|
```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": [
|
|
{
|
|
"target_id": "target-def456",
|
|
"status": "success",
|
|
"deployed_at": "2024-03-14T10:30:30Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Step 8: View Audit Trail
|
|
|
|
See all actions related to your certificate:
|
|
|
|
```bash
|
|
curl -X GET "http://localhost:8443/api/v1/audit/logs?resource_id=$CERT_ID" \
|
|
-H "Content-Type: application/json"
|
|
```
|
|
|
|
Response:
|
|
```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"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Step 9: Trigger Manual Renewal (Optional)
|
|
|
|
To manually trigger certificate renewal:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8443/api/v1/certificates/$CERT_ID/renew \
|
|
-H "Content-Type: application/json"
|
|
```
|
|
|
|
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:
|
|
|
|
```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
|
|
```
|
|
|
|
---
|
|
|
|
## Testing the Flow End-to-End
|
|
|
|
Here's a complete script to test the full flow:
|
|
|
|
```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!"
|
|
```
|
|
|
|
Save as `test.sh`, make executable, and run:
|
|
```bash
|
|
chmod +x test.sh
|
|
./test.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Common Issues
|
|
|
|
### Server Won't Start
|
|
|
|
```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_
|
|
```
|
|
|
|
### Agent Can't Connect
|
|
|
|
```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
|
|
```
|
|
|
|
### Certificate Stays "Pending"
|
|
|
|
```bash
|
|
# Check if agent is registered
|
|
curl http://localhost:8443/api/v1/agents
|
|
|
|
# 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.
|