29 min read

Smallstep's step-ca as CA with ACME support

In this blog post, we will go through the basic installation process and install both the step-ca and step-cli tool that will help us manage our CA and certificates issued by the CA.

step-ca serves as an online Certificate Authority (CA) designed for the efficient and secure management of X.509 and SSH certificates. Functioning alongside step CLI, it provides robust server capabilities. The platform is secured using TLS and includes a range of customisable certificate provisioners, adaptable certificate templates, and interchangeable database backends to accommodate diverse workflows and scenarios. With user-friendly default algorithms and configurations, you can use it safely without needing to be a security expert.

`step-ca` server
Learn about step-ca

This guide has been completed on a Debian system, while the step-cli component has been successfully installed on both Debian and Linux Mint Debian editions.

Installing step-ca

First, let's install step-cli on our server - please note that the server can be run in both VM and an LXC, but in this particular scenario I'm running it in a VM. You can also run the server component within a docker container, but I prefer to run it in a VM/LXC as I'm just more comfortable with customising it on a full system.

First we install step-cli:

wget https://dl.smallstep.com/cli/docs-ca-install/latest/step-cli_amd64.deb
sudo dpkg -i step-cli_amd64.deb

Next, we install step-ca:

wget https://dl.smallstep.com/certificates/docs-ca-install/latest/step-ca_amd64.deb
sudo dpkg -i step-ca_amd64.deb

We will now initialise the system:

step ca init --name="NetworkTechGuy.com CA" --dns=ca.demo.networktechguy.com --dns=10.75.1.10  --acme --ssh

The main part of the command is step ca init and it can be run without any additional parameters. However, I want to specify some of them in the parameters as the install script doesn't allow multiple DNS names (or in our case, FQDN and an IP address - at least I didn't see how I could add multiple entries once I start the script). Finally, we also add support for ACME (Automatic Certificate Management Environment) and SSH (SSH CA). We will use ACME later on to allow other services to request certificates directly from the CA (read: traefik). We will use SSH CA later on to allow public key authentication on our workstation boxes (mostly Linux) without the need to add the SSH key of a particular user to the destination box. It is not something that we will delve into in this blog post, we will just prepare the system to act as SSH CA.

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
✔ Deployment Type: Standalone
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
What would you like to name the CA's first provisioner?
✔ (e.g. [email protected]): NTG
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/nenad/.step/certs/root_ca.crt
✔ Root private key: /home/nenad/.step/secrets/root_ca_key
✔ Root fingerprint: e27ae5a0b80320d646a233ec281c47cf4768ba4d011245f9e550ac4a6acdf876
✔ Intermediate certificate: /home/nenad/.step/certs/intermediate_ca.crt
✔ Intermediate private key: /home/nenad/.step/secrets/intermediate_ca_key
✔ SSH user public key: /home/nenad/.step/certs/ssh_user_ca_key.pub
✔ SSH user private key: /home/nenad/.step/secrets/ssh_user_ca_key
✔ SSH host public key: /home/nenad/.step/certs/ssh_host_ca_key.pub
✔ SSH host private key: /home/nenad/.step/secrets/ssh_host_ca_key
✔ Database folder: /home/nenad/.step/db
✔ Templates folder: /home/nenad/.step/templates
✔ Default configuration: /home/nenad/.step/config/defaults.json
✔ Certificate Authority configuration: /home/nenad/.step/config/ca.json
 
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
FEEDBACK 😍 🍻
 The step utility is not instrumented for usage statistics. It does not phone
 home. But your feedback is extremely valuable. Any information you can provide
 regarding how you’re using `step` helps. Please send us a sentence or two,
 good or bad at [email protected] or join GitHub Discussions
 https://github.com/smallstep/certificates/discussions and our Discord 
 https://u.step.sm/discord.

The only inputs required are for you to decide what kind of deployment you want (Standalone in our case), what port it will be tied to (443), name of the first provisioner (NTG) and the password. After that, the install script will finish the initialisation process and give you an output of all the files it generated.

Let's take a look at the newly generated root certificate by issuing command

step certificate inspect /home/nenad/.step/certs/root_ca.crt

Your output should look something like this:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 214726447278470048304383284452453651499 (0xa18acf39332441c10bcd4dc98f2e142b)
    Signature Algorithm: ECDSA-SHA256
        Issuer: O=NetworkTechGuy.com CA,CN=NetworkTechGuy.com CA Root CA
        Validity
            Not Before: Sep 28 00:26:44 2024 UTC
            Not After : Sep 26 00:26:44 2034 UTC
        Subject: O=NetworkTechGuy.com CA,CN=NetworkTechGuy.com CA Root CA
        Subject Public Key Info:
            Public Key Algorithm: ECDSA
                Public-Key: (256 bit)
                X:
                    70:85:11:c7:4f:9b:d8:54:d7:cc:2c:88:39:84:35:
                    bc:68:2c:3d:8c:5f:42:2f:05:72:d5:a6:73:fe:4b:
                    7e:ea
                Y:
                    c7:94:ab:96:ba:af:6c:aa:82:4b:f9:a3:b3:fd:8e:
                    94:aa:7e:00:08:83:c4:82:bc:12:8b:d0:af:2b:ea:
                    11:22
                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:
                16:97:6A:D4:E1:59:57:1F:A9:F9:C5:BD:30:D0:DE:70:4B:E4:61:90
    Signature Algorithm: ECDSA-SHA256
         30:45:02:21:00:e1:11:7c:df:97:fe:da:5f:1a:52:fd:0b:74:
         05:df:92:68:3c:8f:1b:7e:75:37:c4:12:51:f7:8e:02:04:8a:
         18:02:20:3a:a2:8a:d6:68:16:af:cb:95:29:7e:47:6d:a0:09:
         54:e9:b5:3e:20:d7:0c:a8:f4:17:cb:25:80:88:10:21:88

