Based on the step ca setup as described in Running your own ACME Server, we can add another provisioner that allows us to manually sign CSRs from web servers that do not support Certbot. One example for such use case would be system solutions like TrueNAS or Proxmox, which by now have ACME support but do not support easy customization or override of the ACME server URL. In fact, many system solutions with ACME support assume that only Let’s Encrypt is used when obtaining certificates via ACME protocol.
In this blog post we look at how to add further provisioners for smallstep’s step ca.
Adding a simple provisioner via command line
More or less only one command is needed to add a provisioner. We need to pass in the name of the provisioner (4weeks), the location of the ca config file, the location of the password file and the create command.
andreas@acme ➜ ~ sudo step ca provisioner add 4weeks --ca-config /usr/local/etc/step/ca/config/ca.json --password-file /usr/local/etc/step/password.txt --create
Looking at the /usr/local/etc/step/ca/config/ca.json configuration file we can find the following new block next to our existing ACME provisioner.
{
"type": "JWK",
"name": "4weeks",
"key": {
"use": "sig",
"kty": "EC",
"kid": "WsxEssolEVj1TpF-nfXpSuY2jL8pLQgpCtgVj5Qq3Ls",
"crv": "P-256",
"alg": "ES256",
"x": "5b9f1pk6VVM5CCIHUOpbw6SV8lC-rAxEQtiScRZUopE",
"y": "hxRrUPm7M6S7HBm9LZV5JUbBLP7l2aG4CKr1vY20csw"
},
"encryptedKey": "eyJh... <<REDACTED>> ...no1w"
}
We called our provisioner 4weeks for a reason – we want certificates be valid for 4 weeks (672 hours). That said, we need to add a claims section to the provisioner that clarifies the validity. When adding the claims section, do not forget to comply with JSON and make sure to append a comma to the last line before the new section.
{
"type": "JWK",
"name": "4weeks",
"key": {
"use": "sig",
"kty": "EC",
"kid": "WsxEssolEVj1TpF-nfXpSuY2jL8pLQgpCtgVj5Qq3Ls",
"crv": "P-256",
"alg": "ES256",
"x": "5b9f1pk6VVM5CCIHUOpbw6SV8lC-rAxEQtiScRZUopE",
"y": "hxRrUPm7M6S7HBm9LZV5JUbBLP7l2aG4CKr1vY20csw"
},
"encryptedKey": "eyJh... <<REDACTED>> ...no1w",
"claims": {
"minTLSCertDuration": "24h0m0s",
"maxTLSCertDuration": "672h0m0s",
"defaultTLSCertDuration": "672h0m0s",
"disableRenewal": false
}
}
To make the change effective, the service needs to be restarted.
andreas@acme ➜ ~ sudo service step-ca restart Stopping step_ca. Starting step_ca. step_ca is running as pid 96773.
Import a CSR
While this blog post will not cover how to create a CSR, we start by copying a CSR onto our step ca server. For the remainder of this blog post we assume request.csr to be the name of that CSR.
Issue a Certificate
The step ca command line tools available allow us to issue a certificate with a token. The first step is to create such token, which we export into an environment variable for later use.
andreas@acme ➜ ~ export TOKEN=`step ca token 'newserver.local' --ca-url https://acme.local:8443 --root /etc/ssl/tinkivity.pem` ✔ Provisioner: 4weeks (JWK) [kid: WsxEssolEVj1TpF-nfXpSuY2jL8pLQgpCtgVj5Qq3Ls] ✔ Please enter the password to decrypt the provisioner key:
The command is interactive and will first ask us to select one provisioner from the list of all available provisioners. After we select our provisioner (4weeks), we are being asked for the password to decrypt the provisioner key.
As an alternative to the interactive password input, we could add the –pasword-file directive to the command. That way we don’t have to input our password, but we would need to run the command as sudo in order to get read access to the password file.
andreas@acme ➜ ~ export TOKEN=`step ca token 'newserver.local' --ca-url https://acme.local:8443 --root /etc/ssl/tinkivity.pem --password-file /usr/local/etc/step/password.txt`
Either way the command should complete without error and our token should be available.
andreas@acme ➜ ~ echo $TOKEN eyJhbGciOiJFUzI1NiIsImtpZCI6IldzeEVzc29sRVZqMVRwRi1uZlhwU3VZMmpMOHBMUWdwQ3RnVmo1UXEzTHMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL2FjbWUudGlua2l2aXR5LmhvbWU6ODQ0My8xLjAvc2lnbiIsImV4cCI6MTYwNzAxNTA1NywiaWF0IjoxNjA3MDE0NzU3LCJpc3MiOiI0d2Vla3MiLCJqdGkiOiI3ZDRlZjViZWI3YWQ2NzA1ZTkzNDY3NmMwMjhjMmY3OWFjMmRmNzMxODIwZDg3NDc0NWJmYzMyNzIwMmIyOTNjIiwibmJmIjoxNjA3MDE0NzU3LCJzYW5zIjpbIkFuZHJlYXMgU3RyYXVjaCJdLCJzaGEiOiIwMzUxMWI1YzRjZmNlZWJlNjI5YzJjMjQ2YTIzMjMwYjhhYzQxNDQyOTI0MjliOGMzN2ZhM2FjMGE3MmUwZmM5Iiwic3ViIjoiQW5kcmVhcyBTdHJhdWNoIn0.gaOwV7nEVq8cOL4uVvp1Y4-c3NUMs0YKMri0N9Q9MQRAWnvCg8BKuntSxThIeywvM0gMO2QND_9iz9VObFRULg
All that’s left to do now is to sign the certificate with our token.
andreas@acme ➜ ~ step ca sign --token $TOKEN incoming/request.csr issued/certificate.csr ✔ CA: https://acme.local:8443/1.0/sign ✔ Certificate: issued/certificate.csr
That’s it. The certificate is ready to be deployed.
