mirror of
https://github.com/smallstep/certificates.git
synced 2024-11-09 13:10:36 +00:00
162 lines
6.4 KiB
Markdown
162 lines
6.4 KiB
Markdown
# Using ACME with `step-ca `
|
||
|
||
Let’s assume you’ve [installed
|
||
`step-ca`](https://smallstep.com/docs/getting-started/#1-installing-step-and-step-ca)
|
||
(e.g., using `brew install step`), have it running at `https://ca.internal`,
|
||
and you’ve [bootstrapped your ACME client
|
||
system(s)](https://smallstep.com/docs/getting-started/#bootstrapping) (or at
|
||
least [installed your root
|
||
certificate](https://smallstep.com/docs/cli/ca/root/) at
|
||
`~/.step/certs/root_ca.crt`).
|
||
|
||
## Enabling ACME
|
||
|
||
To enable ACME, simply [add an ACME provisioner](https://smallstep.com/docs/cli/ca/provisioner/add/) to your `step-ca` configuration
|
||
by running:
|
||
|
||
```
|
||
$ step ca provisioner add my-acme-provisioner --type ACME
|
||
```
|
||
|
||
> NOTE: The above command will add a new provisioner of type `ACME` and name
|
||
> `my-acme-provisioner`. The name is used to identify the provisioner
|
||
> (e.g. you cannot have two `ACME` provisioners with the same name).
|
||
|
||
Now restart or SIGHUP `step-ca` to pick up the new configuration.
|
||
|
||
That’s it.
|
||
|
||
## Configuring Clients
|
||
|
||
To configure an ACME client to connect to `step-ca` you need to:
|
||
|
||
1. Point the client at the right ACME directory URL
|
||
2. Tell the client to trust your CA’s root certificate
|
||
|
||
Once certificates are issued, you’ll also need to ensure they’re renewed before
|
||
they expire.
|
||
|
||
### Pointing Clients at the right ACME Directory URL
|
||
|
||
Most ACME clients connect to Let’s Encrypt by default. To connect to `step-ca`
|
||
you need to point the client at the right [ACME directory
|
||
URL](https://tools.ietf.org/html/rfc8555#section-7.1.1).
|
||
|
||
A single instance of `step-ca` can have multiple ACME provisioners, each with
|
||
their own ACME directory URL that looks like:
|
||
|
||
```
|
||
https://{ca-host}/acme/{provisioner-name}/directory
|
||
```
|
||
|
||
We just added an ACME provisioner named “acme”. Its ACME directory URL is:
|
||
|
||
```
|
||
https://ca.internal/acme/acme/directory
|
||
```
|
||
|
||
### Telling clients to trust your CA’s root certificate
|
||
|
||
Communication between an ACME client and server [always uses
|
||
HTTPS](https://tools.ietf.org/html/rfc8555#section-6.1). By default, client’s
|
||
will validate the server’s HTTPS certificate using the public root certificates
|
||
in your system’s [default
|
||
trust](https://smallstep.com/blog/everything-pki.html#trust-stores) store.
|
||
That’s fine when you’re connecting to Let’s Encrypt: it’s a public CA and its
|
||
root certificate is in your system’s default trust store already. Your internal
|
||
root certificate isn’t, so HTTPS connections from ACME clients to `step-ca` will
|
||
fail.
|
||
|
||
There are two ways to address this problem:
|
||
|
||
1. Explicitly configure your ACME client to trust `step-ca`'s root certificate, or
|
||
2. Add `step-ca`'s root certificate to your system’s default trust store (e.g.,
|
||
using [`step certificate
|
||
install`](https://smallstep.com/docs/cli/certificate/install/))
|
||
|
||
If you’re using your CA for TLS in production, explicitly configuring your ACME
|
||
client to only trust your root certificate is a better option. We’ll
|
||
demonstrate this method with several clients below.
|
||
|
||
If you’re simulating Let’s Encrypt in pre-production, installing your root
|
||
certificate is a more faithful simulation of production. Once your root
|
||
certificate is installed, no additional client configuration is necessary.
|
||
|
||
> Caution: adding a root certificate to your system’s trust store is a global
|
||
> operation. Certificates issued by your CA will be trusted everywhere,
|
||
> including in web browsers.
|
||
|
||
### Example using [`certbot`](https://certbot.eff.org/)
|
||
|
||
[`certbot`](https://certbot.eff.org/) is the grandaddy of ACME clients. Built
|
||
and supported by [the EFF](https://www.eff.org/), it’s the standard-bearer for
|
||
production-grade command-line ACME.
|
||
|
||
To get a certificate from `step-ca` using `certbot` you need to:
|
||
|
||
1. Point `certbot` at your ACME directory URL using the `--`server flag.
|
||
2. Tell `certbot` to trust your root certificate using the `REQUESTS_CA_BUNDLE` environment variable.
|
||
|
||
For example:
|
||
|
||
```
|
||
$ sudo REQUESTS_CA_BUNDLE=$(step path)/certs/root_ca.crt \
|
||
certbot certonly -n --standalone -d foo.internal \
|
||
--server https://ca.internal/acme/acme/directory
|
||
```
|
||
|
||
`sudo` is required in `certbot`'s [*standalone*
|
||
mode](https://certbot.eff.org/docs/using.html#standalone) so it can listen on
|
||
port 80 to complete the `http-01` challenge. If you already have a webserver
|
||
running you can use [*webroot*
|
||
mode](https://certbot.eff.org/docs/using.html#webroot) instead. With the
|
||
[appropriate plugin](https://certbot.eff.org/docs/using.html#dns-plugins)
|
||
`certbot` also supports the `dns-01` challenge for most popular DNS providers.
|
||
Deeper integrations with [nginx](https://certbot.eff.org/docs/using.html#nginx)
|
||
and [apache](https://certbot.eff.org/docs/using.html#apache) can even configure
|
||
your server to use HTTPS automatically (we'll set this up ourselves later). All
|
||
of this works with `step-ca`.
|
||
|
||
You can renew all of the certificates you've installed using `cerbot` by running:
|
||
|
||
```
|
||
$ sudo REQUESTS_CA_BUNDLE=$(step path)/certs/root_ca.crt certbot renew
|
||
```
|
||
|
||
You can automate renewal with a simple `cron` entry:
|
||
|
||
```
|
||
*/15 * * * * root REQUESTS_CA_BUNDLE=$(step path)/certs/root_ca.crt certbot -q renew
|
||
```
|
||
|
||
The `certbot` packages for some Linux distributions will create a `cron` entry
|
||
or [systemd
|
||
timer](https://stevenwestmoreland.com/2017/11/renewing-certbot-certificates-using-a-systemd-timer.html)
|
||
like this for you. This entry won't work with `step-ca` because it [doesn't set
|
||
the `REQUESTS_CA_BUNDLE` environment
|
||
variable](https://github.com/certbot/certbot/issues/7170). You'll need to
|
||
manually tweak it to do so.
|
||
|
||
More subtly, `certbot`'s default renewal job is tuned for Let's Encrypt's 90
|
||
day certificate lifetimes: it's run every 12 hours, with actual renewals
|
||
occurring for certificates within 30 days of expiry. By default, `step-ca`
|
||
issues certificates with *much shorter* 24 hour lifetimes. The `cron` entry
|
||
above accounts for this by running `certbot renew` every 15 minutes. You'll
|
||
also want to configure your domain to only renew certificates when they're
|
||
within a few hours of expiry by adding a line like:
|
||
|
||
```
|
||
renew_before_expiry = 8 hours
|
||
```
|
||
|
||
to the top of your renewal configuration (e.g., in `/etc/letsencrypt/renewal/foo.internal.conf`).
|
||
|
||
## Feedback
|
||
|
||
`step-ca` should work with any ACMEv2
|
||
([RFC8555](https://tools.ietf.org/html/rfc8555)) compliant client that supports
|
||
the http-01 or dns-01 challenge.
|
||
|
||
Post feedback on [our GitHub Discussions tab](https://github.com/smallstep/certificates/discussions),
|
||
or [create a bug report issue](https://github.com/smallstep/certificates/issues/new?template=bug_report.md).
|