Let's explain some parts of the output. First of all, without any parameters added while initialising the CA, it will use ECDSA-SHA256 by default as a signature algorithm and all subsequently generated certificates will be signed with the same algorithm.

It also creates a root certificate of a default validity of 10 years, as can be seen in the Not Before and Not After fields. Issuer fields are also populated automatically based on the --name parameter we gave at the beginning of the process.

Customising the installation

Next, let's issue the following command:

sudo setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca)

The command sudo setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca) is used to grant the step-ca binary permission to bind to privileged ports (those below 1024) without requiring it to be run as the root user. Typically, only processes with root privileges can bind to these lower ports, such as port 443 for HTTPS. By setting the CAP_NET_BIND_SERVICE capability, this command allows step-ca to securely listen on ports like 443 while minimising security risks, as running a service as root can expose the system to potential vulnerabilities. The $(which step-ca) portion dynamically inserts the path to the step-ca binary.

Finally, we test-start our CA by issuing command step-ca:

$ step-ca

badger 2024/09/27 20:31:04 INFO: All 0 tables opened in 0s
Please enter the password to decrypt /home/nenad/.step/secrets/ssh_user_ca_key: 
2024/09/27 20:31:15 Building new tls configuration using step-ca x509 Signer Interface
2024/09/27 20:31:15 Starting Smallstep CA/0.27.4 (linux/amd64)
2024/09/27 20:31:15 Documentation: https://u.step.sm/docs/ca
2024/09/27 20:31:15 Community Discord: https://u.step.sm/discord
2024/09/27 20:31:15 Config file: /home/nenad/.step/config/ca.json
2024/09/27 20:31:15 The primary server URL is https://ca.demo.networktechguy.com:443
2024/09/27 20:31:15 Root certificates are available at https://ca.demo.networktechguy.com:443/roots.pem
2024/09/27 20:31:15 Additional configured hostnames: 10.75.1.10
2024/09/27 20:31:15 X.509 Root Fingerprint: e27ae5a0b80320d646a233ec281c47cf4768ba4d011245f9e550ac4a6acdf876
2024/09/27 20:31:15 SSH Host CA Key: ecdsa-sha2-nistp256 ---OUTPUT OMITTED---
2024/09/27 20:31:15 SSH User CA Key: ecdsa-sha2-nistp256 ---OUTPUT OMITTED---
2024/09/27 20:31:15 Serving HTTPS on :443 ...

As you can see from the output, the server is now successfully running and listening on port 443 for any requests. Let's shut it down by pressing Ctrl+C and your output should look something like this:

2024/09/27 20:31:27 shutting down ...
badger 2024/09/27 20:31:27 INFO: Storing value log head: {Fid:0 Len:30 Offset:1575}
badger 2024/09/27 20:31:27 INFO: [Compactor: 173] Running compaction: {level:0 score:1.73 dropPrefixes:[]} for level: 0
badger 2024/09/27 20:31:27 INFO: LOG Compact 0->1, del 1 tables, add 1 tables, took 8.0127ms
badger 2024/09/27 20:31:27 INFO: [Compactor: 173] Compaction for level: 0 DONE
badger 2024/09/27 20:31:27 INFO: Force compaction on level 0 done
sudo useradd --system --home /etc/step-ca --shell /bin/false step

The command sudo useradd --system --home /etc/step-ca --shell /bin/false step creates a system user named step specifically for running the step-ca service. A system user is typically used for managing services and does not have the same privileges as a regular user. The --home /etc/step-ca option sets /etc/step-ca as the home directory for the step user, where configuration files for the service will reside. The --shell /bin/false option ensures that the step user cannot log in or execute commands interactively, enhancing security by preventing unauthorised access to the system through this user account. This approach follows best practices by creating a dedicated, non-interactive service user.

Next, we will create the /etc/step-ca directory and move all the configuration files there:

