Skip to content

Step CA

An internal CA and ACME Provider.

Brief

Guide to setup a internal Certificate Authority and ACME Provider for issuing trusted TLS certs for internal sites. This is useful for both traefik certificateResolver or kubernetes ClusterIssuer. Step can do more, but lets configure the basics.

  • by rskntroot on 2025-06-18

Assumptions

  • An Internal DNS server is configured and accessible.
  • Debian is your choice for the ACME/CA server install.

Install

sudo -i
apt-get update && apt-get install -y --no-install-recommends curl vim gpg ca-certificates
curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg -o /etc/apt/trusted.gpg.d/smallstep.asc && \
    echo 'deb [signed-by=/etc/apt/trusted.gpg.d/smallstep.asc] https://packages.smallstep.com/stable/debian debs main' \
    | tee /etc/apt/sources.list.d/smallstep.list
apt-get update && apt-get -y install step-cli step-ca

For more install instructions see smallstep installation guide.

Config Setup

echo 'some-password' > secret
step ca init \
--deployment-type standalone \
--name ${CA_NAME} \
--dns=${CA_DNS_NAMES} \
--address "0.0.0.0:5001" \
--provisioner ${CA_EMAIL} \
--password-file ./secret
step ca init \
--deployment-type standalone \
--name rskio \
--dns=rskio.com,rskntr.com \
--address "0.0.0.0:5001" \
--provisioner dev@rskio.com \
--password-file ./secret
step ca provisioner add dev --type ACME
mv secret /root/.step/config/.

Service

vi /root/.step/step.service

paste the following and save with [ESC] [:] [x] [ENTER]

[Unit]
Description=Step CA & ACME Provider
After=network-online.target
Requires=network-online.target

[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/usr/bin/step-ca /root/.step/config/ca.json --password-file /root/.step/config/secret
User=root

Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target
ln -s /root/.step/step.service /etc/systemd/system/.
systemctl daemon-reload
systemctl enable --now step.service
systemctl status step.service
ss -pnlt | grep 5001
curl -k https://localhost:5001/acme/dev/directory

you should see your service logs showing it is listening on port :5001 and see the contents of the webpage from curl

Certificates

Trust

cat ~/.step/certs/root_ca.crt
cat ~/.step/certs/intermediate_ca.crt

save and install the files into the trusted certificates on your endpoint and enable trust for ssl signing.

you should now be able to browse to your sites without warning

ClusterIssuer

cat .step/certs/root_ca.crt | base64 -w0

use above output under spec.acme.caBundle

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: dev-step-issuer
spec:
  acme:
    email: ${SOME_EMAIL}
    server: https://${CA_DOMAIN}/acme/dev/directory
    privateKeySecretRef:
      name: dev-step-issuer-account-key
    caBundle: ${CA_ROOT_PEM}
    solvers:
      - selector: {}
        http01:
          ingress:
            class: traefik

FAQs

Why didnt you containerize this?

Because I have multiple kubernetes clusters. Running this on a separate machine means that I don't have to install a rootCA.pem for each cluster instance. You might say "yeah, but you can specify the rootCA as an input to step CA"--but who wants to key files and setup CA for each kuberenetes install? So yeah, maybe I'll do it in the future.