تخطَّ إلى المحتوى

step-ca Cheat Sheet

Overview

step-ca is an open-source online Certificate Authority (CA) from Smallstep that enables organizations to run their own private PKI infrastructure for issuing and managing X.509 certificates (TLS/HTTPS) and SSH certificates. Unlike traditional CAs that require manual certificate signing requests and approval workflows, step-ca provides automated certificate issuance through ACME (the same protocol used by Let’s Encrypt), JWK provisioners, OAuth/OIDC integration, and cloud provider identity tokens. This automation enables short-lived certificates (hours instead of years) that dramatically reduce the risk of certificate compromise.

step-ca is designed for modern infrastructure patterns including mutual TLS (mTLS) between microservices, SSH certificate authentication (eliminating SSH key sprawl), Kubernetes service mesh certificate management, and zero-trust networking. It supports multiple key types (ECDSA, Ed25519, RSA), hardware security modules (HSMs) via PKCS#11 and cloud KMS (AWS KMS, Google Cloud KMS, Azure Key Vault), and integrates with identity providers for certificate issuance based on SSO authentication. The companion step CLI tool handles certificate operations, key management, and CA interaction from the command line.

Installation

step CLI

# macOS
brew install step

# Linux (Debian/Ubuntu)
wget https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.deb
sudo dpkg -i step-cli_amd64.deb

# Linux (RHEL/CentOS)
wget https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.rpm
sudo rpm -i step-cli_amd64.rpm

# Windows
scoop install step

step-ca Server

# macOS
brew install step-ca

# Linux (Debian/Ubuntu)
wget https://dl.smallstep.com/certificates/docs-ca-install/latest/step-ca_amd64.deb
sudo dpkg -i step-ca_amd64.deb

# Docker
docker run -d -p 9000:9000 \
  -v step:/home/step \
  smallstep/step-ca

# Verify
step-ca version
step version

Initial Setup

Initialize CA

# Interactive CA initialization
step ca init

# Non-interactive initialization
step ca init \
  --name "My Private CA" \
  --provisioner admin \
  --dns ca.example.com \
  --address :443 \
  --password-file /path/to/password.txt

# With specific key type
step ca init \
  --name "My Private CA" \
  --provisioner admin \
  --dns ca.example.com \
  --address :443 \
  --key-type EC \
  --curve P-256

# Initialize with SSH certificate support
step ca init --ssh

Start the CA

# Start CA server
step-ca $(step path)/config/ca.json

# Start with password from file
step-ca $(step path)/config/ca.json --password-file /path/to/password.txt

# Start as systemd service
sudo systemctl enable --now step-ca

# Verify CA is running
step ca health

Bootstrap Client

# Bootstrap client to trust the CA
step ca bootstrap --ca-url https://ca.example.com --fingerprint <root-fingerprint>

# Or with automatic trust
step ca bootstrap --ca-url https://ca.example.com --install

Core Commands

Certificate Operations

CommandDescription
step ca certificate <cn> cert.pem key.pemRequest a certificate
step ca renew cert.pem key.pemRenew a certificate
step ca revoke <serial>Revoke a certificate
step ca token <cn>Generate a one-time token
step certificate inspect cert.pemInspect certificate details
step certificate verify cert.pemVerify certificate chain
step ca rootDownload CA root certificate
# Request TLS certificate
step ca certificate server.example.com server.crt server.key

# Request with specific provisioner
step ca certificate server.example.com server.crt server.key \
  --provisioner admin

# Request with SANs
step ca certificate server.example.com server.crt server.key \
  --san server.example.com \
  --san 192.168.1.10 \
  --san server.internal

# Request with custom duration
step ca certificate server.example.com server.crt server.key \
  --not-after 720h

# Request wildcard certificate
step ca certificate "*.example.com" wildcard.crt wildcard.key

# Inspect issued certificate
step certificate inspect server.crt

# Verify certificate
step certificate verify server.crt --roots $(step path)/certs/root_ca.crt

# Renew certificate
step ca renew server.crt server.key

# Auto-renew with daemon
step ca renew --daemon server.crt server.key

# Revoke certificate
step ca revoke --serial <serial-number> --reason "Key Compromise"
step ca revoke server.crt server.key

SSH Certificate Operations

# Issue SSH user certificate
step ssh certificate user@example.com id_ecdsa --provisioner admin

# Issue SSH host certificate
step ssh certificate server.example.com ssh_host_ecdsa_key \
  --host --provisioner admin \
  --principal server.example.com \
  --principal 192.168.1.10

# Configure SSH client to use certificates
# Add to ~/.ssh/config:
# Host *.example.com
#   CertificateFile ~/.ssh/id_ecdsa-cert.pub

# Configure SSH server to trust CA
step ssh config --roots > /etc/ssh/ssh_user_key.pub
# Add to sshd_config: TrustedUserCAKeys /etc/ssh/ssh_user_key.pub

# List SSH hosts
step ssh hosts