sudo mkdir /etc/step-ca
sudo mv $(step path)/* /etc/step-ca

If everything went well, listing of the directory should show you all files that were previously under ~/.step directory:

$ ls -alh /etc/step-ca/

total 28K
drwxr-xr-x  7 root  root  4.0K Sep 27 20:32 .
drwxr-xr-x 70 root  root  4.0K Sep 27 20:32 ..
drwx------  2 nenad nenad 4.0K Sep 27 20:26 certs
drwx------  2 nenad nenad 4.0K Sep 27 20:25 config
drwx------  2 nenad nenad 4.0K Sep 27 20:31 db
drwx------  2 nenad nenad 4.0K Sep 27 20:26 secrets
drwx------  3 nenad nenad 4.0K Sep 27 20:26 templates

Next, we will add the password we typed in into the /etc/step-ca/password.txt file:

echo 'YOUR_PASSWORD' | sudo tee /etc/step-ca/password.txt > /dev/null

We also want to make this file readable only by the owner:

chmod 700 /etc/step-ca/password.txt

Next, we will replace all references to the old directory (~/.step) in the configuration files with the new location:

sudo sed -i "s|/home/$(whoami)/.step/|/etc/step-ca/|g" /etc/step-ca/config/defaults.json /etc/step-ca/config/ca.json

Finally, let's change the ownership of all the files to the previously created user step:

sudo chown -R step:step /etc/step-ca

As a side-note, I added the following commands as well:

sudo chmod 750 /etc/step-ca/ -R
sudo usermod -aG step nenad

This is because I wanted to be able to read the files and content of the directories, but if you want to always use sudo to make any changes or read files, feel free to change 750 to 700.

If you opted for 750, results should be something like this:

ls -alh /etc/step-ca/
total 32K
drwxr-x---  7 step step 4.0K Sep 27 20:32 .
drwxr-xr-x 70 root root 4.0K Sep 27 20:39 ..
drwxr-x---  2 step step 4.0K Sep 27 20:26 certs
drwxr-x---  2 step step 4.0K Sep 27 20:35 config
drwxr-x---  2 step step 4.0K Sep 27 21:04 db
-rwxr-x---  1 step step    9 Sep 27 20:32 password.txt
drwxr-x---  2 step step 4.0K Sep 27 20:26 secrets
drwxr-x---  3 step step 4.0K Sep 27 20:26 templates

Next, since we want to run our CA as a service, we create a service file:

$ sudo tee /etc/systemd/system/step-ca.service > /dev/null <<EOF

[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
EOF

Let's explain what this does.

[Unit] Section
Description=step-ca service
: A brief description of the service, providing clarity about its purpose.
Documentation=...: Links to online documentation, which help users understand how to configure and use the service effectively.
After=network-online.target: Specifies that this service should start only after the network is fully online, ensuring that the service has the necessary network resources available when it starts.
Wants=network-online.target: Indicates that this service wants the network-online.target to be started, promoting better dependencies among services.
StartLimitIntervalSec=30: Defines the time frame within which the systemd service manager will track the service's failures.
StartLimitBurst=3: Specifies the maximum number of times the service can fail within the defined StartLimitIntervalSec before being considered to have failed permanently.
ConditionFileNotEmpty=...: Checks that specified files are not empty before starting the service. This ensures that critical configuration files (/etc/step-ca/config/ca.json and /etc/step-ca/password.txt) are present and contain data, preventing the service from starting with invalid or missing configurations.

[Service] Section
Type=simple
: Indicates that the service runs continuously and does not fork into a background process. The service manager considers the service started as soon as the main process is executed.
User=step: Specifies the user under which the service will run, improving security by limiting access to necessary resources only.
Group=step: Specifies the group under which the service will run, similar to User.
Environment=STEPPATH=/etc/step-ca: Sets the STEPPATH environment variable for the service, defining the path used for configuration and data storage.
WorkingDirectory=/etc/step-ca: Sets the directory where the service will execute. This is typically where configuration files are located.
ExecStart=...: The command that starts the service. It specifies the executable and its arguments, which in this case include the configuration file and the password file.
ExecReload=/bin/kill --signal HUP $MAINPID: Defines how to reload the service without stopping it, using the HUP signal to notify the main process to reload its configuration.
Restart=on-failure: Configures the service to restart automatically if it fails, enhancing resilience.
RestartSec=5: Specifies the delay (in seconds) before attempting to restart the service after a failure.
TimeoutStopSec=30: Sets the maximum time to wait for the service to stop after a stop command is issued. If it exceeds this time, the service will be forcibly terminated.
StartLimitInterval=30 and StartLimitBurst=3: These are repeated from the [Unit] section, enforcing the same start limits.

Process Capabilities & Privileges
AmbientCapabilities=CAP_NET_BIND_SERVICE
: Grants the ability to bind to network ports below 1024, which is necessary for services that need to listen on these privileged ports (e.g., HTTPS).
CapabilityBoundingSet=CAP_NET_BIND_SERVICE: Restricts the capabilities of the service to only those specified, enhancing security by limiting what the service can do.
SecureBits=keep-caps: Ensures that the process retains its capabilities after a fork, providing additional security against privilege escalation.
NoNewPrivileges=yes: Prevents the service from gaining new privileges, further enhancing security.

Sandboxing
ProtectSystem=full
: Restricts write access to the system files, making the service less able to alter system-wide configurations.
ProtectHome=true: Prevents access to user home directories, enhancing privacy and security.
RestrictNamespaces=true: Disallows the service from using namespaces, which could be exploited for privilege escalation.
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6: Limits the address families that the service can use for networking, providing additional security.
PrivateTmp=true: Provides the service with a private temporary directory, isolating it from other services.
PrivateDevices=true: Restricts access to raw devices, reducing the risk of device-related attacks.
ProtectClock=true: Prevents the service from altering the system clock, protecting against potential tampering.
ProtectControlGroups=true: Prevents the service from modifying cgroups, enhancing stability and security.
ProtectKernelTunables=true: Restricts the service's ability to alter kernel parameters, which could affect system security and stability.
ProtectKernelLogs=true: Prevents the service from accessing kernel logs, protecting sensitive information.
ProtectKernelModules=true: Disallows loading or unloading kernel modules, enhancing system security.
LockPersonality=true: Prevents the service from changing its personality, which could be used for privilege escalation.
RestrictSUIDSGID=true: Disallows the service from using SUID and SGID binaries, reducing the risk of privilege escalation.
RemoveIPC=true: Cleans up any IPC (Inter-Process Communication) objects when the service stops, preventing potential resource leaks.
RestrictRealtime=true: Disallows the service from accessing real-time scheduling policies, enhancing system stability.
SystemCallFilter=@system-service: Limits the system calls that the service can make, reducing the attack surface.
SystemCallArchitectures=native: Restricts the service to use only native architecture for system calls, enhancing compatibility and security.
MemoryDenyWriteExecute=true: Prevents memory regions from being both writable and executable, reducing the risk of certain types of exploits.
ReadWriteDirectories=/etc/step-ca/db: Specifies which directories the service can write to, ensuring that it only has write access to necessary directories.

[Install] Section
WantedBy=multi-user.target
: Specifies that the service should be started in the multi-user target, which is the default mode for most server operations. This ensures the service is activated during the boot process.

sudo systemctl daemon-reload is a way to refresh systemd’s view of service configurations after modifications:

sudo systemctl daemon-reload

Next, we will enable the service:

$ sudo systemctl enable --now step-ca

Created symlink /etc/systemd/system/multi-user.target.wants/step-ca.service → /etc/systemd/system/step-ca.service.

sudo systemctl status step-ca
● step-ca.service - step-ca service
     Loaded: loaded (/etc/systemd/system/step-ca.service; enabled; preset: enabled)
     Active: active (running) since Fri 2024-09-27 20:37:01 EDT; 4s ago
       Docs: https://smallstep.com/docs/step-ca
             https://smallstep.com/docs/step-ca/certificate-authority-server-production
   Main PID: 1635 (step-ca)
      Tasks: 9 (limit: 4643)
     Memory: 99.4M
        CPU: 272ms
     CGroup: /system.slice/step-ca.service
             └─1635 /usr/bin/step-ca config/ca.json --password-file password.txt

Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 Documentation: https://u.step.sm/docs/ca
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 Community Discord: https://u.step.sm/discord
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 Config file: config/ca.json
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 The primary server URL is https://ca.demo.networktechguy.com:443
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 Root certificates are available at https://ca.demo.networktechguy.com:443/roots.pem
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 Additional configured hostnames: 10.75.1.10
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 X.509 Root Fingerprint: e27ae5a0b80320d646a233ec281c47cf4768ba4d011245f9e550ac4a6acdf876
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 SSH Host CA Key: ecdsa-sha2-nistp256 ---OUTPUT OMITTED---
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 SSH User CA Key: ecdsa-sha2-nistp256 ---OUTPUT OMITTED---
Sep 27 20:37:02 deb-step-01 step-ca[1635]: 2024/09/27 20:37:02 Serving HTTPS on :443 ...

We will restart the service as well, just to make sure that it restarts properly:

sudo systemctl restart step-ca

Since I've added myself to the step group, I can also issue following commands:

echo 'export STEPPATH=/etc/step-ca' | sudo tee -a ~/.bashrc > /dev/null
source ~/.bashrc

This will allow me to use commands like this when logged into the CA server:

$ step certificate fingerprint $(step path)/certs/root_ca.crt

e27ae5a0b80320d646a233ec281c47cf4768ba4d011245f9e550ac4a6acdf876

This finalises the installation of the step-ca CA on our server and we can now move onto a workstation to test certificate requests and issuance.

Testing the CA

On our workstation, which is running LMDE, we will also install step-cli tool:

wget https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.deb
sudo dpkg -i step-cli_amd64.deb

Next, we will bootstrap the CA on this workstation by issuing the following command:

$ step ca bootstrap --ca-url https://ca.demo.networktechguy.com --fingerprint e27ae5a0b80320d646a233ec281c47cf4768ba4d011245f9e550ac4a6acdf876

The root certificate has been saved in /home/nenad/.step/certs/root_ca.crt.
The authority configuration has been saved in /home/nenad/.step/config/defaults.json.

Couple of things to mention - if you want to use FQDN for your CA, you need to make sure that your DNS is working properly and that proper records are configured for the CA. You can always use the IP address as well, as long as you have configured it to do so during initialisation process. In this output I'm using my own FQDN, you will need to replace that with whatever you're using and fingerprint will also be different, of course.

With that out of the way, let's try and request a certificate:

$ step ca certificate test-01.demo.networktechguy.com test-01.demo.networktechguy.com.crt test-01.demo.networktechguy.com.key

Use the arrow keys to navigate: ↓ ↑ → ← 
What provisioner key do you want to use?
▸ NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
  acme (ACME)
  sshpop (SSHPOP)
✔ Provisioner: NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
Please enter the password to decrypt the provisioner key: 
✔ CA: https://ca.demo.networktechguy.com
✔ Certificate: test-01.demo.networktechguy.com.crt
✔ Private Key: test-01.demo.networktechguy.com.key

Let's take a look at the certificate that was issued:

$ step certificate inspect test-01.demo.networktechguy.com.crt 

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 230303080852659320237188564093704885389 (0xad42c28d62c83216d65a9a872140548d)
    Signature Algorithm: ECDSA-SHA256
        Issuer: O=NetworkTechGuy.com CA,CN=NetworkTechGuy.com CA Intermediate CA
        Validity
            Not Before: Sep 28 01:40:15 2024 UTC
            Not After : Sep 29 01:41:15 2024 UTC
        Subject: CN=test-01.demo.networktechguy.com
        Subject Public Key Info:
            Public Key Algorithm: ECDSA
                Public-Key: (256 bit)
                X:
                    e1:6c:56:ea:fa:e9:11:7e:2a:d1:0d:0c:ec:f5:26:
                    71:54:7f:31:ca:e8:8a:09:f2:3a:86:58:d3:97:db:
                    0f:de
                Y:
                    5f:7a:2e:9e:e7:01:a0:d9:06:c5:bf:1f:22:ec:a7:
                    b6:9f:eb:cd:21:3f:30:4b:78:41:8f:df:c5:0d:73:
                    bb:3c
                Curve: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                Server Authentication, Client Authentication
            X509v3 Subject Key Identifier:
                BC:28:C8:31:E3:52:E6:B8:71:5A:65:73:32:E9:24:16:44:24:07:31
            X509v3 Authority Key Identifier:
                keyid:68:AA:E5:56:18:0F:A2:87:0A:F8:95:61:C0:CC:04:A7:DE:B7:50:AB
            X509v3 Subject Alternative Name:
                DNS:test-01.demo.networktechguy.com
            X509v3 Step Provisioner:
                Type: JWK
                Name: NTG
                CredentialID: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A
    Signature Algorithm: ECDSA-SHA256
         30:45:02:20:37:b8:2e:b7:27:8f:88:5d:0e:d1:05:9b:b4:36:
         12:83:06:1e:45:44:19:f4:43:32:d7:01:d7:e9:80:aa:ac:e7:
         02:21:00:83:43:e3:03:f0:bd:12:e8:83:01:ae:67:04:aa:e4:
         35:1d:ad:e8:ca:c3:a5:78:21:92:dc:b0:41:a6:3b:4b:a0

You will notice a couple of things - Subject and DNS fields are populated based on the parameters of the command we issued. step-ca also uses its intermediate CA to sign all of the certificate requests, that's why you will see it in the Issuer field. Everything else is using default values set on the CA itself.

If you want someone else to create CSRs for their own systems and sign them afterwards, all they need to do is create a CSR (Certificate Signing Request):

step certificate create test-02.demo.networktechguy.com test-02.demo.networktechguy.com.csr test-02.demo.networktechguy.com.key --kty RSA --size 2048 --csr

Of course, they need to have the step-cli tool installed on their computer as well!

Once they create the CSR, they can send the file to you and you can then inspect it and sign it:

$ step certificate inspect test-02.demo.networktechguy.com.csr

Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: CN=test-02.demo.networktechguy.com
        Subject Public Key Info:
            Public Key Algorithm: RSA
                Public-Key: (2048 bit)
                Modulus:
                    e5:65:6f:d2:05:98:48:4c:ca:aa:63:9c:9e:43:25:
                    77:55:6e:6a:0d:17:08:d0:58:2c:d6:3c:4e:b6:4c:
                    8c:a3:82:cf:a1:1b:8d:ed:ff:a7:8f:19:4b:1e:a2:
                    87:d9:dd:08:8d:47:d4:c3:77:de:b7:2a:1d:ae:ef:
                    7c:8d:cb:9f:3c:95:cc:ad:d5:29:11:00:3d:89:61:
                    76:2c:2b:58:31:93:a7:da:15:3d:6a:1e:40:81:3c:
                    38:f5:6b:8b:09:76:3b:a4:15:d8:c1:48:0b:8e:5d:
                    f5:d1:e4:1a:03:3d:45:8a:e3:17:6b:d0:3e:5e:d4:
                    9e:11:5c:dc:90:92:11:2e:c2:6d:32:85:ed:a3:76:
                    0e:0d:61:a1:4c:5f:26:44:9a:f5:ea:0c:f2:1e:67:
                    49:c8:27:04:e8:41:09:6c:ae:af:89:3f:2f:44:01:
                    35:50:1f:aa:3d:62:8f:f7:44:4c:f3:59:80:d6:09:
                    60:bd:21:2e:b5:3c:c2:94:39:ba:53:df:45:bc:06:
                    59:e4:c0:5c:a6:7f:d3:8b:67:af:cf:a6:79:0c:0c:
                    00:6f:e3:6e:68:78:47:7f:42:b3:ff:8a:42:f5:5e:
                    7b:81:fc:2e:ae:00:04:7d:39:3d:c3:bf:88:79:54:
                    b0:d0:06:ca:62:4d:46:a6:af:44:31:18:ad:5b:7c:
                    4f
                Exponent: 65537 (0x10001)
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:test-02.demo.networktechguy.com
    Signature Algorithm: SHA256-RSA
         57:fb:81:33:d0:7d:3f:7a:c1:e8:52:56:e9:39:09:7c:d8:60:
         25:66:b8:2c:05:b8:fb:66:f5:61:66:75:27:ea:f5:e2:c3:0c:
         a8:d6:fd:ef:cf:16:47:98:04:77:37:65:81:da:71:bf:a0:de:
         5c:40:0c:fc:3e:c2:ec:68:72:9c:cb:23:84:fd:ac:bd:ca:6a:
         32:20:bc:d9:7a:1c:63:24:5c:b5:be:1f:02:5c:4e:fc:67:e5:
         ac:43:f8:26:e6:3a:c4:cd:51:94:f6:16:00:c0:da:80:70:b9:
         2e:2b:2f:19:7a:70:b8:c9:29:fb:5d:18:ce:55:31:95:0a:f1:
         7a:e6:d9:12:4b:a4:31:5c:11:5f:ac:d9:01:ea:13:02:9c:aa:
         2b:f2:5d:0a:f7:99:f3:86:e3:9c:35:36:e9:c7:a5:d2:cd:8c:
         0c:87:d5:4b:fe:6a:89:1f:93:00:89:8a:68:4d:4d:11:f9:53:
         d5:ba:e2:89:a4:19:e3:f2:55:39:11:3d:3e:9d:46:d4:e8:bf:
         ca:ac:da:0e:84:e9:b5:a0:2c:f7:7a:f3:2a:d7:d4:fb:a4:04:
         2a:1c:ad:fc:3f:09:05:b2:c8:78:a0:93:f0:6f:ff:6c:07:e0:
         72:31:38:14:d6:cd:4e:0b:65:df:44:53:c5:a1:f2:d8:e5:cf:
         e0:22:d8:2c

As you can see here, they are requesting an RSA key, so let's see what happens when we issue the certificate:

$ step ca sign test-02.demo.networktechguy.com.csr test-02.demo.networktechguy.com.crt

Use the arrow keys to navigate: ↓ ↑ → ← 
What provisioner key do you want to use?
▸ NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
  acme (ACME)
  sshpop (SSHPOP)
✔ Provisioner: NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
Please enter the password to decrypt the provisioner key: 
✔ CA: https://ca.demo.networktechguy.com
✔ Certificate: test-02.demo.networktechguy.com.crt

Let's inspect the signed certificate:

$ step certificate inspect test-02.demo.networktechguy.com.crt

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 181670349895972408265478593914397351809 (0x88ac6fcabb6952fec8bcdff7dcd55f81)
    Signature Algorithm: ECDSA-SHA256
        Issuer: O=NetworkTechGuy.com CA,CN=NetworkTechGuy.com CA Intermediate CA
        Validity
            Not Before: Sep 28 01:47:23 2024 UTC
            Not After : Sep 29 01:48:23 2024 UTC
        Subject: CN=test-02.demo.networktechguy.com
        Subject Public Key Info:
            Public Key Algorithm: RSA
                Public-Key: (2048 bit)
                Modulus:
                    e5:65:6f:d2:05:98:48:4c:ca:aa:63:9c:9e:43:25:
                    77:55:6e:6a:0d:17:08:d0:58:2c:d6:3c:4e:b6:4c:
                    8c:a3:82:cf:a1:1b:8d:ed:ff:a7:8f:19:4b:1e:a2:
                    87:d9:dd:08:8d:47:d4:c3:77:de:b7:2a:1d:ae:ef:
                    7c:8d:cb:9f:3c:95:cc:ad:d5:29:11:00:3d:89:61:
                    76:2c:2b:58:31:93:a7:da:15:3d:6a:1e:40:81:3c:
                    38:f5:6b:8b:09:76:3b:a4:15:d8:c1:48:0b:8e:5d:
                    f5:d1:e4:1a:03:3d:45:8a:e3:17:6b:d0:3e:5e:d4:
                    9e:11:5c:dc:90:92:11:2e:c2:6d:32:85:ed:a3:76:
                    0e:0d:61:a1:4c:5f:26:44:9a:f5:ea:0c:f2:1e:67:
                    49:c8:27:04:e8:41:09:6c:ae:af:89:3f:2f:44:01:
                    35:50:1f:aa:3d:62:8f:f7:44:4c:f3:59:80:d6:09:
                    60:bd:21:2e:b5:3c:c2:94:39:ba:53:df:45:bc:06:
                    59:e4:c0:5c:a6:7f:d3:8b:67:af:cf:a6:79:0c:0c:
                    00:6f:e3:6e:68:78:47:7f:42:b3:ff:8a:42:f5:5e:
                    7b:81:fc:2e:ae:00:04:7d:39:3d:c3:bf:88:79:54:
                    b0:d0:06:ca:62:4d:46:a6:af:44:31:18:ad:5b:7c:
                    4f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                Server Authentication, Client Authentication
            X509v3 Subject Key Identifier:
                72:34:53:31:E5:46:35:40:AD:6B:6B:2C:05:E8:32:D1:07:62:5D:49
            X509v3 Authority Key Identifier:
                keyid:68:AA:E5:56:18:0F:A2:87:0A:F8:95:61:C0:CC:04:A7:DE:B7:50:AB
            X509v3 Subject Alternative Name:
                DNS:test-02.demo.networktechguy.com
            X509v3 Step Provisioner:
                Type: JWK
                Name: NTG
                CredentialID: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A
    Signature Algorithm: ECDSA-SHA256
         30:45:02:21:00:d1:98:ae:45:51:5d:9f:30:82:37:49:61:55:
         64:83:2a:d1:9b:80:3e:1a:48:3e:0f:d5:34:1d:f9:a5:9d:ed:
         25:02:20:64:a1:b1:4a:b9:2d:c9:1b:4b:c0:8a:6d:4e:13:a8:
         b6:00:02:31:c3:17:30:ba:a2:74:82:9c:c8:8e:ea:7a:17

You will notice that, while the certificate itself is using RSA as an algorithm, signing algorithm (from the CA) is actually ECDSA-SHA256 (the default signing algorithm for step-ca). If that is an issue for you and you require all certificates to be signed with RSA instead, you may want to take a look here. By default, the CA will sign certificate requests for RSA, ECDSA, or Ed25519 keys.

If you want to directly create a new certificate that is using RSA as an algorithm, you can do that as well:

$ step ca certificate test-03.demo.networktechguy.com test-03.demo.networktechguy.com.crt test-03.demo.networktechguy.com.key --kty RSA --size 2048

✔ Provisioner: NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
Please enter the password to decrypt the provisioner key: 
✔ CA: https://ca.demo.networktechguy.com
✔ Certificate: test-03.demo.networktechguy.com.crt
✔ Private Key: test-03.demo.networktechguy.com.key
💡
You will notice that I'm using commands that start with either step ca or step certificate in this blog post. step ca is used when we want to interact with the CA directly, while step certificate allows us to manipulate the certificate (or CSRs) locally, directly on the host/workstation.

Inspecting the certificate shows that it's using RSA:

$ step certificate inspect test-03.demo.networktechguy.com.crt 

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 35108943346902447396060278580001223444 (0x1a69bc8d47a44fe25bac1a53d299b314)
    Signature Algorithm: ECDSA-SHA256
        Issuer: O=NetworkTechGuy.com CA,CN=NetworkTechGuy.com CA Intermediate CA
        Validity
            Not Before: Sep 28 15:13:21 2024 UTC
            Not After : Sep 29 15:14:21 2024 UTC
        Subject: CN=test-03.demo.networktechguy.com
        Subject Public Key Info:
            Public Key Algorithm: RSA
                Public-Key: (2048 bit)
                Modulus:
                    f0:12:fc:dd:12:bb:9f:bc:98:e1:ae:88:79:4f:3e:
                    ed:43:a6:c3:f7:43:4f:78:a5:69:e6:a5:a4:c5:d9:
                    ec:18:be:e2:ef:a6:e5:67:72:96:d0:8c:0c:85:89:
                    a2:ae:68:dc:14:25:cd:74:43:b6:1f:cc:95:dc:cc:
                    90:6c:3d:72:54:ae:d0:36:ce:6d:3f:38:5d:ea:cc:
                    4e:47:f3:e1:c1:14:36:b0:9a:0d:03:55:fb:cc:b4:
                    9c:12:35:cd:d3:d8:c2:e1:f6:bf:06:b5:d4:28:e2:
                    6a:97:0f:32:01:dc:7d:b0:49:da:c1:5d:99:c4:84:
                    89:24:c3:ef:23:55:44:20:33:b5:e3:b5:c7:9a:ad:
                    15:1d:cf:ee:f4:ba:77:1b:53:ef:09:f0:bb:2e:92:
                    69:df:ae:94:b5:3b:91:e4:f6:a4:e9:ef:e1:4b:e0:
                    be:04:0b:7b:76:dd:c9:32:96:00:5b:ed:65:9b:d8:
                    9d:6a:fb:4d:ed:24:b8:26:7f:b3:67:1a:61:6e:c8:
                    ac:98:85:a9:d1:c5:c4:d0:88:5f:ef:ae:2f:f0:2f:
                    ad:3f:8b:4a:ee:94:df:c6:77:5c:7d:54:0d:d2:77:
                    84:b4:22:f3:bc:e0:6c:7b:aa:54:1f:6d:ff:0d:e8:
                    17:98:1c:9e:6a:b6:db:a5:69:59:f3:d4:f0:99:81:
                    93
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                Server Authentication, Client Authentication
            X509v3 Subject Key Identifier:
                8A:3B:AA:E0:DF:ED:B3:F2:A9:CB:A6:AB:A6:14:5A:51:F2:D1:CE:FD
            X509v3 Authority Key Identifier:
                keyid:68:AA:E5:56:18:0F:A2:87:0A:F8:95:61:C0:CC:04:A7:DE:B7:50:AB
            X509v3 Subject Alternative Name:
                DNS:test-03.demo.networktechguy.com
            X509v3 Step Provisioner:
                Type: JWK
                Name: NTG
                CredentialID: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A
    Signature Algorithm: ECDSA-SHA256
         30:44:02:20:20:da:22:45:5b:5c:24:09:c0:5f:d8:dc:46:e1:
         c8:c4:ff:e2:47:ba:ee:78:82:3b:ad:54:af:3b:fb:b6:95:93:
         02:20:4c:08:f1:f6:2f:ec:db:d8:9e:dd:d9:67:4a:0d:a7:09:
         35:fa:95:3c:45:2f:f6:c4:21:61:97:5f:4a:a3:69:4b

Finally, you may have noticed that all the certificates that we requested have a default validity of just one day (Not Before and Not After fields)! This is really inconvenient in most cases, but if we try and request a certificate that has longer validity, we get this:

$ step ca certificate test-04.demo.networktechguy.com test-04.demo.networktechguy.com.crt test-04.demo.networktechguy.com.key --kty RSA --size 2048 --not-after=18380h

✔ Provisioner: NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
Please enter the password to decrypt the provisioner key: 
Please enter the password to decrypt the provisioner key: 
✔ CA: https://ca.demo.networktechguy.com
The request was forbidden by the certificate authority: requested duration of 18380h1m0s is more than the authorized maximum certificate duration of 24h1m0s.
Re-run with STEPDEBUG=1 for more info.

Here, we requested a certificate that has validity of 18380 hours (2 years and a few months, give or take). The response was expected, but we definitely want to change that.

Back to the CA configuration

To do that, we have to go back to our CA server and edit the ca.json file at /etc/step-ca/config.

You will need to add something similar in your claims under your providers:

"minTLSCertDuration": "4834h0m0s"
"maxTLSCertDuration": "43830h0m0s"
"defaultTLSCertDuration": "17532h0m0s"

Here, I've defined that my minimum duration is set to 6 months, my maximum duration is set to 5 years and the default duration is set to 2 years.

These claims need to be added under your authority section of the ca.json file, and while we're doing these changes, we can make changes for the SSH CA provider as well:

"minUserSSHCertDuration": "4834h0m0s"
"maxUserSSHCertDuration": "43830h0m0s"
"defaultUserSSHCertDuration": "17532h0m0s"
"minHostSSHCertDuration": "4834h0m0s"
"maxHostSSHCertDuration": "43830h0m0s"
"defaultHostSSHCertDuration": "17532h0m0s"

Please note that ca.json file is a JSON file, so the structure of the file is extremely important. First of all, if you are continuing something that had only one entry before, something like this:

                        {
                                "type": "ACME",
                                "name": "acme"
                        }

You will notice that there is no , at the end of the line defining the name. Since we are adding new parameter to the config (claims), we will need to add a comma to the previous value, so that it looks something like this:

                        {
                                "type": "ACME",
                                "name": "acme",
                                "claims": {
                                }
                        }

Please make sure that all values that you add, if they are not the final value in the list, have a trailing comma as well. Final result should look something like this:

        "authority": {
                "provisioners": [
                        {
                                "type": "JWK",
                                "name": "NTG",
                                "key": {
                                        "use": "sig",
                                        "kty": "EC",
                                        "kid": "---OUTPUT OMITTED---",
                                        "crv": "P-256",
                                        "alg": "ES256",
                                        "x": "---OUTPUT OMITTED---",
                                        "y": "---OUTPUT OMITTED---"
                                },
                                "encryptedKey": "---OUTPUT OMITTED---",
                                "claims": {
                                        "enableSSHCA": true,
                                        "minTLSCertDuration": "4834h0m0s",
                                        "maxTLSCertDuration": "43830h0m0s",
                                        "defaultTLSCertDuration": "17532h0m0s"
                                }
                        },
                        {
                                "type": "ACME",
                                "name": "acme",
                                "claims": {
                                        "minTLSCertDuration": "4834h0m0s",
                                        "maxTLSCertDuration": "43830h0m0s",
                                        "defaultTLSCertDuration": "8766h0m0s"
                                }
                        },
                        {
                                "type": "SSHPOP",
                                "name": "sshpop",
                                "claims": {
                                        "enableSSHCA": true,
                                        "minUserSSHCertDuration": "4834h0m0s",
                                        "maxUserSSHCertDuration": "43830h0m0s",
                                        "defaultUserSSHCertDuration": "17532h0m0s",
                                        "minHostSSHCertDuration": "4834h0m0s",
                                        "maxHostSSHCertDuration": "43830h0m0s",
                                        "defaultHostSSHCertDuration": "17532h0m0s"
                                }
                        }
                ]
        },

When you're done with the config, restart the step-ca service (sudo systemctl restart step-ca) and check if everything is OK with sudo systemctl status step-ca:

sudo systemctl status step-ca
● step-ca.service - step-ca service
     Loaded: loaded (/etc/systemd/system/step-ca.service; enabled; preset: enabled)
     Active: active (running) since Sat 2024-09-28 12:35:46 EDT; 2s ago
       Docs: https://smallstep.com/docs/step-ca
             https://smallstep.com/docs/step-ca/certificate-authority-server-production
   Main PID: 1299 (step-ca)
      Tasks: 10 (limit: 4643)
     Memory: 17.3M
        CPU: 99ms
     CGroup: /system.slice/step-ca.service
             └─1299 /usr/bin/step-ca config/ca.json --password-file password.txt

Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 Documentation: https://u.step.sm/docs/ca
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 Community Discord: https://u.step.sm/discord
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 Config file: config/ca.json
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 The primary server URL is https://ca.demo.networktechguy.com:443
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 Root certificates are available at https://ca.demo.networktechguy.com:443/roots.pem
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 Additional configured hostnames: 10.75.1.10
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 X.509 Root Fingerprint: ---OUTPUT OMITTED---
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 SSH Host CA Key: ecdsa-sha2-nistp256 ---OUTPUT OMITTED---
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 SSH User CA Key: ecdsa-sha2-nistp256 ---OUTPUT OMITTED---
Sep 28 12:35:47 deb-step-01 step-ca[1299]: 2024/09/28 12:35:47 Serving HTTPS on :443 ...

Another test on the workstation

Now, let's go back to our workstation and try and request the certificate again:

$ step ca certificate test-04.demo.networktechguy.com test-04.demo.networktechguy.com.crt test-04.demo.networktechguy.com.key --kty RSA --size 2048 --not-after=18380h

✔ Provisioner: NTG (JWK) [kid: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A]
Please enter the password to decrypt the provisioner key: 
✔ CA: https://ca.demo.networktechguy.com
✔ Certificate: test-04.demo.networktechguy.com.crt
✔ Private Key: test-04.demo.networktechguy.com.key

If we inspect the certificate now, we will see that the validity of the new certificate is set to 2 years and a few months:

step certificate inspect test-04.demo.networktechguy.com.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 168037223532597902684174011559766671308 (0x7e6acac4449c5ebfcf68d48372a43fcc)
    Signature Algorithm: ECDSA-SHA256
        Issuer: O=NetworkTechGuy.com CA,CN=NetworkTechGuy.com CA Intermediate CA
        Validity
            Not Before: Sep 28 16:20:26 2024 UTC
            Not After : Nov 3 12:21:26 2026 UTC
        Subject: CN=test-04.demo.networktechguy.com
        Subject Public Key Info:
            Public Key Algorithm: RSA
                Public-Key: (2048 bit)
                Modulus:
                    c5:86:f4:e0:e1:1e:65:bf:de:6b:ef:95:5e:5f:56:
                    0c:42:e2:ac:ed:a6:4f:c3:3d:15:49:a6:37:d9:c3:
                    eb:e5:4d:79:19:37:c6:27:50:38:52:8b:41:61:09:
                    35:60:fb:21:5c:82:03:20:d2:ea:ff:cd:68:1a:e8:
                    42:fc:00:a0:3c:2e:12:c6:bc:34:be:0a:10:50:c3:
                    43:64:bb:bc:34:0d:f2:c7:f0:81:85:be:68:8e:cf:
                    77:79:ac:f1:c6:dc:89:02:71:b1:19:5c:82:8e:bd:
                    e2:8d:72:90:eb:08:6f:ae:43:66:3d:2f:f2:f4:f2:
                    20:17:f2:ab:79:0e:bb:28:a1:16:15:36:4f:a2:75:
                    46:02:2c:26:b0:e4:85:7c:3c:f0:c1:84:96:f8:15:
                    95:24:48:0c:07:63:49:9e:d7:2e:fb:28:69:f4:c2:
                    7e:7a:19:f4:46:32:55:39:f2:29:3a:90:aa:b1:8d:
                    e5:46:cd:39:40:6e:9e:79:a4:2b:a7:8c:0a:fe:37:
                    4d:41:60:9f:46:ca:22:e2:0e:bc:9f:bb:0b:e3:b1:
                    c0:63:b3:63:21:89:2d:68:2d:c9:e7:54:ca:30:9e:
                    98:45:53:65:c8:17:4f:42:96:11:97:8d:a9:24:74:
                    a4:f8:97:37:15:48:a8:08:02:7b:71:ec:3a:80:88:
                    47
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                Server Authentication, Client Authentication
            X509v3 Subject Key Identifier:
                6E:F8:14:EC:95:0C:9A:13:91:33:33:76:52:76:06:C8:3E:A6:92:DE
            X509v3 Authority Key Identifier:
                keyid:68:AA:E5:56:18:0F:A2:87:0A:F8:95:61:C0:CC:04:A7:DE:B7:50:AB
            X509v3 Subject Alternative Name:
                DNS:test-04.demo.networktechguy.com
            X509v3 Step Provisioner:
                Type: JWK
                Name: NTG
                CredentialID: 6zkvMKLGZxf0qa4n-cleOyn2seI04fweoAuOjBlcr4A
    Signature Algorithm: ECDSA-SHA256
         30:44:02:20:2a:c4:2a:d5:84:fd:d6:e0:1c:ee:0f:18:8a:ec:
         1e:08:69:63:6a:7d:ba:6a:52:32:fa:fd:ff:5c:4f:6b:e6:7e:
         02:20:61:6d:07:99:5c:1b:70:81:38:53:70:25:98:f3:96:60:
         d0:0b:e1:d7:d1:03:fa:3e:d6:00:0e:4f:5e:38:49:46

Final thoughts

And that's it. Now you have a fully functional CA in your environment and you will be able to use it to issue certificates to your services. On top of that, you also have ACME provisioner that we will utilise later on when deploying our services behind traefik. Fun stuff doesn't end here, as you now also have an SSH CA, that we will use to issue SSH certificates to our workstations to simplify connectivity and make it as secure as possible!

If you want to, you can inspect the certificate in your GUI and see the full chain as well:

Signed certificate for test-04.demo.networktechguy.com
⚠️
One thing to note - if you're using iOS devices in your environment, your certificates should not have validity beyond 825 days or they will be untrusted by default! This should not apply to the root certificate, but I haven't tested that yet.

You can read more about certificate requirements for iOS and macOS systems here:

Requirements for trusted certificates in iOS 13 and macOS 10.15 - Apple Support
Learn about new security requirements for TLS server certificates in iOS 13 and macOS 10.15.