Step CA Private Certificate Authority
Step CA (smallstep/certificates) is a modern, open-source private certificate authority (PKI) system providing automated certificate lifecycle management, ACME protocol support, and cloud-native deployment. This guide covers installation, CA initialization, ACME server configuration, provisioners, and certificate templates.
Table of Contents
- Prerequisites
- Understanding Step CA
- Installing Step CA
- Initializing a CA
- ACME Server Configuration
- Provisioners and Policies
- Certificate Templates
- Client Configuration
- Monitoring and Management
- Troubleshooting
- Conclusion
Prerequisites
Before setting up Step CA, ensure you have:
- Linux system (Ubuntu 20.04+, CentOS 8+)
- Root or sudo access
- At least 2GB RAM
- 10GB disk space
- Internet connectivity
- Basic PKI knowledge
Understanding Step CA
Step CA provides:
- Private PKI: Self-hosted certificate authority
- ACME Support: Automated certificate management (like Let's Encrypt but internal)
- Zero-Trust: Certificate-based authentication for microservices
- Provisioners: Multiple authentication methods for certificate requests
- Templates: Custom certificate extensions and SANs
Typical Step CA workflow:
Client Application
|
+-- Request certificate via ACME
| |
+-- Authenticate with provisioner
| |
+-- Receive certificate
|
Use certificate for TLS
Installing Step CA
Install Step CA from official repositories.
Install step tools (CLI):
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y curl
curl -sL https://dl.step.sm/cli/apt-key.asc | sudo apt-key add -
echo "deb https://dl.step.sm/cli/apt focal main" | sudo tee /etc/apt/sources.list.d/step.list
sudo apt-get update
sudo apt-get install -y step-cli
# Verify
step --version
Install Step CA server:
# Ubuntu/Debian
echo "deb https://dl.step.sm/ca/apt focal main" | sudo tee /etc/apt/sources.list.d/step-ca.list
sudo apt-get update
sudo apt-get install -y step-ca
# Verify
step-ca --version
For CentOS/RHEL:
curl -sL https://dl.step.sm/ca/rpm-key.asc | sudo rpm --import -
echo -e "[stepca]\nname=Step CA Releases\nbaseurl=https://dl.step.sm/ca/rpm\nenabled=1\ngpgcheck=1\ngpgkey=https://dl.step.sm/ca/rpm-key.asc" | sudo tee /etc/yum.repos.d/step.repo
sudo yum install -y step-ca
Initializing a CA
Initialize a new certificate authority.
Create CA user and directories:
sudo useradd -r -s /bin/false step
sudo mkdir -p /etc/step-ca
sudo mkdir -p /var/lib/step-ca
sudo chown -R step:step /etc/step-ca /var/lib/step-ca
sudo chmod 700 /etc/step-ca /var/lib/step-ca
Initialize CA as step user:
sudo -u step step-ca init \
--name "Internal CA" \
--dns localhost,127.0.0.1,ca.example.com \
--address 0.0.0.0:9000 \
--provisioner admin \
--password-file <(openssl rand -base64 32) \
--path /etc/step-ca
This creates:
/etc/step-ca/certs/root_ca.crt: Root CA certificate/etc/step-ca/secrets/root_ca_key: Root CA private key/etc/step-ca/config/ca.json: CA configuration/etc/step-ca/config/defaults.json: Client defaults
Verify installation:
ls -la /etc/step-ca/
cat /etc/step-ca/config/ca.json
ACME Server Configuration
Enable ACME protocol for automated certificate issuance.
Edit CA configuration:
sudo nano /etc/step-ca/config/ca.json
Default configuration includes ACME. Example section:
{
"root": "/etc/step-ca/certs/root_ca.crt",
"crt": "/etc/step-ca/certs/intermediate_ca.crt",
"key": "/etc/step-ca/secrets/intermediate_ca_key",
"db": {
"type": "badger",
"dataSource": "/var/lib/step-ca/db"
},
"authority": {
"provisioners": [
{
"type": "ACME",
"name": "acme"
},
{
"type": "JWK",
"name": "admin",
"key": {
"use": "sig",
"kty": "EC",
"kid": "...",
"crv": "P-256",
"x": "...",
"y": "..."
}
}
]
},
"tls": {
"cipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
],
"minVersion": 1.2,
"maxVersion": 1.3
}
}
Start Step CA:
# Test run
sudo systemctl start step-ca
# Enable for automatic startup
sudo systemctl enable step-ca
# Check status
sudo systemctl status step-ca
Verify ACME endpoint:
curl http://localhost:9000/acme/acme/directory
Provisioners and Policies
Provisioners control how certificates can be requested.
JWK Provisioner: Uses JSON Web Key for authentication
{
"type": "JWK",
"name": "admin",
"key": { /* JWK data */ }
}
OIDC Provisioner: Uses OpenID Connect for single sign-on
{
"type": "OIDC",
"name": "google",
"clientID": "client-id.apps.googleusercontent.com",
"clientSecret": "client-secret",
"configuration": {
"issuer": "https://accounts.google.com",
"authorizationEndpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"tokenEndpoint": "https://oauth2.googleapis.com/token",
"userInfoEndpoint": "https://openidconnect.googleapis.com/v1/userinfo",
"jwksUri": "https://www.googleapis.com/oauth2/v3/certs"
},
"admins": ["[email protected]"],
"users": ["[email protected]"]
}
Kubernetes Provisioner: Authenticate via Kubernetes ServiceAccount
{
"type": "K8sSA",
"name": "kubernetes",
"publicKeys": ["-----BEGIN PUBLIC KEY-----..."],
"admins": ["system:masters"]
}
ACME Provisioner: For automated certificate renewal (built-in)
Add provisioner via API:
# Using step CLI
step ca provisioner add my-provisioner \
--type=JWK \
--public-key /path/to/key.pub \
--private-key /path/to/key.priv
View provisioners:
step ca provisioner list
Certificate Templates
Define custom certificate fields and extensions.
Template example in ca.json:
{
"templates": {
"x509": {
"profile": "leaf",
"encoding": "PEM",
"issuerTemplate": "{{ .Issuer }}",
"subjectTemplate": "{{ .Subject }}",
"durationTemplate": "{{ .Insecure.Duration }}",
"serialNumberTemplate": "{{ .SerialNumber }}",
"keyUsageTemplate": "{{ .KeyUsage }}",
"extKeyUsageTemplate": "{{ .ExtKeyUsage }}",
"sanTemplate": "{{ .SANs }}",
"subjectAltNameTemplate": "{{ .SANs }}",
"subjectKeyIdTemplate": "{{ .SubjectKeyID }}",
"authorityKeyIdTemplate": "{{ .AuthorityKeyID }}",
"basicConstraintsTemplate": "{{ .BasicConstraints }}"
}
}
}
Custom certificate request with template:
step ca certificate \
--template=/path/to/template.json \
--provisioner=acme \
example.com \
cert.crt \
cert.key
Client Configuration
Configure clients to use Step CA with ACME.
Export Step CA certificate:
step ca root > /tmp/root.crt
cat /tmp/root.crt
Certbot with Step CA ACME:
# Configure certbot for Step CA
sudo certbot certonly \
--server http://ca.example.com:9000/acme/acme/directory \
--authenticator standalone \
-d example.com \
--email [email protected] \
--agree-tos \
--no-eff-email
Step CLI for certificate requests:
# Initialize step CLI configuration
step ca bootstrap \
--ca-url http://ca.example.com:9000 \
--fingerprint $(step certificate fingerprint root_ca.crt)
# Request certificate
step ca certificate example.com cert.crt cert.key
# Renew certificate
step ca renew cert.crt cert.key
Automated renewal script:
#!/bin/bash
# /usr/local/bin/step-renew.sh
DOMAIN=$1
CERT_FILE=${2:-${DOMAIN}.crt}
KEY_FILE=${3:-${DOMAIN}.key}
# Renew if expires within 30 days
step ca renew \
--expires-in 720h \
"${CERT_FILE}" "${KEY_FILE}"
# Reload services
systemctl reload nginx
Add to crontab:
# Renew daily
0 2 * * * /usr/local/bin/step-renew.sh example.com /etc/ssl/certs/example.com.crt /etc/ssl/private/example.com.key
Monitoring and Management
Monitor Step CA health and certificate operations.
Check CA status:
step ca health
View CA certificates:
step ca certificate inspect /etc/step-ca/certs/root_ca.crt
step ca certificate inspect /etc/step-ca/certs/intermediate_ca.crt
Monitor Step CA logs:
sudo journalctl -u step-ca -f
Check certificate database:
# List issued certificates
step-ca-admin db list-certs
# Revoke a certificate
step-ca-admin db revoke --serial=<serial>
Configure audit logging:
{
"auditLog": {
"format": "json",
"events": ["write"],
"disable": false
}
}
View audit events:
tail -f /var/lib/step-ca/audit.log | jq .
Troubleshooting
Common Step CA issues:
ACME endpoint not accessible:
# Check if CA is running
sudo systemctl status step-ca
# Test ACME directory
curl http://localhost:9000/acme/acme/directory
# Check firewall
sudo ufw allow 9000
Certificate request failures:
# Test with step CLI
step ca certificate test.example.com test.crt test.key \
--provisioner=admin
# Check provisioner configuration
step ca provisioner list
# View detailed error
step ca certificate test.example.com test.crt test.key \
--provisioner=admin \
--debug
Provisioner authentication issues:
# Reset admin provisioner
step-ca-admin provisioner update admin \
--private-key=/path/to/key
# List active provisioners
step ca provisioner list
# Test OIDC provisioner
curl -X POST http://localhost:9000/acme/acme/new-account
Database corruption:
# Backup database
sudo cp -r /var/lib/step-ca/db /var/lib/step-ca/db.backup
# Rebuild database (if needed)
sudo systemctl stop step-ca
sudo rm -rf /var/lib/step-ca/db
sudo systemctl start step-ca
Conclusion
Step CA provides a modern, cloud-native approach to managing internal certificates. This guide covered installation, CA initialization, ACME server setup, provisioners for flexible authentication, and certificate templates for custom requirements. For production deployments, secure the CA private key, implement robust backup strategies, configure audit logging, use multiple provisioners for different use cases, and establish automated certificate renewal. Step CA excels for zero-trust architectures, microservices PKI, and organizations requiring fine-grained certificate control without relying on external CAs.


