8.1 KiB
Step-CA Docker Stack
A Docker Compose setup for deploying Smallstep CA (step-ca) with PostgreSQL backend support for certificate management and PKI infrastructure.
Features
- Automated Initialization: Automatic step-ca setup with optional SSH and ACME support
- PostgreSQL Backend: Uses PostgreSQL as the primary database (replacing the default Badger)
- Health Checks: Built-in health checks for PostgreSQL service
- Customizable Configuration: Full environment variable support for customization
- Docker Build: Custom Dockerfile with jq for JSON manipulation
- Remote Management: Support for remote management capabilities
- Admin Provisioner: Built-in JWK admin provisioner for certificate issuance
Prerequisites
- Docker
- Docker Compose
- Basic knowledge of step-ca and PKI concepts
Quick Start
1. Clone and Setup
cd /path/to/step-ca
cp .env.example .env
# Edit .env with your specific configuration
2. Configure Environment
Edit .env file with your desired configuration:
# PostgreSQL Configuration
POSTGRES_PASSWORD=your_secure_password
# Step-CA Configuration
STEP_CA_IP=192.168.1.100
STEP_CA_PORT=9000
STEP_CA_NAME=My Internal CA
STEP_CA_ISSUER=CN=My Internal CA, O=MyOrg, C=US
STEP_CA_DNS_NAMES=ca.example.com,ca.internal,pki.local
STEP_CA_PROVISIONER=admin-provisioner
STEP_CA_ADMIN_SUBJECT=admin@example.com
STEP_CA_SSH=true
STEP_CA_ACME=true
STEP_CA_REMOTE_MANAGEMENT=true
# DNS Configuration
DNS_1=8.8.8.8
DNS_2=8.8.4.4
DNS_SEARCH_1=example.com
DNS_SEARCH_2=internal.local
3. Initialize Secrets
Create the required secret files. These are mounted as Docker secrets at /run/secrets/ inside containers:
mkdir -p secrets
echo "your_secure_password" > secrets/postgres_password.txt
echo "your_ca_password" > secrets/step_pwd.txt
chmod 600 secrets/*.txt
Important: These secrets are automatically mounted by Docker Compose:
secrets/postgres_password.txt→/run/secrets/postgres_passwordsecrets/step_pwd.txt→/run/secrets/password
or just make configure
4. Start the Stack
docker-compose up -d --build
5. Verify Deployment
docker-compose logs -f step-ca
docker-compose ps
Configuration
Environment Variables
All configuration is managed through the .env file. Key variables:
| Variable | Description | Default | Example |
|---|---|---|---|
POSTGRES_PASSWORD |
PostgreSQL password | - | secure_pass_123 |
STEP_CA_IP |
IP address for CA service | 127.0.0.1 |
192.168.1.100 |
STEP_CA_PORT |
Port for CA service | 9000 |
9000 |
STEP_CA_NAME |
CA name | Default CA |
Company Internal CA |
STEP_CA_ISSUER |
CA issuer certificate DN | - | CN=My CA, O=Org, C=US |
STEP_CA_DNS_NAMES |
DNS names for CA cert | localhost,ca.local |
ca.example.com,ca.internal |
STEP_CA_PROVISIONER |
Provisioner name | admin |
admin-provisioner |
STEP_CA_ADMIN_SUBJECT |
Admin email address | admin@example.com |
ca-admin@company.com |
STEP_CA_SSH |
Enable SSH support | true |
true or false |
STEP_CA_ACME |
Enable ACME support | true |
true or false |
STEP_CA_REMOTE_MANAGEMENT |
Enable remote management | true |
true or false |
DNS_1, DNS_2 |
DNS servers | 8.8.8.8, 8.8.4.4 |
1.1.1.1, 1.0.0.1 |
DNS_SEARCH_1-3 |
DNS search domains | localhost,local,internal |
example.com,internal.local |
Service Details
PostgreSQL Service
- Image:
postgres:16-alpine - Database:
stepca - User:
stepca - Health Check: PostgreSQL readiness probe every 10 seconds
- Persistent Storage:
postgres-datavolume
Step-CA Service
- Build: Custom image based on
smallstep/step-ca - Port: Configurable via
STEP_CA_PORT(default: 9000) - Database Migration: Automatic transition from Badger to PostgreSQL
- Persistent Storage:
stepca-datavolume for certificates and configuration
Initialization Flow
-
First Run: If
ca.jsondoesn't exist:- Step-ca performs automated initialization with Badger database
- Uses Docker secret from
/run/secrets/passwordfor key encryption - Generates root, intermediate, and SSH certificates
- Creates admin provisioner
-
PostgreSQL Migration:
- Configuration is migrated from Badger to PostgreSQL
- Database connection details are stored in
ca.json - Marker file created to prevent re-initialization
-
Subsequent Runs:
- Step-ca starts directly with PostgreSQL backend
- Uses the same Docker secret for decrypting keys
- No re-initialization occurs (marker file prevents this)
File Structure
step-ca/
├── compose.yaml # Docker Compose configuration
├── Dockerfile # Custom Docker image build
├── init.sh # Initialization script
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
├── config/
│ └── ca.json # Step-ca configuration (generated)
├── secrets/
│ ├── postgres_password.txt
│ └── step_pwd.txt
└── README.md # This file
Usage Examples
Access Step-CA Admin Interface
Once the container is running, you can interact with step-ca:
# Enter the container
docker-compose exec step-ca sh
# List certificates
step certificate list
# Get CA fingerprint
step certificate fingerprint /home/step/certs/root_ca.crt
Request a Certificate via JWK Provisioner
# From inside the container, using the mounted Docker secret
docker-compose exec step-ca sh -c \
'step ca certificate --provisioner=admin --provisioner-password-file=/run/secrets/password \
"my-service.example.com" /tmp/cert.pem /tmp/key.pem'
# Or from the host with your CA password
step ca certificate --provisioner=admin \
"my-service.example.com" cert.pem key.pem
ACME Client Setup
If ACME is enabled, configure your ACME client:
CA URL: https://ca.example.com:9000
Directory: https://ca.example.com:9000/acme/acme/directory
Troubleshooting
PostgreSQL Connection Fails
# Check PostgreSQL logs
docker-compose logs postgres
# Verify database exists
docker-compose exec postgres psql -U stepca -d stepca -c "\dt"
Step-CA Won't Start
# Check step-ca logs
docker-compose logs step-ca
# Verify configuration
docker-compose exec step-ca cat /home/step/config/ca.json
Remove and Reset
To completely reset the environment:
# Stop and remove containers
docker-compose down
# Remove data volumes
docker volume rm ca-stepca-data ca-postgres-data
# Restart fresh
docker-compose up -d --build
Security Considerations
- Secret Management: Store passwords in
secrets/directory and add to.gitignore - Network: Use internal Docker network for PostgreSQL communication
- Firewall: Restrict access to port 9000 from trusted networks only
- TLS: Ensure step-ca certificates are properly validated by clients
- Backups: Regularly backup the
stepca-dataandpostgres-datavolumes
Ports and Networks
- Step-CA Port: 9000 (configurable)
- PostgreSQL Port: 5432 (internal only)
- Network:
ca-internal(internal Docker bridge)
Debugging
Enable verbose logging by modifying the init script:
# Add to init.sh
set -x # Enable debug output
View real-time logs:
docker-compose logs -f step-ca
docker-compose logs -f postgres
Related Documentation
Support
For issues with step-ca, refer to:
License
This Docker Compose stack follows the licensing of Smallstep and individual components.