# Step-CA Docker Stack A Docker Compose setup for deploying [Smallstep CA](https://smallstep.com/certificates/) (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 ```bash 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: ```env # 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: ```bash 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_password` - `secrets/step_pwd.txt` → `/run/secrets/password` or just `make configure` ### 4. Start the Stack ```bash docker-compose up -d --build ``` ### 5. Verify Deployment ```bash 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-data` volume ### 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-data` volume for certificates and configuration ## Initialization Flow 1. **First Run**: If `ca.json` doesn't exist: - Step-ca performs automated initialization with Badger database - Uses Docker secret from `/run/secrets/password` for key encryption - Generates root, intermediate, and SSH certificates - Creates admin provisioner 2. **PostgreSQL Migration**: - Configuration is migrated from Badger to PostgreSQL - Database connection details are stored in `ca.json` - Marker file created to prevent re-initialization 3. **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: ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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: ```bash # 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-data` and `postgres-data` volumes ## 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: ```bash # Add to init.sh set -x # Enable debug output ``` View real-time logs: ```bash docker-compose logs -f step-ca docker-compose logs -f postgres ``` ## Related Documentation - [Step-CA Documentation](https://smallstep.com/docs/step-ca) - [Step CLI Reference](https://smallstep.com/docs/step-cli) - [Docker Compose Documentation](https://docs.docker.com/compose/) - [PostgreSQL Documentation](https://www.postgresql.org/docs/) ## Support For issues with step-ca, refer to: - [Step-CA GitHub](https://github.com/smallstep/certificates) - [Step Community Discord](https://u.step.sm/discord) - [Step Community Discussions](https://github.com/smallstep/certificates/discussions) ## License This Docker Compose stack follows the licensing of Smallstep and individual components.