4 minutes
Debian – Step CA server
Been a while since I’ve done a guide. I have passed my RHCSA!! yeya :) Was focused on the exam, and in the meantime am working on RHCE as well. With that in mind I’m trying to learn other bits on the side which brought me to an issue I had with my TLS certs for my Gitlab server.
Let’s dive in! :)
Requirements
1Gb RAM, 1 CPU host should be more than enough for this build. Debian Bookworm being the distro that I’m sticking to in most my builds these days. Full references can be obtained from their documentation webpage.
First update the server:
sudo apt update && sudo apt upgrade
Following section will need to run as root
to install the packages and dependencies for our CA
server:
apt-get update && apt-get install -y --no-install-recommends curl jq 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
Once the binaries are installed it’s time to init the CA
:
step-cli ca init
Initialisation is done through a terminal prompt:
We will choose Standalone
:
Use the arrow keys to navigate: ↓ ↑ → ←
? What deployment type would you like to configure?:
▸ Standalone - step-ca instance you run yourself
Linked - standalone, plus cloud configuration, reporting & alerting
Hosted - fully-managed step-ca cloud instance run for you by smallstep
I’ve named my example: MyDomainCA
:
What would you like to name your new PKI?
✔ (e.g. Smallstep): MyDomainCA
DNS needs no explanations and the IP address I went with the one on my test server 10.0.50.67
.
Yours may differ, so be careful on this config bit:
What DNS names or IP addresses will clients use to reach your CA?
✔ (e.g. ca.example.com[,10.1.2.3,etc.]): mydomain.local,10.0.50.67
Port can be bound on any, I’ve chosen to go with 443
What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)
✔ (e.g. :443 or 127.0.0.1:443): :443
Provisioner can be arbitrary:
What would you like to name the CA's first provisioner?
✔ (e.g. [email protected]): [email protected]
Password either choose one or let the prompt generate one. In my case I’ve left it empty and it has generated one like below:
Choose a password for your CA keys and first provisioner.
✔ [leave empty and we'll generate one]:
✔ Password: m26MAjDKHIwEloyyk3FIuoUO4Mq4sArj
Once the password has been set we should see something like:
Generating root certificate... done!
Generating intermediate certificate... done!
✔ Root certificate: /root/.step/certs/root_ca.crt
✔ Root private key: /root/.step/secrets/root_ca_key
✔ Root fingerprint: 974ddadbfbef067b237d5a3ae0c01b381af68a7cc15a79c0a76356203f3327b6
✔ Intermediate certificate: /root/.step/certs/intermediate_ca.crt
✔ Intermediate private key: /root/.step/secrets/intermediate_ca_key
✔ Database folder: /root/.step/db
✔ Default configuration: /root/.step/config/defaults.json
✔ Certificate Authority configuration: /root/.step/config/ca.json
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
NOTE: Really important, make sure you save the above into a password manager, keep them safe as we will need fingerprint.
Running step-ca
as a daemon
NOTE: In order for step-ca
to run as a daemon it will need a Linux OS running systemd
version 245 or greater.
- Add a service user for the
CA
. The service user will only be used bysystemd
to manage theCA
:
sudo useradd --user-group --system --home /etc/step-ca --shell /bin/false step
If the CA
will bind to port 443, the step-ca
binary will need to be given low port-binding capabilities:
sudo setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca)
- Move
CA
configuration into a system-wide location:
sudo mkdir -p /etc/step-ca && sudo mv $(step path)/* /etc/step-ca
Now with the new directory structure we will need to create password file:
vim /etc/step-ca/password.txt
Add the password from above in the password file:
m26MAjDKHIwEloyyk3FIuoUO4Mq4sArj
Also needed to amend the config with the new location of the config
and root_ca.crt
from:
{
"ca-url": "https://mydomain.local",
"ca-config": "/root/.step/config/ca.json",
"fingerprint": "974ddadbfbef067b237d5a3ae0c01b381af68a7cc15a79c0a76356203f3327b6",
"root": "/root/.step/certs/root_ca.crt"
}
to:
{
"ca-url": "https://mydomain.local",
"ca-config": "/etc/step-ca/config/ca.json",
"fingerprint": "974ddadbfbef067b237d5a3ae0c01b381af68a7cc15a79c0a76356203f3327b6",
"root": "/etc/step-ca/certs/root_ca.crt"
}
There are four entries that need changing in /etc/step-ca/config/ca/ca.json
:
"root": "/root/.step/certs/root_ca.crt",
"crt": "/root/.step/certs/intermediate_ca.crt",
"key": "/root/.step/secrets/intermediate_ca_key",
"dataSource": "/root/.step/db",
Simply change the path to the new structure:
"root": "/etc/step-ca/certs/root_ca.crt",
"crt": "/etc/step-ca/certs/intermediate_ca.crt",
"key": "/etc/step-ca/secrets/intermediate_ca_key",
"dataSource": "/etc/step-ca/db",
Now ownership of the new directory:
chown -R step:step /etc/step-ca
Amend the ca.conf
file to point to new database location:
cat <<< $(jq '.db.dataSource = "/etc/step-ca/db"' /etc/step-ca/config/ca.json) > /etc/step-ca/config/ca.json
- Create a
systemd
unit file:
vim /etc/systemd/system/step-ca.service
Add the following contents to it:
[Unit]
Description=step-ca service
Documentation=https://smallstep.com/docs/step-ca
Documentation=https://smallstep.com/docs/step-ca/certificate-authority-server-production
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=30
StartLimitBurst=3
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
ExecReload=/bin/kill --signal HUP $MAINPID
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
StartLimitInterval=30
StartLimitBurst=3
; Process capabilities & privileges
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
SecureBits=keep-caps
NoNewPrivileges=yes
; Sandboxing
ProtectSystem=full
ProtectHome=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
PrivateTmp=true
PrivateDevices=true
ProtectClock=true
ProtectControlGroups=true
ProtectKernelTunables=true
ProtectKernelLogs=true
ProtectKernelModules=true
LockPersonality=true
RestrictSUIDSGID=true
RemoveIPC=true
RestrictRealtime=true
SystemCallFilter=@system-service
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
ReadWriteDirectories=/etc/step-ca/db
[Install]
WantedBy=multi-user.target
More detail on the systemd
service file can be found in the office guide here.
- Enabling the service
To enable the service we will reload daemons and and follow journalctl
to see the status of the daemon:
systemctl daemon-reload && systemctl enable --now step-ca && journalctl --follow --unit=step-ca