Step CA is an open-source private CA made by Smallstep. I will use it to generate certificates for some componenents in my lab.
First we install the dependencies:
sudo apt-get update && sudo apt-get install -y --no-install-recommends curl gpg ca-certificates
Then we get the Smallstep repository signing key:
sudo curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg -o /etc/apt/keyrings/smallstep.asc
Then we add the Smallstep repository:
cat << 'EOF' | sudo tee /etc/apt/sources.list.d/smallstep.sources > /dev/null Types: deb URIs: https://packages.smallstep.com/stable/debian Suites: debs Components: main Signed-By: /etc/apt/keyrings/smallstep.asc EOF
Then we install step-cli and step-ca:
sudo apt-get update && sudo apt-get -y install step-cli step-ca
Then we check the install:
step-ca version step version Smallstep CA/0.30.2 (linux/amd64) Release Date: 2026-03-23T00:18:00Z Smallstep CLI/0.30.4 (linux/amd64) Release Date: 2026-06-10T06:10:28Z
Next, we’ll run the initializer:
step ca init \ --name "lostintransit.se" \ --dns "stepca.lostintransit.se" \ --address ":443" \ --provisioner "[email protected]" ✔ Deployment Type: Standalone Choose a password for your CA keys and first provisioner. ✔ [leave empty and we'll generate one]: Generating root certificate... done! Generating intermediate certificate... done! ✔ Root certificate: /home/ddib/.step/certs/root_ca.crt ✔ Root private key: /home/ddib/.step/secrets/root_ca_key ✔ Root fingerprint: 8f08102ae41eb7fc6a57f62fbaccaf82cb7a67dbedca858a0352a75b4fa763cd ✔ Intermediate certificate: /home/ddib/.step/certs/intermediate_ca.crt ✔ Intermediate private key: /home/ddib/.step/secrets/intermediate_ca_key ✔ Database folder: /home/ddib/.step/db ✔ Default configuration: /home/ddib/.step/config/defaults.json ✔ Certificate Authority configuration: /home/ddib/.step/config/ca.json Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
The name we define will be used in the common name (CN) of the certificate. The DNS name is how the clients will reach the CA. It could also be an IP address.
Two certificates are generated. Let’s first look at the root certificate:
step certificate inspect root_ca.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 181056573757559942311126483785212531632 (0x88363a4abacade63f875537c81ac93b0)
Signature Algorithm: ECDSA-SHA256
Issuer: O=lostintransit.se,CN=lostintransit.se Root CA
Validity
Not Before: Jun 10 15:20:40 2026 UTC
Not After : Jun 7 15:20:40 2036 UTC
Subject: O=lostintransit.se,CN=lostintransit.se Root CA
Subject Public Key Info:
Public Key Algorithm: ECDSA
Public-Key: (256 bit)
X:
bc:99:12:4f:4a:9a:89:7b:b4:54:55:fc:b6:cf:27:
26:ea:62:ad:76:7f:27:e1:8f:16:55:fc:4e:f4:36:
48:71
Y:
73:bd:b0:ae:bb:13:70:36:01:6d:f3:15:b2:fa:45:
9e:33:67:3b:fc:fe:54:a2:87:b8:c5:dd:9b:63:90:
7e:a0
Curve: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
X509v3 Subject Key Identifier:
50:70:2A:A4:91:33:B6:0B:60:37:B1:23:79:B2:8E:0A:BA:0F:B7:C1
Signature Algorithm: ECDSA-SHA256
30:45:02:21:00:8e:65:b6:dc:d1:2e:3e:a8:c2:12:7e:1f:06:
07:2c:d7:7c:b3:92:95:f3:18:84:f6:a1:d6:dc:32:40:a3:6e:
70:02:20:45:d8:f8:06:a3:02:fa:1c:b7:e8:c0:67:e1:36:6d:
e3:4c:00:80:0c:84:0e:bf:91:94:7d:8d:9e:39:3d:3a:b5
Then the intermediate certificate:
step certificate inspect intermediate_ca.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 117200397332447190053195182546110244923 (0x582bf9b882cfe5b92a5c21d8f8b5e83b)
Signature Algorithm: ECDSA-SHA256
Issuer: O=lostintransit.se,CN=lostintransit.se Root CA
Validity
Not Before: Jun 10 15:20:41 2026 UTC
Not After : Jun 7 15:20:41 2036 UTC
Subject: O=lostintransit.se,CN=lostintransit.se Intermediate CA
Subject Public Key Info:
Public Key Algorithm: ECDSA
Public-Key: (256 bit)
X:
ac:b5:a4:8c:e0:84:46:50:96:cd:b7:b9:b9:75:a7:
a3:b5:78:08:34:e6:38:2b:5c:5f:65:d9:c1:56:91:
1d:d0
Y:
d3:e4:fe:24:5d:fe:09:f4:ff:b1:60:84:68:22:54:
3d:78:9f:bc:e3:c2:a7:2e:cc:57:2d:03:01:8a:0b:
9f:6a
Curve: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Subject Key Identifier:
92:5D:76:F6:28:CE:19:62:13:3C:3A:F8:15:85:2B:10:63:1B:CC:E4
X509v3 Authority Key Identifier:
50:70:2A:A4:91:33:B6:0B:60:37:B1:23:79:B2:8E:0A:BA:0F:B7:C1
Signature Algorithm: ECDSA-SHA256
30:45:02:21:00:f0:0e:05:97:d5:97:27:7d:16:02:ac:32:9c:
49:d8:45:77:b1:e4:22:f3:b8:6e:7b:14:95:d4:82:c3:bd:cb:
0f:02:20:3b:df:14:76:f6:09:39:d5:97:1f:70:a2:96:a6:e3:
f6:ca:22:a5:4a:fa:b0:0a:77:af:83:89:51:66:86:3d:cf
Note that when we sign certificates, they will be signed by the intermediate CA. When we import the root CA chain, we need the full path and will need to concatenate the two certs.
Next we’re going to do some hardening. First we create a service user named step without any shell or home login:
sudo useradd --system --home /etc/step-ca --shell /bin/false step
Then we need to grant permission to bind to port 443:
sudo setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca)
We are using setcap, short for set capabilities. The CAP_NET_BIND_SERVICE is what allows us to do the binding. The +eip is effective (active immediately), inheritable (passed to child processes), and permitted. We use shell substitution with $(which step-ca) to return the full path to the binary, /usr/bin/step-ca.
Next, we’re going to move the CA configuration to a system-wide location (/etc/step-ca):
sudo mkdir -p /etc/step-ca sudo cp -r ~/.step/* /etc/step-ca/ sudo chown -R step:step /etc/step-ca
We copy the existing files (recursively) from .step directory in the home directory and set the owner to be the step user and group. Only this user can read in the directory we created.
We need to update the configuration to point to the right directory:
sudo sed -i 's|/home/ddib/.step|/etc/step-ca|g' /etc/step-ca/config/defaults.json sudo sed -i 's|/home/ddib/.step|/etc/step-ca|g' /etc/step-ca/config/ca.json
You can verify with:
sudo cat /etc/step-ca/config/defaults.json sudo cat /etc/step-ca/config/ca.json
We need to configure the maximum certificate duration for the provisioner. The default is 24 hours which is too short for SD-WAN control plane certificates (my main use case). Edit the CA config:
sudo vi /etc/step-ca/config/ca.json
Find the provisioner entry and add a claims block after the encryptedKey line:
"encryptedKey": "your-encrypted-key-here",
"claims": {
"maxTLSCertDuration": "87600h",
"defaultTLSCertDuration": "8760h"
}
This sets the maximum certificate lifetime to 10 years and the default to 1 year.
Now we need to store the CA password for systemd:
echo "your-ca-password-here" | sudo tee /etc/step-ca/password.txt sudo chmod 600 /etc/step-ca/password.txt sudo chown step:step /etc/step-ca/password.txt
We modify so ownly the owner can read and write and set the owner to be the step user.
Next we create the systemd unit file:
sudo tee /etc/systemd/system/step-ca.service > /dev/null << 'EOF' [Unit] Description=step-ca Certificate Authority After=network-online.target Wants=network-online.target ConditionFileNotEmpty=/etc/step-ca/config/ca.json ConditionFileNotEmpty=/etc/step-ca/password.txt [Service] Type=simple User=step Group=step Environment=STEPPATH=/etc/step-ca WorkingDirectory=/etc/step-ca ExecStart=/usr/bin/step-ca config/ca.json --password-file password.txt Restart=on-failure RestartSec=5 NoNewPrivileges=false AmbientCapabilities=CAP_NET_BIND_SERVICE ProtectSystem=strict ReadWritePaths=/etc/step-ca/db ProtectHome=true [Install] WantedBy=multi-user.target EOF
This allows us to start the CA as a systemd service.
Then we enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now step-ca
sudo systemctl status step-ca
Created symlink /etc/systemd/system/multi-user.target.wants/step-ca.service → /etc/systemd/system/step-ca.service.
● step-ca.service - step-ca Certificate Authority
Loaded: loaded (/etc/systemd/system/step-ca.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-06-11 07:52:59 UTC; 60ms ago
Main PID: 9020 (step-ca)
Tasks: 5 (limit: 2263)
Memory: 6.1M (peak: 6.3M)
CPU: 48ms
CGroup: /system.slice/step-ca.service
└─9020 /usr/bin/step-ca config/ca.json --password-file password.txt
Jun 11 07:52:59 stepca systemd[1]: Started step-ca.service - step-ca Certificate Authority.
That’s our basic installation of Step CA which will allow us to sign certificates.