# Inspect SSH certificate
step ssh inspect id_ecdsa-cert.pub

Configuration

CA Configuration

{
  "root": "/etc/step-ca/certs/root_ca.crt",
  "federatedRoots": null,
  "crt": "/etc/step-ca/certs/intermediate_ca.crt",
  "key": "/etc/step-ca/secrets/intermediate_ca_key",
  "address": ":443",
  "dnsNames": ["ca.example.com"],
  "logger": {"format": "text"},
  "db": {
    "type": "badgerv2",
    "dataSource": "/etc/step-ca/db"
  },
  "authority": {
    "provisioners": [
      {
        "type": "JWK",
        "name": "admin",
        "key": { "...": "..." },
        "encryptedKey": "..."
      }
    ],
    "claims": {
      "minTLSCertDuration": "5m",
      "maxTLSCertDuration": "720h",
      "defaultTLSCertDuration": "24h",
      "minHostSSHCertDuration": "5m",
      "maxHostSSHCertDuration": "1680h",
      "defaultHostSSHCertDuration": "720h",
      "minUserSSHCertDuration": "5m",
      "maxUserSSHCertDuration": "24h",
      "defaultUserSSHCertDuration": "16h"
    }
  },
  "tls": {
    "cipherSuites": [
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
    ],
    "minVersion": 1.2,
    "maxVersion": 1.3
  }
}

Provisioner Types

# Add ACME provisioner (Let's Encrypt compatible)
step ca provisioner add acme --type ACME

# Add OIDC provisioner (SSO-based certificates)
step ca provisioner add google --type OIDC \
  --client-id <client-id> \
  --client-secret <client-secret> \
  --configuration-endpoint https://accounts.google.com/.well-known/openid-configuration \
  --domain example.com

# Add AWS provisioner (EC2 instance identity)
step ca provisioner add aws --type AWS \
  --aws-account <account-id>

# Add GCP provisioner
step ca provisioner add gcp --type GCP \
  --gcp-project <project-id>

# Add Azure provisioner
step ca provisioner add azure --type Azure \
  --azure-tenant <tenant-id>

# Add X5C provisioner (certificate-based)
step ca provisioner add x5c --type X5C \
  --x5c-roots /path/to/trusted-root.pem

# List provisioners
step ca provisioner list

Advanced Usage

ACME with Certbot/Caddy

# Use step-ca as ACME server with certbot
certbot certonly --standalone \
  --server https://ca.example.com/acme/acme/directory \
  -d server.example.com

# Caddy automatic HTTPS with step-ca
# Caddyfile:
# {
#   acme_ca https://ca.example.com/acme/acme/directory
#   acme_ca_root /etc/step-ca/certs/root_ca.crt
# }
# server.example.com {
#   respond "Hello, mTLS!"
# }

Mutual TLS (mTLS)

# Issue client certificate
step ca certificate client.example.com client.crt client.key

# Configure Nginx for mTLS
# nginx.conf:
# server {
#     listen 443 ssl;
#     ssl_certificate /etc/nginx/server.crt;
#     ssl_certificate_key /etc/nginx/server.key;
#     ssl_client_certificate /etc/nginx/ca.crt;
#     ssl_verify_client on;
# }

# Test mTLS connection
curl --cert client.crt --key client.key \
  --cacert $(step path)/certs/root_ca.crt \
  https://server.example.com

Kubernetes Integration

# Deploy step-ca with Helm
# helm install step-certificates smallstep/step-certificates

# cert-manager integration
apiVersion: certmanager.step.sm/v1beta1
kind: StepIssuer
metadata:
  name: step-issuer
spec:
  url: https://ca.example.com
  caBundle: <base64-encoded-root-ca>
  provisioner:
    name: admin
    kid: <provisioner-kid>
    passwordRef:
      name: step-provisioner-password
      key: password

HSM/KMS Integration

# Initialize CA with Google Cloud KMS
step ca init \
  --name "HSM-backed CA" \
  --provisioner admin \
  --kms googlekms \
  --dns ca.example.com

# Initialize with AWS KMS
step ca init \
  --name "AWS KMS CA" \
  --provisioner admin \
  --kms awskms \
  --dns ca.example.com

# Initialize with YubiKey
step ca init \
  --name "YubiKey CA" \
  --provisioner admin \
  --kms yubikey \
  --dns ca.example.com

Troubleshooting

IssueSolution
CA won’t startCheck password file, verify certificate/key paths in ca.json
Certificate request deniedVerify provisioner name and credentials, check CA logs
Client doesn’t trust CARun step ca bootstrap --install to install root cert
ACME challenge failsEnsure port 80/443 is accessible, check DNS resolution
SSH certificate rejectedVerify TrustedUserCAKeys in sshd_config points to correct CA public key
Certificate expired too quicklyAdjust defaultTLSCertDuration in CA claims configuration
Connection refusedVerify CA address/port in config, check firewall rules
Database corruptionStop CA, backup db directory, restart to rebuild