Remove deprecated docs directory
|
@ -1,740 +0,0 @@
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
Demonstrates setting up your own public key infrastructure (PKI) and certificate authority (CA) using `step ca`
|
|
||||||
and getting certificates using the `step` command line tool and SDK.
|
|
||||||
|
|
||||||
Check out [Getting started with docker](docker.md) to run [step certificates](https://github.com/smallstep/certificates)
|
|
||||||
using docker.
|
|
||||||
|
|
||||||
![Animated terminal showing step ca init in practice](https://smallstep.com/images/blog/2018-12-04-unfurl.gif)
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
* [Step CA](#installation-guide)
|
|
||||||
|
|
||||||
## Terminology
|
|
||||||
|
|
||||||
### PKI - Public Key Infrastructure
|
|
||||||
|
|
||||||
A set of roles, policies, and procedures needed to create, manage, distribute,
|
|
||||||
use, store, and revoke digital certificates and manage public-key encryption.
|
|
||||||
The purpose of a PKI is to facilitate the secure electronic transfer of
|
|
||||||
information for a range of network activities.
|
|
||||||
|
|
||||||
### Provisioners
|
|
||||||
|
|
||||||
Provisioners are people or code that are registered with the CA and authorized
|
|
||||||
to issue "provisioning tokens". Provisioning tokens are single use tokens that
|
|
||||||
can be used to authenticate with the CA and get a certificate.
|
|
||||||
|
|
||||||
See [provisioners.md](provisioners.md) for more information on the supported
|
|
||||||
provisioners and its options.
|
|
||||||
|
|
||||||
## Initializing PKI and configuring the Certificate Authority
|
|
||||||
|
|
||||||
To initialize a PKI and configure the Step Certificate Authority run:
|
|
||||||
|
|
||||||
> **NOTE**: `step ca init` only initialize an x509 CA. If you
|
|
||||||
> would like to initialize an SSH CA as well, add the `--ssh` flag.
|
|
||||||
|
|
||||||
```
|
|
||||||
step ca init [--ssh]
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll be asked for a name for your PKI. This name will appear in your CA
|
|
||||||
certificates. It doesn't really matter what you choose. The name of your
|
|
||||||
organization or your project will suffice.
|
|
||||||
|
|
||||||
If you run:
|
|
||||||
|
|
||||||
```
|
|
||||||
tree $(step path)
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see:
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── certs
|
|
||||||
│ ├── intermediate_ca.crt
|
|
||||||
│ ├── root_ca.crt
|
|
||||||
│ ├── ssh_host_key.pub (--ssh only)
|
|
||||||
│ └── ssh_user_key.pub (--ssh only)
|
|
||||||
├── config
|
|
||||||
│ ├── ca.json
|
|
||||||
│ └── defaults.json
|
|
||||||
└── secrets
|
|
||||||
├── intermediate_ca_key
|
|
||||||
├── root_ca_key
|
|
||||||
├── ssh_host_key (--ssh only)
|
|
||||||
└── ssh_user_key (--ssh only)
|
|
||||||
```
|
|
||||||
|
|
||||||
The files created include:
|
|
||||||
|
|
||||||
* `root_ca.crt` and `root_ca_key`: the root certificate and private key for
|
|
||||||
your PKI.
|
|
||||||
|
|
||||||
* `intermediate_ca.crt` and `intermediate_ca_key`: the intermediate certificate
|
|
||||||
and private key that will be used to sign leaf certificates.
|
|
||||||
|
|
||||||
* `ssh_host_key.pub` and `ssh_host_key` (`--ssh` only): the SSH host pub/priv key
|
|
||||||
pair that will be used to sign new host SSH certificates.
|
|
||||||
|
|
||||||
* `ssh_user_key.pub` and `ssh_user_key` (`--ssh` only): the SSH user pub/priv key
|
|
||||||
pair that will be used to sign new user SSH certificates.
|
|
||||||
|
|
||||||
* `ca.json`: the configuration file necessary for running the Step CA.
|
|
||||||
|
|
||||||
* `defaults.json`: file containing default parameters for the `step` CA cli
|
|
||||||
interface. You can override these values with the appropriate flags or
|
|
||||||
environment variables.
|
|
||||||
|
|
||||||
All of the files ending in `_key` are password protected using the password
|
|
||||||
you chose during PKI initialization. We advise you to change these passwords
|
|
||||||
(using the `step crypto change-pass` utility) if you plan to run your CA in a
|
|
||||||
non-development environment.
|
|
||||||
|
|
||||||
## What's Inside `ca.json`?
|
|
||||||
|
|
||||||
`ca.json` is responsible for configuring communication, authorization, and
|
|
||||||
default new certificate values for the Step CA. Below is a short list of
|
|
||||||
definitions and descriptions of available configuration attributes.
|
|
||||||
|
|
||||||
* `root`: location of the root certificate on the filesystem. The root certificate
|
|
||||||
is used to mutually authenticate all api clients of the CA.
|
|
||||||
|
|
||||||
* `crt`: location of the intermediate certificate on the filesystem. The
|
|
||||||
intermediate certificate is returned alongside each new certificate,
|
|
||||||
allowing the client to complete the certificate chain.
|
|
||||||
|
|
||||||
* `key`: location of the intermediate private key on the filesystem. The
|
|
||||||
intermediate key signs all new certificates generated by the CA.
|
|
||||||
|
|
||||||
* `password`: optionally store the password for decrypting the intermediate private
|
|
||||||
key (this should be the same password you chose during PKI initialization). If
|
|
||||||
the value is not stored in configuration then you will be prompted for it when
|
|
||||||
starting the CA.
|
|
||||||
|
|
||||||
* `address`: e.g. `127.0.0.1:8080` - address and port on which the CA will bind
|
|
||||||
and respond to requests.
|
|
||||||
|
|
||||||
* `dnsNames`: comma separated list of DNS Name(s) for the CA.
|
|
||||||
|
|
||||||
* `logger`: the default logging format for the CA is `text`. The other option
|
|
||||||
is `json`.
|
|
||||||
|
|
||||||
* `db`: data persistence layer. See [database documentation](./database.md) for more
|
|
||||||
info.
|
|
||||||
* `type`: `badger`, `bbolt`, `mysql`, etc.
|
|
||||||
* `dataSource`: string that can be interpreted differently depending on the
|
|
||||||
type of the database. Usually a path to where the data is stored. See the
|
|
||||||
[database configuration docs](./database.md#configuration) for more info.
|
|
||||||
* `database`: name of the database. Used for backends that may have multiple
|
|
||||||
databases. e.g. MySQL
|
|
||||||
* `valueDir`: directory to store the value log in (Badger specific).
|
|
||||||
|
|
||||||
* `crl`: Certificate Revocation List settings:
|
|
||||||
* `enable`: enables CRL generation (`true` to generate, `false` to disable)
|
|
||||||
* `generateOnRevoke`: a revoke will generate a new CRL if the crl is enabled.
|
|
||||||
* `cacheDuration`: the duration until next update of the CRL, defaults to 24h.
|
|
||||||
* `renewPeriod`: the time between CRL regeneration. If not set ~2/3 of the
|
|
||||||
cacheDuration will be used.
|
|
||||||
|
|
||||||
* `tls`: settings for negotiating communication with the CA; includes acceptable
|
|
||||||
ciphersuites, min/max TLS version, etc.
|
|
||||||
|
|
||||||
* `authority`: controls the request authorization and signature processes.
|
|
||||||
|
|
||||||
- `template`: default ASN1DN values for new certificates.
|
|
||||||
|
|
||||||
- `claims`: default validation for requested attributes in the certificate request.
|
|
||||||
Can be overriden by similar claims objects defined by individual provisioners.
|
|
||||||
|
|
||||||
* `minTLSCertDuration`: do not allow certificates with a duration less
|
|
||||||
than this value.
|
|
||||||
|
|
||||||
* `maxTLSCertDuration`: do not allow certificates with a duration greater
|
|
||||||
than this value.
|
|
||||||
|
|
||||||
* `defaultTLSCertDuration`: if no certificate validity period is specified,
|
|
||||||
use this value.
|
|
||||||
|
|
||||||
* `disableIssuedAtCheck`: disable a check verifying that provisioning
|
|
||||||
tokens must be issued after the CA has booted. This is one prevention
|
|
||||||
against token reuse. The default value is `false`. Do not change this
|
|
||||||
unless you know what you are doing.
|
|
||||||
|
|
||||||
SSH CA properties
|
|
||||||
|
|
||||||
* `minUserSSHDuration`: do not allow certificates with a duration less
|
|
||||||
than this value.
|
|
||||||
|
|
||||||
* `maxUserSSHDuration`: do not allow certificates with a duration
|
|
||||||
greater than this value.
|
|
||||||
|
|
||||||
* `defaultUserSSHDuration`: if no certificate validity period is specified,
|
|
||||||
use this value.
|
|
||||||
|
|
||||||
* `minHostSSHDuration`: do not allow certificates with a duration less
|
|
||||||
than this value.
|
|
||||||
|
|
||||||
* `maxHostSSHDuration`: do not allow certificates with a duration
|
|
||||||
greater than this value.
|
|
||||||
|
|
||||||
* `defaultHostSSHDuration`: if no certificate validity period is specified,
|
|
||||||
use this value.
|
|
||||||
|
|
||||||
* `enableSSHCA`: enable all provisioners to generate SSH Certificates.
|
|
||||||
The deault value is `false`. You can enable this option per provisioner
|
|
||||||
by setting it to `true` in the provisioner claims.
|
|
||||||
|
|
||||||
- `provisioners`: list of provisioners.
|
|
||||||
See the [provisioners documentation](./provisioners.md). Each provisioner
|
|
||||||
has an optional `claims` attribute that can override any attribute defined
|
|
||||||
at the level above in the `authority.claims`.
|
|
||||||
|
|
||||||
`step ca init` will generate one provisioner. New provisioners can be added by
|
|
||||||
running `step ca provisioner add`.
|
|
||||||
|
|
||||||
## Running the CA
|
|
||||||
|
|
||||||
To start the CA run:
|
|
||||||
|
|
||||||
```
|
|
||||||
export STEPPATH=$(step path)
|
|
||||||
step-ca $STEPPATH/config/ca.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Systemctl
|
|
||||||
|
|
||||||
Consider adding a service user that will only be used by `systemctl` to manage
|
|
||||||
the service.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ useradd step
|
|
||||||
$ passwd -l step
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the following example as a base for your `systemctl` service file:
|
|
||||||
|
|
||||||
```
|
|
||||||
[Unit]
|
|
||||||
Description=step-ca
|
|
||||||
After=syslog.target network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
|
|
||||||
User=step
|
|
||||||
Group=step
|
|
||||||
ExecStart=/bin/sh -c '/bin/step-ca /home/step/.step/config/ca.json --password-file=/home/step/.step/pwd >> /var/log/step-ca/output.log 2>&1'
|
|
||||||
Type=simple
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
|
|
||||||
The following are a few example commands you can use to check the status,
|
|
||||||
enable on restart, and start your `systemctl` service.
|
|
||||||
|
|
||||||
```
|
|
||||||
# Check the current status of the `step-ca` service
|
|
||||||
$ systemctl status step-ca
|
|
||||||
# Configure the `step-ca` process to startup on reboot automatically
|
|
||||||
$ systemctl enable step-ca
|
|
||||||
# Start the `step-ca` service.
|
|
||||||
$ systemctl start step-ca
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configure Your Environment
|
|
||||||
|
|
||||||
**Note**: Configuring your environment is only necessary for remote servers
|
|
||||||
(not the server on which the `step ca init` command was originally run).
|
|
||||||
|
|
||||||
Many of the cli utilities under `step ca [sub-command]` interface directly with
|
|
||||||
a running instance of the Step CA. The CA exposes an HTTP API and clients are
|
|
||||||
required to connect using HTTP over TLS (aka HTTPS). As part of bootstraping
|
|
||||||
the Step CA, a certificate was generated using the root of trust that was
|
|
||||||
created when you initilialized your PKI. In order to properly validate this
|
|
||||||
certificate clients need access to the public root of trust, aka the public root
|
|
||||||
certificate. If you are using the `step cli` on the same host where you
|
|
||||||
initialized your PKI (the `root_ca.crt` is stored on disk locally), then you can
|
|
||||||
continue to [setting up your environment](#setup-env),
|
|
||||||
otherwise we will show you how to easily download your root certificate in the
|
|
||||||
following step.
|
|
||||||
|
|
||||||
#### Download the Root Certificate
|
|
||||||
|
|
||||||
The next few steps are a guide for downloading the root certificate of your PKI
|
|
||||||
from a running instance of the CA. First we'll define two servers:
|
|
||||||
|
|
||||||
* **remote server**: This is the server where the Step CA is running. This may
|
|
||||||
also be the server where you initialized your PKI, but for security reasons
|
|
||||||
you may have done that offline.
|
|
||||||
|
|
||||||
* **local server**: This is the server that wants access to the `step ca [sub-command]`
|
|
||||||
|
|
||||||
* **ca-url**: This is the url at which the CA is listening for requests. This
|
|
||||||
should be a combination of the DNS name and port entered during PKI initialization.
|
|
||||||
In the examples below we will use `https://ca.smallstep.com:8080`.
|
|
||||||
|
|
||||||
1. Get the Fingerprint.
|
|
||||||
|
|
||||||
From the **remote server**:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ FP=$(step certificate fingerprint $(step path)/certs/root_ca.crt)
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Bootstrap your environment.
|
|
||||||
|
|
||||||
From the **local server**:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step ca bootstrap --fingerprint $FP --ca-url "https://ca.smallstep.com:8080"
|
|
||||||
$ cat $(step path)/config/defaults.json
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Test.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step ca health
|
|
||||||
```
|
|
||||||
|
|
||||||
<a name="setup-env"></a>
|
|
||||||
#### Setting up Environment Defaults
|
|
||||||
|
|
||||||
This is optional, but we recommend you populate a `defaults.json` file with a
|
|
||||||
few variables that will make your command line experience much more pleasant.
|
|
||||||
|
|
||||||
You can do this manually or with the step command `step ca bootstrap`:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step ca bootstrap \
|
|
||||||
--ca-url https://ca.smallstep.com:8080 \
|
|
||||||
--fingerprint 0d7d3834cf187726cf331c40a31aa7ef6b29ba4df601416c9788f6ee01058cf3
|
|
||||||
# Let's see what we got...
|
|
||||||
$ cat $STEPPATH/config/defaults.json
|
|
||||||
{
|
|
||||||
"ca-url": "https://ca.smallstep.com:8080",
|
|
||||||
"fingerprint": "628cfc85090ca65bb246d224f1217445be155cfc6167db4ed8f1b0e3de1447c5",
|
|
||||||
"root": "/Users/<you>/src/github.com/smallstep/step/.step/certs/root_ca.crt"
|
|
||||||
}
|
|
||||||
# Test it out
|
|
||||||
$ step ca health
|
|
||||||
```
|
|
||||||
|
|
||||||
* **ca-url** is the DNS name and port that you used when initializing the CA.
|
|
||||||
|
|
||||||
* **root** is the path to the root certificate on the file system.
|
|
||||||
|
|
||||||
* **fingerprint** is the root certificate fingerprint (SHA256).
|
|
||||||
|
|
||||||
You can always override these values with command-line flags or environment
|
|
||||||
variables.
|
|
||||||
|
|
||||||
To manage the CA provisioners you can also add the property **ca-config** with
|
|
||||||
the path to the CA configuration file, with that property you won't need to add
|
|
||||||
it in commands like `step ca provisioners [add|remove]`.
|
|
||||||
**Note**: to manage provisioners you must be on the host on which the CA is
|
|
||||||
running. You need direct access to the `ca.json` file.
|
|
||||||
|
|
||||||
### Hot Reload
|
|
||||||
|
|
||||||
It is important that the CA be able to handle configuration changes with no downtime.
|
|
||||||
Our CA has a built in `reload` function allowing it to:
|
|
||||||
|
|
||||||
1. Finish processing existing connections while blocking new ones.
|
|
||||||
2. Parse the configuration file and re-initialize the API.
|
|
||||||
3. Begin accepting blocked and new connections.
|
|
||||||
|
|
||||||
`reload` is triggered by sending a SIGHUP to the PID (see `man kill`
|
|
||||||
for your OS) of the Step CA process. A few important details to note when using `reload`:
|
|
||||||
|
|
||||||
* The location of the modified configuration must be in the same location as it
|
|
||||||
was in the original invocation of `step-ca`. So, if the original command was
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step-ca ./.step/config/ca.json
|
|
||||||
```
|
|
||||||
|
|
||||||
then, upon `reload`, the Step CA will read it's new configuration from the same
|
|
||||||
configuration file.
|
|
||||||
|
|
||||||
* Step CA requires the password to decrypt the intermediate certificate, again,
|
|
||||||
upon `reload`. You can automate this in one of two ways:
|
|
||||||
|
|
||||||
* Use the `--password-file` flag in the original invocation.
|
|
||||||
* Use the top level `password` attribute in the `ca.json` configuration file.
|
|
||||||
|
|
||||||
### Let's issue a certificate!
|
|
||||||
|
|
||||||
There are two steps to issuing a certificate at the command line:
|
|
||||||
|
|
||||||
1. Generate a provisioning token using your provisioning credentials.
|
|
||||||
2. Generate a CSR and exchange it, along with the provisioning token, for a certificate.
|
|
||||||
|
|
||||||
If you would like to generate a certificate from the command line, the Step CLI
|
|
||||||
provides a single command that will prompt you to select and decrypt an
|
|
||||||
authorized provisioner and then request a new certificate.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step ca certificate "foo.example.com" foo.crt foo.key
|
|
||||||
```
|
|
||||||
|
|
||||||
If you would like to generate certificates on demand from an automated
|
|
||||||
configuration management solution (no user input) you would split the above flow
|
|
||||||
into two commands.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ TOKEN=$(step ca token foo.example.com \
|
|
||||||
--kid 4vn46fbZT68Uxfs9LBwHkTvrjEvxQqx-W8nnE-qDjts \
|
|
||||||
--ca-url https://ca.example.com \
|
|
||||||
--root /path/to/root_ca.crt --password-file /path/to/provisioner/password)
|
|
||||||
|
|
||||||
$ step ca certificate "foo.example.com" foo.crt foo.key --token "$TOKEN"
|
|
||||||
```
|
|
||||||
|
|
||||||
You can take a closer look at the contents of the certificate using `step certificate inspect`:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step certificate inspect foo.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
### List|Add|Remove Provisioners
|
|
||||||
|
|
||||||
The Step CA configuration is initialized with one provisioner; one entity
|
|
||||||
that is authorized by the CA to generate provisioning tokens for new certificates.
|
|
||||||
We encourage you to have many provisioners - ideally one for each entity in your
|
|
||||||
infrastructure.
|
|
||||||
|
|
||||||
**Why should I be using multiple provisioners?**
|
|
||||||
|
|
||||||
* Each certificate generated by the Step CA contains the ID of the provisioner
|
|
||||||
that issued the *provisioning token* authorizing the creation of the cert. This
|
|
||||||
ID is stored in the X.509 ExtraExtensions of the certificate under
|
|
||||||
`OID: 1.3.6.1.4.1.37476.9000.64.1` and can be inspected by running `step
|
|
||||||
certificate inspect foo.crt`. These IDs can and should be used to debug and
|
|
||||||
gather information about the origin of a certificate. If every member of your
|
|
||||||
ops team and the configuration management tools all use the same provisioner
|
|
||||||
to authorize new certificates you lose valuable visibility into the workings
|
|
||||||
of your PKI.
|
|
||||||
* Each provisioner should require a **unique** password to decrypt it's private key
|
|
||||||
-- we can generate unique passwords for you but we can't force you to use them.
|
|
||||||
If you only have one provisioner then every entity in the infrastructure will
|
|
||||||
need access to that one password. Jim from your dev ops team should not be using
|
|
||||||
the same provisioner/password combo to authorize certificates for debugging as
|
|
||||||
Chef is for your CICD - no matter how trustworthy Jim says he is.
|
|
||||||
|
|
||||||
Let's begin by listing the existing provisioners:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/step ca provisioner list
|
|
||||||
```
|
|
||||||
|
|
||||||
Now let's add a provisioner for Jim.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/step ca provisioner add jim@smallstep.com --create
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE**: This change will not affect the Step CA until a `reload` is forced by
|
|
||||||
sending a SIGHUP signal to the process.
|
|
||||||
|
|
||||||
List the provisioners again and you will see that nothing has changed.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/step ca provisioner list
|
|
||||||
```
|
|
||||||
|
|
||||||
Now let's `reload` the CA. You will need to re-enter your intermediate
|
|
||||||
password unless it's in your `ca.json` or you are using `--password-file`.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ps aux | grep step-ca # to get the PID
|
|
||||||
$ kill -1 <pid>
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the CA is running again, list the provisioners, again.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/step ca provisioner list
|
|
||||||
```
|
|
||||||
|
|
||||||
Boom! Magic.
|
|
||||||
Now suppose Jim forgets his password ('come on Jim!'), and he'd like to remove
|
|
||||||
his old provisioner. Get the `kid` (Key ID) of Jim's provisioner by listing
|
|
||||||
the provisioners and finding the appropriate one. Then run:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/step ca provisioner remove jim@smallstep.com --kid <kid>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then `reload` the CA and verify that Jim's provisioner is no longer returned
|
|
||||||
in the provisioner list.
|
|
||||||
|
|
||||||
We can also remove all of Jim's provisioners, supposing Jim forgot all the passwords
|
|
||||||
('really Jim?'), by running the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/step ca provisioner remove jim@smallstep.com --all
|
|
||||||
```
|
|
||||||
|
|
||||||
The same entity may have multiple provisioners for authorizing different
|
|
||||||
types of certs. Each of these provisioners must have unique keys.
|
|
||||||
|
|
||||||
## Use Custom Claims for Provisioners to Control Certificate Validity etc
|
|
||||||
|
|
||||||
It's possible to configure provisioners on the CA to issue certs using
|
|
||||||
properties specific to their target environments. Most commonly different
|
|
||||||
validity periods and disabling renewals for certs. Here's how:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ step ca init
|
|
||||||
# complete the init steps
|
|
||||||
$ step ca provisioner add --create dev@smallstep.com
|
|
||||||
# lets create a provisioner for dev certs
|
|
||||||
Please enter a password to encrypt the provisioner private key? password
|
|
||||||
# add claims inside a provisioner element in ~/.step/config/ca.json
|
|
||||||
~/.step/config/ca.json
|
|
||||||
[...]
|
|
||||||
"authority": {
|
|
||||||
"provisioners": [
|
|
||||||
{
|
|
||||||
"name": "you@smallstep.com",
|
|
||||||
"type": "jwk",
|
|
||||||
"key": {
|
|
||||||
"use": "sig",
|
|
||||||
"kty": "EC",
|
|
||||||
"kid": "Kg43gSukHnl8f5NztLPDxqpz_9TNUILnMrIMIa70jOU",
|
|
||||||
"crv": "P-256",
|
|
||||||
"alg": "ES256",
|
|
||||||
"x": "So0JVWFFXo-6GmDwq6WWZZk-AFZt5GKTx5PzdLhdsrQ",
|
|
||||||
"y": "kVz8pCl2Qx9fZmJZhXGrHpufwNDTp7oHwi8Zaj7rhiQ"
|
|
||||||
},
|
|
||||||
"encryptedKey": "...",
|
|
||||||
+ "claims": {
|
|
||||||
+ "minTLSCertDuration": "5s",
|
|
||||||
+ "maxTLSCertDuration": "12h",
|
|
||||||
+ "defaultTLSCertDuration": "2h",
|
|
||||||
+ "disableRenewal": true
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
[...]
|
|
||||||
|
|
||||||
## launch CA...
|
|
||||||
$ step-ca $(step path)/config/ca.json
|
|
||||||
Please enter the password to decrypt ~/.step/secrets/intermediate_ca_key: password
|
|
||||||
2019/02/21 12:09:51 Serving HTTPS on :9443 ...
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [`provisioner doc`][1] for details on all available provisioner claims.
|
|
||||||
The durations are strings which are a sequence of decimal numbers, each with
|
|
||||||
optional fraction and a unit suffix, such as "300ms" or "2h45m". Valid time
|
|
||||||
units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
Now certs issued by the `dev@smallstep.com` provisioner will be valid for two
|
|
||||||
hours and deny renewals. Command line flags allow validity extension up to 12h,
|
|
||||||
please see [`step ca certificate`][2]'s docs for details.
|
|
||||||
|
|
||||||
[1]: ./provisioners.md
|
|
||||||
[2]: https://smallstep.com/docs/cli/ca/certificate/
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# grab a cert, will also work with 'step ca token' flow
|
|
||||||
$ step ca certificate localhost site.crt site.key
|
|
||||||
Use the arrow keys to navigate: ↓ ↑ → ←
|
|
||||||
What provisioner key do you want to use?
|
|
||||||
IY7gYg_cDKmXtcs1sbhdBDDb9K9YvLO5aHzArjaayso (sebastian@smallstep.com)
|
|
||||||
▸ uBYWYDCpeJu_IYzMGPZ1LJJTdlaiJQfdpkOVewbjy-8 (dev@smallstep.com)
|
|
||||||
|
|
||||||
✔ Please enter the password to decrypt the provisioner key: password
|
|
||||||
✔ CA: https://ca.smallstep.com:9443/1.0/sign
|
|
||||||
✔ Certificate: site.crt
|
|
||||||
✔ Private Key: site.key
|
|
||||||
|
|
||||||
$ step certificate inspect site.crt --format json | jq .validity
|
|
||||||
{
|
|
||||||
"start": "2019-02-21T20:19:06Z",
|
|
||||||
"end": "2019-02-21T22:19:06Z",
|
|
||||||
"length": 7200
|
|
||||||
}
|
|
||||||
|
|
||||||
# renewals will be denied for certs issued by this provisioner
|
|
||||||
$ step ca renew site.crt site.key
|
|
||||||
error renewing certificate: Unauthorized
|
|
||||||
```
|
|
||||||
|
|
||||||
## Use Oauth OIDC to obtain personal certificates
|
|
||||||
|
|
||||||
To authenticate users with the CA you can leverage services that expose OAuth
|
|
||||||
OpenID Connect identity providers. One of the most common providers, and the
|
|
||||||
one we'll use in this example, is G-Suite.
|
|
||||||
|
|
||||||
Navigate to the Google APIs developer console and pick a suitable project from the
|
|
||||||
top navbar's dropdown.
|
|
||||||
|
|
||||||
![Google Dev Console](./images/oidc1.png)
|
|
||||||
|
|
||||||
In the masthead navigation click **Credentials** (key symbol) and then "OAuth
|
|
||||||
consent screen" from the subnav. Fill out naming details, all mandatory fields,
|
|
||||||
and decide if your app is of type **Public** or **Internal**. Internal
|
|
||||||
will make sure the access scope is bound to your G-Suite organization.
|
|
||||||
**Public** will let anybody with a Google Account log in, incl.
|
|
||||||
`gmail.com` accounts.
|
|
||||||
|
|
||||||
Move back to **Credentials** on the subnav and choose "OAuth client ID" from the
|
|
||||||
**Create credentials** dropdown. Since OIDC will be used from the `step CLI` pick **Other**
|
|
||||||
from the available options and pick a name (e.g. **Step CLI**).
|
|
||||||
|
|
||||||
![Create credential](./images/oidc2.png)
|
|
||||||
|
|
||||||
On successful completion, a confirmation modal with both `clientID` and
|
|
||||||
`clientSecret` will be presented. Please note that the `clientSecret` will
|
|
||||||
allow applications access to the configured OAuth consent screen. However, it
|
|
||||||
will not allow direct authentication of users without their own MfA credentials
|
|
||||||
per account.
|
|
||||||
|
|
||||||
![OIDC credentials](./images/oidc3.png)
|
|
||||||
|
|
||||||
Now using `clientID` and `clientSecret` run the following command to add
|
|
||||||
G-Suite as a provisioner to `step certificates`. Please see [`step ca
|
|
||||||
provisioner add`](https://smallstep.com/docs/cli/ca/provisioner/add/)'s docs
|
|
||||||
for all available configuration options and descriptions.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ step ca provisioner add Google --type oidc --ca-config $(step path)/config/ca.json \
|
|
||||||
--client-id 972437157139-ssiqna0g4ibuhafl3pkrrcb52tbroekt.apps.googleusercontent.com \
|
|
||||||
--client-secret RjEk-GwKBvdsFAICiJhn_RiF \
|
|
||||||
--configuration-endpoint https://accounts.google.com/.well-known/openid-configuration \
|
|
||||||
--domain yourdomain.com --domain gmail.com
|
|
||||||
```
|
|
||||||
|
|
||||||
Start up the online CA or send a HUP signal if it's already running to reload
|
|
||||||
the configuration and pick up the new provisioner. Now users should be able to
|
|
||||||
obtain certificates using the familiar `step ca certificate` flow:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ step ca certificate sebastian@smallstep.com personal.crt personal.key
|
|
||||||
Use the arrow keys to navigate: ↓ ↑ → ←
|
|
||||||
What provisioner key do you want to use?
|
|
||||||
fYDoiQdYueq_LAXx2kqA4N_Yjf_eybe-wari7Js5iXI (admin)
|
|
||||||
▸ 972437157139-ssiqna0g4ibuhafl3pkrrcb52tbroekt.apps.googleusercontent.com (Google)
|
|
||||||
✔ Key ID: 972437157139-ssiqna0g4ibuhafl3pkrrcb52tbroekt.apps.googleusercontent.com (Google)
|
|
||||||
✔ CA: https://localhost
|
|
||||||
✔ Certificate: personal.crt
|
|
||||||
✔ Private Key: personal.key
|
|
||||||
|
|
||||||
$ step certificate inspect --short personal.crt ⏎
|
|
||||||
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 6169...4235]
|
|
||||||
Subject: 106202051347258973689
|
|
||||||
sebastian@smallstep.com
|
|
||||||
Issuer: Local CA Intermediate CA
|
|
||||||
Provisioner: Google [ID: 9724....com]
|
|
||||||
Valid from: 2019-03-26T20:36:28Z
|
|
||||||
to: 2019-03-27T20:36:28Z
|
|
||||||
```
|
|
||||||
|
|
||||||
Now it's easy for anybody in the G-Suite organization to obtain valid personal
|
|
||||||
certificates!
|
|
||||||
|
|
||||||
## Notes on Securing the Step CA and your PKI.
|
|
||||||
|
|
||||||
In this section we recommend a few best practices when it comes to
|
|
||||||
running, deploying, and managing your own online CA and PKI. Security is a moving
|
|
||||||
target and we expect out recommendations to change and evolve as well.
|
|
||||||
|
|
||||||
### Initializing your PKI
|
|
||||||
|
|
||||||
When you initialize your PKI two private keys are generated; one intermediate
|
|
||||||
private key and one root private key. It is very important that these private keys
|
|
||||||
are kept secret. The root private key should be moved around as little as possible,
|
|
||||||
preferably not all - meaning it never leaves the server on which it was created.
|
|
||||||
|
|
||||||
### Passwords
|
|
||||||
|
|
||||||
When you initialize your PKI (`step ca init`) the root and intermediate
|
|
||||||
private keys will be encrypted with the same password. We recommend that you
|
|
||||||
change the password with which the intermediate is encrypted at your earliest
|
|
||||||
convenience.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ step crypto change-pass $STEPPATH/secrets/intermediate_ca_key
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you've changed the intermediate private key password you should never have
|
|
||||||
to use the root private key password again.
|
|
||||||
|
|
||||||
We encourage users to always use a password manager to generate random passwords
|
|
||||||
or let Step CLI generate passwords for you.
|
|
||||||
|
|
||||||
The next important matter is how your passwords are stored. We recommend using a
|
|
||||||
[password manager](https://en.wikipedia.org/wiki/List_of_password_managers).
|
|
||||||
There are many to choose from and the choice will depend on the risk & security
|
|
||||||
profile of your organization.
|
|
||||||
|
|
||||||
In addition to using a password manager to store all passwords (private key,
|
|
||||||
provisioner, etc.) we recommend using a threshold cryptography algorithm like
|
|
||||||
[Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir's_Secret_Sharing)
|
|
||||||
to divide the root private key password across a handful of trusted parties.
|
|
||||||
|
|
||||||
### Provisioners
|
|
||||||
|
|
||||||
When you initialize your PKI (`step ca init`) a default provisioner will be created
|
|
||||||
and it's private key will be encrypted using the same password used to encrypt
|
|
||||||
the root private key. Before deploying the Step CA you should remove this
|
|
||||||
provisioner and add new ones that are encrypted with new, secure, random passwords.
|
|
||||||
See the section on [managing provisioners](#listaddremove-provisioners).
|
|
||||||
|
|
||||||
### Deploying
|
|
||||||
|
|
||||||
* Refrain from entering passwords for private keys or provisioners on the command line.
|
|
||||||
Use the `--password-file` flag whenever possible.
|
|
||||||
* Run the Step CA as a new user and make sure that the config files, private keys,
|
|
||||||
and passwords used by the CA are stored in such a way that only this new user
|
|
||||||
has permissions to read and write them.
|
|
||||||
* Use short lived certificates. Our default validity period for new certificates
|
|
||||||
is 24 hours. You can configure this value in the `ca.json` file. Shorter is
|
|
||||||
better - less time to form an attack.
|
|
||||||
* Short lived certificates are **not** a replacement for CRL and OCSP. CRL and OCSP
|
|
||||||
are features that we plan to implement, but are not yet available. In the mean
|
|
||||||
time short lived certificates are a decent alternative.
|
|
||||||
* Keep your hosts secure by enforcing AuthN and AuthZ for every connection. SSH
|
|
||||||
access is a big one.
|
|
||||||
|
|
||||||
<a name="step-ca-ha"></a>
|
|
||||||
## Notes on Running Step CA as a Highly Available Service
|
|
||||||
|
|
||||||
**CAUTION**: `step-ca` is built to scale horizontally. However, the creators
|
|
||||||
and maintainers do not regularly test in an HA environment using mulitple
|
|
||||||
instances. You may run into issues we did not plan for. If this happens, please
|
|
||||||
[open an issue][3].
|
|
||||||
|
|
||||||
### Considerations
|
|
||||||
|
|
||||||
A few things to consider / implement when running multiple instances of `step-ca`:
|
|
||||||
|
|
||||||
* Use `MySQL` DB: The default `Badger` DB cannot be read / written by more than one
|
|
||||||
process simultaneously. The only supported DB that can support multiple instances
|
|
||||||
is `MySQL`. See the [database documentation][4] for guidance on configuring `MySQL`.
|
|
||||||
* The ACME server has known concurrency limitations when using the same account to
|
|
||||||
manage multiple orders. The recommended temporary workaround is to generate
|
|
||||||
an ephemeral account keypair for each new ACME order, or to ensure that ACME
|
|
||||||
orders owned by the same account are managed serially. The issue tracking
|
|
||||||
this limitation can be found [here](https://github.com/smallstep/certificates/issues/341).
|
|
||||||
|
|
||||||
* Synchronize `ca.json` across instances: `step-ca` reads all of it's
|
|
||||||
configuration (and all of the provisioner configuration) from the `ca.json` file
|
|
||||||
specified on the command line. If the `ca.json` of one instance is modified
|
|
||||||
(either manually or using a command like `step ca provisioner (add | remove)`)
|
|
||||||
the other instances will not pick up on this change until the `ca.json` is
|
|
||||||
copied over to the correct location for each instance and the instance itself
|
|
||||||
is `SIGHUP`'ed (or restarted). It's recommended to use a configuration management
|
|
||||||
(ansible, chef, salt, puppet, etc.) tool to synchronize `ca.json` across instances.
|
|
||||||
|
|
||||||
[3]: https://github.com/smallstep/certificates/issues
|
|
||||||
[4]: ./database.md
|
|
|
@ -1,41 +0,0 @@
|
||||||
# Step Certificates Documentation
|
|
||||||
|
|
||||||
## Note: Much of [our documentation has moved](https://smallstep.com/docs)
|
|
||||||
|
|
||||||
Index of Documentation and Tutorials for using and deploying the `step certificates`.
|
|
||||||
|
|
||||||
[![GitHub release](https://img.shields.io/github/release/smallstep/certificates.svg)](https://github.com/smallstep/certificates/releases)
|
|
||||||
[![CA Image](https://images.microbadger.com/badges/image/smallstep/step-ca.svg)](https://microbadger.com/images/smallstep/step-ca)
|
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/smallstep/certificates)](https://goreportcard.com/report/github.com/smallstep/certificates)
|
|
||||||
[![Build Status](https://travis-ci.com/smallstep/certificates.svg?branch=master)](https://travis-ci.com/smallstep/certificates)
|
|
||||||
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
|
|
||||||
[![CLA assistant](https://cla-assistant.io/readme/badge/smallstep/certificates)](https://cla-assistant.io/smallstep/certificates)
|
|
||||||
|
|
||||||
[![GitHub stars](https://img.shields.io/github/stars/smallstep/certificates.svg?style=social)](https://github.com/smallstep/certificates/stargazers)
|
|
||||||
[![Twitter followers](https://img.shields.io/twitter/follow/smallsteplabs.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=smallsteplabs)
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
* **General Info**
|
|
||||||
* [Website](https://smallstep.com)
|
|
||||||
* [Installation Guide](https://smallstep.com/docs/step-ca/installation)
|
|
||||||
* [Getting Started](https://smallstep.com/docs/step-ca/getting-started): in depth guide on getting started
|
|
||||||
with `step-ca`, including all configuration options.
|
|
||||||
* [Contributor's Guide](./CONTRIBUTING.md)
|
|
||||||
* [Sane Defaults](https://smallstep.com/docs/step-ca/certificate-authority-server-production#sane-cryptographic-defaults): default algorithms and attributes used
|
|
||||||
in cryptographic primitives and why they were selected.
|
|
||||||
* [Frequently Asked Questions](./questions.md)
|
|
||||||
* Check out our [Blog](https://smallstep.com/blog/). We post quality
|
|
||||||
educational content as well as periodic updates on new releases.
|
|
||||||
* **API**: Guides to using the API via the `step` CLI.
|
|
||||||
* [Revoking Certificates](https://smallstep.com/docs/step-ca/revocation)
|
|
||||||
* [Persistence Layer](https://smallstep.com/docs/step-ca/configuration#databases): description and guide to using `step certificates`'
|
|
||||||
persistence layer for storing certificate management metadata.
|
|
||||||
* **Tutorials**: Guides for deploying and getting started with `step` in various environments.
|
|
||||||
* [Docker](./docker.md)
|
|
||||||
* [Kubernetes](../autocert/README.md)
|
|
||||||
|
|
||||||
## Further Reading
|
|
||||||
|
|
||||||
* [Use TLS Everywhere](https://smallstep.com/blog/use-tls.html)
|
|
||||||
* [Everything you should know about certificates and PKI but are too afraid to ask](https://smallstep.com/blog/everything-pki.html)
|
|
161
docs/acme.md
|
@ -1,161 +0,0 @@
|
||||||
# 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).
|
|
217
docs/cas.md
|
@ -1,217 +0,0 @@
|
||||||
# Registration Authorities
|
|
||||||
|
|
||||||
This document describes how to use an external registration authority (RA), aka
|
|
||||||
certificate authority service (CAS) to sign X.509 certificates requests.
|
|
||||||
|
|
||||||
A CAS is a system that implements an API to sign certificate requests, the
|
|
||||||
difference between CAS and KMS is that the latter can sign any data, while CAS
|
|
||||||
is intended to sign only X.509 certificates.
|
|
||||||
|
|
||||||
`step-ca` defines an interface that can be implemented to support other
|
|
||||||
registration authorities, currently only CloudCAS and the default SoftCAS are
|
|
||||||
implemented.
|
|
||||||
|
|
||||||
The `CertificateAuthorityService` is defined in the package
|
|
||||||
`github.com/smallstep/certificates/cas/apiv1` and it is:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type CertificateAuthorityService interface {
|
|
||||||
CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error)
|
|
||||||
RenewCertificate(req *RenewCertificateRequest) (*RenewCertificateResponse, error)
|
|
||||||
RevokeCertificate(req *RevokeCertificateRequest) (*RevokeCertificateResponse, error)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The same package defines another interface that is used to get the root
|
|
||||||
certificates from the CAS:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type CertificateAuthorityGetter interface {
|
|
||||||
GetCertificateAuthority(req *GetCertificateAuthorityRequest) (*GetCertificateAuthorityResponse, error)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## SoftCAS
|
|
||||||
|
|
||||||
SoftCAS is the default implementation supported by `step-ca`. No special
|
|
||||||
configurations are required to enable it.
|
|
||||||
|
|
||||||
SoftCAS generally uses certificates and keys in the filesystem, but a KMS can
|
|
||||||
also be used instead of a key file for signing certificates. See [KMS](kms.md)
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
## CloudCAS
|
|
||||||
|
|
||||||
CloudCAS is the implementation of the `CertificateAuthorityService` and
|
|
||||||
`CertificateAuthorityGetter` interfaces using [Google's Certificate Authority
|
|
||||||
Service](https://cloud.google.com/certificate-authority-service/).
|
|
||||||
|
|
||||||
Before enabling CloudCAS in `step-ca` you do some steps in Google Cloud Console
|
|
||||||
or using `gcloud` CLI:
|
|
||||||
|
|
||||||
1. Create or define a project to use. Let's say the name is `smallstep-cas-test`.
|
|
||||||
2. Create the KMS keyring and keys for root and intermediate certificates:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# Create key ring
|
|
||||||
gcloud kms keyrings create kr1 --location us-west1
|
|
||||||
# Create key for Root certificate
|
|
||||||
gcloud kms keys create k1 \
|
|
||||||
--location us-west1 \
|
|
||||||
--keyring kr1 \
|
|
||||||
--purpose asymmetric-signing \
|
|
||||||
--default-algorithm ec-sign-p256-sha256 \
|
|
||||||
--protection-level software
|
|
||||||
# Create key for Intermediate certicate
|
|
||||||
gcloud kms keys create k2 \
|
|
||||||
--location us-west1 \
|
|
||||||
--keyring kr1 \
|
|
||||||
--purpose asymmetric-signing \
|
|
||||||
--default-algorithm ec-sign-p256-sha256 \
|
|
||||||
--protection-level software
|
|
||||||
|
|
||||||
# Put the resource name for version 1 of the new KMS keys into a shell variable.
|
|
||||||
# This will be used in the other instructions below.
|
|
||||||
KMS_ROOT_KEY_VERSION=$(gcloud kms keys versions describe 1 --key k1 --keyring kr1 --location us-west1 --format "value(name)")
|
|
||||||
KMS_INTERMEDIATE_KEY_VERSION=$(gcloud kms keys versions describe 1 --key k2 --keyring kr1 --location us-west1 --format "value(name)")
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Enable the CA service API. You can do it on the console or running:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gcloud services enable privateca.googleapis.com
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Configure IAM. Create a service account using Google Console or running:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# Create service account
|
|
||||||
gcloud iam service-accounts create step-ca-sa \
|
|
||||||
--project smallstep-cas-test \
|
|
||||||
--description "Step-CA Service Account" \
|
|
||||||
--display-name "Step-CA Service Account"
|
|
||||||
# Add permissions to use the privateca API
|
|
||||||
gcloud projects add-iam-policy-binding smallstep-cas-test \
|
|
||||||
--member=serviceAccount:step-ca-sa@smallstep-cas-test.iam.gserviceaccount.com \
|
|
||||||
--role=roles/privateca.caManager
|
|
||||||
gcloud projects add-iam-policy-binding smallstep-cas-test \
|
|
||||||
--member=serviceAccount:step-ca-sa@smallstep-cas-test.iam.gserviceaccount.com \
|
|
||||||
--role=roles/privateca.certificateRequester
|
|
||||||
# Download the credentials.file
|
|
||||||
gcloud iam service-accounts keys create credentials.json \
|
|
||||||
--iam-account step-ca-sa@smallstep-cas-test.iam.gserviceaccount.com
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Create a Root CA. You can do this on the console or running:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gcloud beta privateca roots create prod-root-ca \
|
|
||||||
--location us-west1 \
|
|
||||||
--kms-key-version "$KMS_ROOT_KEY_VERSION" \
|
|
||||||
--subject "CN=Example Root CA, O=Example LLC" \
|
|
||||||
--max-chain-length 2
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Create an Intermediate CA. You can do this on the console or running:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
gcloud beta privateca subordinates create prod-intermediate-ca \
|
|
||||||
--location us-west1 \
|
|
||||||
--issuer prod-root-ca \
|
|
||||||
--issuer-location us-west1 \
|
|
||||||
--kms-key-version "$KMS_INTERMEDIATE_KEY_VERSION" \
|
|
||||||
--subject "CN=Example Intermediate CA, O=Example LLC" \
|
|
||||||
--reusable-config "subordinate-server-tls-pathlen-0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Now it's time to enable it in `step-ca` by adding some new files in the
|
|
||||||
`"authority"` section of the `ca.json`.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"authority": {
|
|
||||||
"type": "cloudCAS",
|
|
||||||
"credentialsFile": "/path/to/credentials.json",
|
|
||||||
"certificateAuthority": "projects/<name>/locations/<loc>/certificateAuthorities/<ca-name>",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* **type** defines the name of the CAS to use, _cloudCAS_ must be used to enable it.
|
|
||||||
* **credentialsFile** defines the path to a Google Cloud credential file with
|
|
||||||
access to Google's Certificate AuthorityService. We created this file before
|
|
||||||
in step 4. Instead of setting this property, the environment variable
|
|
||||||
`GOOGLE_APPLICATION_CREDENTIALS` can be pointed to the file to use. Or if the
|
|
||||||
`step-ca` is running in Google Cloud, the default service account in the
|
|
||||||
machine can also be used.
|
|
||||||
* **certificateAuthority** defines the Google Cloud resource to the intermediate
|
|
||||||
(or subordinated) certificate to use. We created this resource in step 6.
|
|
||||||
|
|
||||||
As we said before, the CloudCAS implementation in `step-ca` also defines the
|
|
||||||
interface `CertificateAuthorityGetter`, this allows `step-ca` to automatically
|
|
||||||
download the root certificate from Cloud CAS. In the `ca.json` now you don't
|
|
||||||
need to configure `"root"`, and because the intermediate is in Google Cloud,
|
|
||||||
`"crt"` and `"key"` are no needed. A full `ca.json` can look like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"address": ":443",
|
|
||||||
"dnsNames": ["ca.example.com"],
|
|
||||||
"logger": {"format": "text"},
|
|
||||||
"db": {
|
|
||||||
"type": "badger",
|
|
||||||
"dataSource": "/home/jane/.step/db",
|
|
||||||
},
|
|
||||||
"authority": {
|
|
||||||
"type": "cloudCAS",
|
|
||||||
"credentialsFile": "/home/jane/.step/credentials.json",
|
|
||||||
"certificateAuthority": "projects/smallstep-cas-test/locations/us-west1/certificateAuthorities/prod-intermediate-ca",
|
|
||||||
"provisioners": [
|
|
||||||
{
|
|
||||||
"type": "JWK",
|
|
||||||
"name": "jane@example.com",
|
|
||||||
"key": {
|
|
||||||
"use": "sig",
|
|
||||||
"kty": "EC",
|
|
||||||
"kid": "ehFT9BkVOY5k_eIiMax0ZxVZCe2hlDVkMwZ2Y78av4s",
|
|
||||||
"crv": "P-256",
|
|
||||||
"alg": "ES256",
|
|
||||||
"x": "GtEftN0_ED1lNc2SEUJDXV9EMi7JY-kqINPIEQJIkjM",
|
|
||||||
"y": "8HYFdNe1MbWcbclF-hU1L80SCmMcZQI6vZfTOXfPOjg"
|
|
||||||
},
|
|
||||||
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiSjBSWnY5UFZrM3JKRUJkem5RbExzZyJ9.Fiwvo-RIKU5G6v5udeCT1nlX87ElxrocP2FcgNs3AqEz5OH9H4suew.NmzUJR_9xv8ynQC8.dqOveA_G5kn5lxjxnEZoJCystnJMVYLkZ_8CVzfJQhYchbZfNk_-FKdIuQxeWWBzvmomsILFNtLOIUoqSt30qk83lFyGQWN8Ke2bK5DhuwojF7RI_UqkMyiKP0F28Z4ZFhfQP5D2ZT_stoFaMlU8eak0-T8MOiBIfdAJTWM9x2DN-68mtUBuL5z5eU8bqsxELnjGauD_GHTdnduOosmYsw8vp_PmffTTwqUzDFH1RhkeSmRFRZntAizZMGYkxLamquHI3Jvuqiv4eeJ3yLqh3Ppyo_mVQKnxM7P9TyTxcvLkb2dB3K-cItl1fpsz92cy8euKsKG8n5-hKFRyPfY.j7jBN7nUwatoSsIZuNIwHA"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tls": {
|
|
||||||
"cipherSuites": [
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
|
||||||
],
|
|
||||||
"minVersion": 1.2,
|
|
||||||
"maxVersion": 1.3,
|
|
||||||
"renegotiation": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The we only need to run `step-ca` as usual, but this time, the CA will print the
|
|
||||||
root fingerprint too:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ step-ca /home/jane/.step/config/ca.json
|
|
||||||
2020/09/22 13:17:15 Using root fingerprint '3ef16343cf0952eedbe2b843066bb798fa7a7bceb16aa285e8b0399f661b28b7'
|
|
||||||
2020/09/22 13:17:15 Serving HTTPS on :9000 ...
|
|
||||||
```
|
|
||||||
|
|
||||||
We will need to bootstrap once our environment using the printed fingerprint:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
step ca bootstrap --ca-url https://ca.example.com --fingerprint 3ef16343cf0952eedbe2b843066bb798fa7a7bceb16aa285e8b0399f661b28b7
|
|
||||||
```
|
|
||||||
|
|
||||||
And now we can sign sign a certificate as always:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
step ca certificate test.example.com test.crt test.key
|
|
||||||
```
|
|
106
docs/database.md
|
@ -1,106 +0,0 @@
|
||||||
# Step Certificates Database
|
|
||||||
|
|
||||||
`step certificates` uses a simple key-value interface over popular database
|
|
||||||
implementations to store persistent certificate management meta-data.
|
|
||||||
|
|
||||||
Our recommended default database implementation is
|
|
||||||
[nosql-Badger](https://github.com/smallstep/nosql/badger) - a NoSQL interface
|
|
||||||
over the popular [Badger](https://github.com/dgraph-io/badger) database.
|
|
||||||
|
|
||||||
## What will the database store?
|
|
||||||
|
|
||||||
As a first pass, the database layer will store every certificate (along with
|
|
||||||
metadata surrounding the provisioning of the certificate) and revocation data
|
|
||||||
that will be used to enforce passive revocation.
|
|
||||||
|
|
||||||
## Implementations
|
|
||||||
|
|
||||||
Current implementations include Badger (default), BoltDB, and MysQL.
|
|
||||||
|
|
||||||
- [ ] Memory
|
|
||||||
- [x] No database
|
|
||||||
- [x] [BoltDB](https://github.com/etcd-io/bbolt) -- etcd fork.
|
|
||||||
- [x] [Badger](https://github.com/dgraph-io/badger)
|
|
||||||
- [x] [MySQL/MariaDB](https://github.com/go-sql-driver/mysql)
|
|
||||||
- [ ] PostgreSQL
|
|
||||||
- [ ] Cassandra
|
|
||||||
|
|
||||||
Let us know which integration you would like to see next by opening an issue or PR.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Configuring `step certificates` to use a database is as simple as adding a
|
|
||||||
top-level `db` stanza to `$(step path)/config/ca.json`. Below are a few examples for supported databases:
|
|
||||||
|
|
||||||
### Badger
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"db": {
|
|
||||||
"type": "badger",
|
|
||||||
"dataSource": "./.step/db",
|
|
||||||
"valueDir": "./.step/valuedb"
|
|
||||||
"badgerFileLoadingMode": "MemoryMap"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Options for `db`:
|
|
||||||
|
|
||||||
* `type`
|
|
||||||
* `badger` - currently refers to Badger V1. However, as Badger V1 is deprecated,
|
|
||||||
this will refer to Badger V2 starting with a the next major version release.
|
|
||||||
* `badgerV1` - explicitly select Badger V1.
|
|
||||||
* `badgerV2` - explicitly select Badger V2. Anyone looking to use Badger V2
|
|
||||||
will need to set it explicitly until it becomes the default.
|
|
||||||
* `dataSource` - path, database directory.
|
|
||||||
* `valueDir` [optional] - path, value directory, only if different from `dataSource`.
|
|
||||||
* `badgerFileLoadingMode` [optional] - can be set to `FileIO` (instead of the default
|
|
||||||
`MemoryMap`) to avoid memory-mapping log files. This can be
|
|
||||||
useful in environments with low RAM. Make sure to use `badgerV2` as the
|
|
||||||
database `type` if using this option.
|
|
||||||
* `MemoryMap` - default.
|
|
||||||
* `FileIO` - This can be useful in environments with low RAM.
|
|
||||||
|
|
||||||
### BoltDB
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"db": {
|
|
||||||
"type": "bbolt",
|
|
||||||
"dataSource": "./stepdb"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
### MySQL
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"db": {
|
|
||||||
"type": "mysql",
|
|
||||||
"dataSource": "user:password@tcp(127.0.0.1:3306)/",
|
|
||||||
"database": "myDatabaseName"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
As the interface is a key-value store, the schema is very simple. We support
|
|
||||||
`tables`, `keys`, and `values`. An entry in the database is a `[]byte value`
|
|
||||||
that is indexed by `[]byte table` and `[]byte key`.
|
|
||||||
|
|
||||||
## Data Backup
|
|
||||||
|
|
||||||
Backing up your data is important, and it's good hygiene. We chose
|
|
||||||
[Badger](https://github.com/dgraph-io/badger) as our default file based data
|
|
||||||
storage backend because it has mature tooling for running common database
|
|
||||||
tasks. See the [documentation](https://github.com/dgraph-io/badger#database-backup)
|
|
||||||
for a guide on backing up your data.
|
|
227
docs/defaults.md
|
@ -1,227 +0,0 @@
|
||||||
# Default Algorithms and Attributes for Tokens, Keys, Certificates, etc.
|
|
||||||
|
|
||||||
The `step` ecosystem aims to be a "easy to use and hard to misuse" suite of PKI
|
|
||||||
tools. This means we need to select sane defaults for the myriad
|
|
||||||
configuration options that exist when using cryptographic primitives and higher
|
|
||||||
order abstractions (e.g. JWTs).
|
|
||||||
|
|
||||||
Below we document significant configuration options that we have selected as
|
|
||||||
defaults. These selections will change and evolve over time; security and
|
|
||||||
cryptography are constantly changing in response to real world pressures. We
|
|
||||||
intend for this document be an accurate representation of current best practices
|
|
||||||
in the industry, and to have these practices codified as defaults in the `step
|
|
||||||
certificates` code base. If you have questions, suggestions, or comments about
|
|
||||||
any of these decisions please let us know by opening an issue on this repo,
|
|
||||||
reaching out through [GitHub Discussions](https://github.com/smallstep/certificates/discussions).
|
|
||||||
|
|
||||||
## Tokens
|
|
||||||
|
|
||||||
We use JWTs (JSON Web Tokens) to prove authenticity and identity within the
|
|
||||||
Step ecosystem. JWTs have received negative attention because they are easy to
|
|
||||||
misuse and misconfigure. We agree! But lots of things are easy to misuse. We also
|
|
||||||
believe that when configured well JWTs are a great way to sign and encode data.
|
|
||||||
Our JWT's are, by default, short-lived (5 minute lifespan) and one time use
|
|
||||||
during the lifetime of the Step CA. We use a 1 minute clock drift leeway
|
|
||||||
because that was the recommended default in the reputable JWT package that we
|
|
||||||
chose. If using Step JWTs or your own JWTs in your code be sure to verify and
|
|
||||||
validate every single standard attribute of the JWT. JWTs, like all
|
|
||||||
cryptographic tools, are useless without proper attention to configuration and
|
|
||||||
guidelines.
|
|
||||||
|
|
||||||
## Keys
|
|
||||||
|
|
||||||
RSA keys don't scale very well. To get 128 bits of security, you need 3,072-bit
|
|
||||||
RSA keys, which are noticeably slower. ECDSA keys provide an alternative
|
|
||||||
that offers better security and better performance. At 256 bits, ECDSA keys
|
|
||||||
provide 128 bits of security. A small number of older clients don't support
|
|
||||||
ECDSA, but most modern clients do.
|
|
||||||
|
|
||||||
**Default Key Type**: ECDSA
|
|
||||||
|
|
||||||
**Default Curve Bits**: P-256
|
|
||||||
|
|
||||||
We've chosen the AES encryption algorithm (aka Rijndael) for writing private
|
|
||||||
keys to disk because it was the official choice of the Advanced
|
|
||||||
Encryption Standard contest. The three supported key sizes are 128, 192, and
|
|
||||||
256. Each of these is considered to be unbreakable for the forseeable future,
|
|
||||||
therefore we chose 128 bits as our default because the performance is
|
|
||||||
better (as compared to the greater key sizes) and because we agree, with
|
|
||||||
the designers of the algorithm, that 128 bits are quite sufficient for
|
|
||||||
most security needs.
|
|
||||||
|
|
||||||
**Default PEMCipher**: AES128
|
|
||||||
|
|
||||||
## X.509 Certificate Defaults
|
|
||||||
|
|
||||||
### Root Certificate
|
|
||||||
|
|
||||||
* Validity (10 year window)
|
|
||||||
* **Not Before**: Now
|
|
||||||
|
|
||||||
* **Not After**: Now + 10 years
|
|
||||||
|
|
||||||
A 10 year window seems advisable until software and tools can be written
|
|
||||||
for rotating the root certificate.
|
|
||||||
|
|
||||||
* **Basic Constraints**
|
|
||||||
* **CA**: TRUE
|
|
||||||
|
|
||||||
The root certificate is a Certificate Authority, it will be used to sign
|
|
||||||
other Certificates.
|
|
||||||
|
|
||||||
* **pathlen**: 1
|
|
||||||
|
|
||||||
The path length constraint expresses the number of possible intermediate
|
|
||||||
CA certificates in a path built from an end-entity certificate up to the
|
|
||||||
CA certificate. An absent path length constraint means that there is no
|
|
||||||
limitation to the number of intermediate certificates from end-entity to
|
|
||||||
the CA certificate. The smallstep PKI has only one intermediate CA
|
|
||||||
certificate between end-entity certificates and the root CA certificcate.
|
|
||||||
|
|
||||||
* **Key Usage** describes how the certificate can be used.
|
|
||||||
* **Certificate Sign**
|
|
||||||
|
|
||||||
Indicates that our root public key will be used to verify a signature on
|
|
||||||
certificates.
|
|
||||||
|
|
||||||
* **CRL Sign**
|
|
||||||
|
|
||||||
Indicates that our root public key will be used to verify a signature on
|
|
||||||
revocation information, such as CRL.
|
|
||||||
|
|
||||||
### Intermediate Certificate
|
|
||||||
|
|
||||||
* Validity (10 year window)
|
|
||||||
* **Not Before**: Now
|
|
||||||
* **Not After**: Now + 10 years
|
|
||||||
|
|
||||||
A 10 year window seems advisable until software and tools can be written
|
|
||||||
for rotating the root certificate.
|
|
||||||
|
|
||||||
* **Basic Constraints**
|
|
||||||
* **CA**: TRUE
|
|
||||||
|
|
||||||
The intermediate certificate is a Certificate Authority, used to sign
|
|
||||||
end-entity (service, process, job, etc.) certificates.
|
|
||||||
* **pathlen**: 0
|
|
||||||
|
|
||||||
The path length constraint expresses the number of possible intermediate
|
|
||||||
CA certificates in a path built from an end-entity certificate up to the
|
|
||||||
CA certificate. An absent path length constraint means that there is no
|
|
||||||
limitation to the number of intermediate certificates from end-entity to
|
|
||||||
the CA certificate. There are no additional intermediary certificates in
|
|
||||||
the path between the smallstep intermediate CA and end-entity certificates.
|
|
||||||
|
|
||||||
* **Key Usage**
|
|
||||||
* **Certificate Signing**
|
|
||||||
|
|
||||||
Indicates that our the intermediate private key can be used to sign
|
|
||||||
certificate requests.
|
|
||||||
|
|
||||||
* **CRL Sign**
|
|
||||||
|
|
||||||
Indicates that this public key can be used to verify a signature on
|
|
||||||
revocation information, such as CRL.
|
|
||||||
|
|
||||||
### Leaf Certificate - End Entity Certificate (certificates returned by the CA)
|
|
||||||
|
|
||||||
* Validity (24 hour window)
|
|
||||||
* **Not Before**: Now
|
|
||||||
* **Not After**: Now + 24 hours
|
|
||||||
|
|
||||||
The default is a 24hr window. This value is somewhat arbitrary, however,
|
|
||||||
our goal is to have seamless end-entity certificate rotation (we are
|
|
||||||
getting close). Rotating certificates frequently is good security hygiene
|
|
||||||
because it gives bad actors very little time to form an attack and limits
|
|
||||||
the usefulness of any single private key in the system. We will continue
|
|
||||||
to work towards decreasing this window because we believe it significantly
|
|
||||||
reduces probability and effectiveness of any attack.
|
|
||||||
|
|
||||||
* **Key Usage**
|
|
||||||
* **Key Encipherment**
|
|
||||||
|
|
||||||
Indicates that a certificate will be used with a protocol that encrypts keys.
|
|
||||||
|
|
||||||
* **Digital Signature**
|
|
||||||
|
|
||||||
Indicates that this public key may be used as a digital signature to
|
|
||||||
support security services that enable entity authentication and data
|
|
||||||
origin authentication with integrity.
|
|
||||||
|
|
||||||
* **Extended Key Usage**
|
|
||||||
* **TLS Web Server Authentication**
|
|
||||||
|
|
||||||
Certificate can be used as the server side certificate in the TLS protocol.
|
|
||||||
|
|
||||||
* **TLS Web Client Authentication**
|
|
||||||
|
|
||||||
Certificate can be used as the client side certificate in the TLS protocol.
|
|
||||||
|
|
||||||
## Default TLS Configuration Options
|
|
||||||
|
|
||||||
* **Min TLS Version**: TLS 1.2
|
|
||||||
* **Max TLS Version**: TLS 1.2
|
|
||||||
|
|
||||||
The PCI Security Standards Council required all payment processors
|
|
||||||
and merchants to move to TLS 1.2 and above by June 30, 2018. By setting
|
|
||||||
TLS 1.2 as the default for all tls protocol negotiation we encourage our
|
|
||||||
users to adopt the same security conventions.
|
|
||||||
|
|
||||||
* **Default Cipher Suites**:
|
|
||||||
|
|
||||||
```
|
|
||||||
[
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
The default 'ciphersuites' are a list of two cipher combinations. For
|
|
||||||
communication between services running step there is no need for cipher suite
|
|
||||||
negotiation. The server can specify a single cipher suite which the client is
|
|
||||||
already known to support.
|
|
||||||
|
|
||||||
Reasons for selecting `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305`:
|
|
||||||
* ECDHE key exchange algorithm has perfect forward secrecy
|
|
||||||
* ECDSA has smaller keys and better performance (than RSA)
|
|
||||||
* CHACHA20 with POLY1305 is the cipher mode used by google.
|
|
||||||
* CHACHA20's performance is better than GCM and CBC.
|
|
||||||
|
|
||||||
|
|
||||||
The http2 spec requires the `TLS_ECDHE_(RSA|ECDSA)_WITH_AES_128_GCM_SHA256`
|
|
||||||
ciphersuite be accepted by the server, therefore it makes our list of
|
|
||||||
default ciphersuites until we build the functionality to modify our defaults
|
|
||||||
based on http version.
|
|
||||||
|
|
||||||
* **Approved Cipher Suites**:
|
|
||||||
|
|
||||||
```
|
|
||||||
[
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
Above is a list of step approved cipher suites. Not all communication
|
|
||||||
can be mediated with step TLS functionality. For those connections the list of
|
|
||||||
server supported cipher suites must have more options - in case older clients
|
|
||||||
do not support our favored cipher suite.
|
|
||||||
|
|
||||||
Reasons for selecting these cipher suites can be found in the following
|
|
||||||
[ssllabs article](https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices#23-use-secure-cipher-suites).
|
|
||||||
|
|
||||||
* **Renegotation**: Never
|
|
||||||
|
|
||||||
TLS renegotiation significantly complicates the state machine and has been
|
|
||||||
the source of numerous, subtle security issues. Therefore, by default we
|
|
||||||
disable it.
|
|
186
docs/docker.md
|
@ -1,186 +0,0 @@
|
||||||
# Getting started with Docker
|
|
||||||
|
|
||||||
## NOTE: This guide is deprecated. Please see [smallstep/step-ca](https://hub.docker.com/r/smallstep/step-ca) on Docker Hub for instructions.
|
|
||||||
|
|
||||||
This guide shows how to set up [step certificates](https://github.com/smallstep/certificates) using docker.
|
|
||||||
|
|
||||||
For short, we will use **step-ca** to refer to [step certificates](https://github.com/smallstep/certificates).
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
1. To follow this guide you will need to [install step
|
|
||||||
cli](https://github.com/smallstep/cli#installation-guide).
|
|
||||||
|
|
||||||
2. Get the docker image.
|
|
||||||
|
|
||||||
Get the latest version of **step-ca** from the [step-ca docker
|
|
||||||
hub](https://hub.docker.com/r/smallstep/step-ca):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ docker pull smallstep/step-ca
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Create the required volumes.
|
|
||||||
|
|
||||||
We need to create a volume in docker where we will store our PKI as well as
|
|
||||||
the step-ca configuration file.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ docker volume create step
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Initialize the PKI.
|
|
||||||
|
|
||||||
The simple way to do this is to run an interactive terminal:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ docker run -it -v step:/home/step smallstep/step-ca sh
|
|
||||||
|
|
||||||
~ $ step ca init
|
|
||||||
✔ What would you like to name your new PKI? (e.g. Smallstep): Smallstep
|
|
||||||
✔ What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,1.1.1.1,etc.]): localhost
|
|
||||||
✔ What address will your new CA listen at? (e.g. :443): :9000
|
|
||||||
✔ What would you like to name the first provisioner for your new CA? (e.g. you@smallstep.com): admin
|
|
||||||
✔ What do you want your password to be? [leave empty and we'll generate one]: <your password here>
|
|
||||||
|
|
||||||
Generating root certificate...
|
|
||||||
all done!
|
|
||||||
|
|
||||||
Generating intermediate certificate...
|
|
||||||
all done!
|
|
||||||
|
|
||||||
✔ Root certificate: /home/step/certs/root_ca.crt
|
|
||||||
✔ Root private key: /home/step/secrets/root_ca_key
|
|
||||||
✔ Root fingerprint: f9e45ae9ec5d42d702ce39fd9f3125372ce54d0b29a5ff3016b31d9b887a61a4
|
|
||||||
✔ Intermediate certificate: /home/step/certs/intermediate_ca.crt
|
|
||||||
✔ Intermediate private key: /home/step/secrets/intermediate_ca_key
|
|
||||||
✔ Default configuration: /home/step/config/defaults.json
|
|
||||||
✔ Certificate Authority configuration: /home/step/config/ca.json
|
|
||||||
|
|
||||||
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Place the PKI root password in a known location.
|
|
||||||
|
|
||||||
Our image is expecting the password to be placed in `/home/step/secrets/password`
|
|
||||||
you can simply go in to the terminal again and write that file:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ docker run -it -v step:/home/step smallstep/step-ca sh
|
|
||||||
~ $ echo <your password here> > /home/step/secrets/password
|
|
||||||
```
|
|
||||||
|
|
||||||
At this time everything is ready to run step-ca!
|
|
||||||
|
|
||||||
## Running step certificates
|
|
||||||
|
|
||||||
Now that we have configured our environment we are ready to run step-ca.
|
|
||||||
|
|
||||||
Expose the server address locally and run the step-ca with:
|
|
||||||
```sh
|
|
||||||
$ docker run -d -p 127.0.0.1:9000:9000 -v step:/home/step smallstep/step-ca
|
|
||||||
```
|
|
||||||
|
|
||||||
Let's verify that the service is running with curl:
|
|
||||||
```sh
|
|
||||||
$ curl https://localhost:9000/health
|
|
||||||
curl: (60) SSL certificate problem: unable to get local issuer certificate
|
|
||||||
More details here: https://curl.haxx.se/docs/sslcerts.html
|
|
||||||
|
|
||||||
curl performs SSL certificate verification by default, using a "bundle"
|
|
||||||
of Certificate Authority (CA) public keys (CA certs). If the default
|
|
||||||
bundle file isn't adequate, you can specify an alternate file
|
|
||||||
using the --cacert option.
|
|
||||||
If this HTTPS server uses a certificate signed by a CA represented in
|
|
||||||
the bundle, the certificate verification probably failed due to a
|
|
||||||
problem with the certificate (it might be expired, or the name might
|
|
||||||
not match the domain name in the URL).
|
|
||||||
If you'd like to turn off curl's verification of the certificate, use
|
|
||||||
the -k (or --insecure) option.
|
|
||||||
HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure.
|
|
||||||
```
|
|
||||||
|
|
||||||
It's working but curl complains because the certificate is not signed by an
|
|
||||||
accepted certificate authority.
|
|
||||||
|
|
||||||
### Notes for running on a Raspberry Pi
|
|
||||||
|
|
||||||
When you run step-ca on a Raspberry Pi, you might get the following error in
|
|
||||||
your continaer logs:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
step-ca | badger 2021/05/08 20:13:12 INFO: All 0 tables opened in 0s
|
|
||||||
step-ca | Error opening database of Type badger with source /home/step/db: error opening Badger database: Mmap value log file. Path=/home/step/db/000000.vlog. Error=cannot allocate memory
|
|
||||||
```
|
|
||||||
|
|
||||||
To fix it, adjust the `db` configuration in the file `config/ca.json`.
|
|
||||||
Change the value of `badgerFileLoadingMode` from `""` to `"FileIO"`.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker run -it -v step:/home/step smallstep/step-ca sh
|
|
||||||
|
|
||||||
~ $ vi config/ca.json
|
|
||||||
```
|
|
||||||
|
|
||||||
You will end up with this:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"db": {
|
|
||||||
"type": "badger",
|
|
||||||
"dataSource": "/root/.step/db",
|
|
||||||
"badgerFileLoadingMode": "FileIO"
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dev environment bootstrap
|
|
||||||
|
|
||||||
To initialize the development environment we need to grab the Root fingerprint
|
|
||||||
from the [Initializing the PKI](#initializing-the-pki) step earlier. In the
|
|
||||||
case of this example:
|
|
||||||
`f9e45ae9ec5d42d702ce39fd9f3125372ce54d0b29a5ff3016b31d9b887a61a4`. With the
|
|
||||||
fingerprint we can bootstrap our dev environment.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ step ca bootstrap --ca-url https://localhost:9000 --fingerprint f9e45ae9ec5d42d702ce39fd9f3125372ce54d0b29a5ff3016b31d9b887a61a4 --install
|
|
||||||
The root certificate has been saved in ~/.step/certs/root_ca.crt.
|
|
||||||
Your configuration has been saved in ~/.step/config/defaults.json.
|
|
||||||
Installing the root certificate in the system truststore... done.
|
|
||||||
```
|
|
||||||
|
|
||||||
Now [step cli](https://github.com/smallstep/cli) is configured to use step-ca
|
|
||||||
and our new root certificate is trusted by our local environment.
|
|
||||||
```sh
|
|
||||||
$ curl https://localhost:9000/health
|
|
||||||
{"status":"ok"}
|
|
||||||
```
|
|
||||||
|
|
||||||
And we are able to run web services configured with TLS (and mTLS):
|
|
||||||
```sh
|
|
||||||
~ $ step ca certificate localhost localhost.crt localhost.key
|
|
||||||
✔ Key ID: aTPGWP0qbuQdflR5VxtNouDIOXyNMH1H9KAZKP-UcHo (admin)
|
|
||||||
✔ Please enter the password to decrypt the provisioner key:
|
|
||||||
✔ CA: https://localhost:9000/1.0/sign
|
|
||||||
✔ Certificate: localhost.crt
|
|
||||||
✔ Private Key: localhost.key
|
|
||||||
~ $ step ca root root_ca.crt
|
|
||||||
The root certificate has been saved in root_ca.crt.
|
|
||||||
~ $ python <<EOF
|
|
||||||
import BaseHTTPServer, ssl
|
|
||||||
class H(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
||||||
def do_GET(self):
|
|
||||||
self.send_response(200); self.send_header('content-type', 'text/html; charset=utf-8'); self.end_headers()
|
|
||||||
self.wfile.write(b'\n\xf0\x9f\x91\x8b Hello! Welcome to TLS \xf0\x9f\x94\x92\xe2\x9c\x85\n\n')
|
|
||||||
httpd = BaseHTTPServer.HTTPServer(('', 8443), H)
|
|
||||||
httpd.socket = ssl.wrap_socket (httpd.socket, server_side=True, keyfile="localhost.key", certfile="localhost.crt", ca_certs="root_ca.crt")
|
|
||||||
httpd.serve_forever()
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Test from another terminal:
|
|
||||||
```sh
|
|
||||||
$ curl https://localhost:8443
|
|
||||||
|
|
||||||
👋 Hello! Welcome to TLS 🔒✅
|
|
||||||
```
|
|
||||||
|
|
||||||
Or visit `https://localhost:8443` from your browser.
|
|
Before Width: | Height: | Size: 572 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 6.2 MiB |
Before Width: | Height: | Size: 9.5 MiB |
237
docs/kms.md
|
@ -1,237 +0,0 @@
|
||||||
# Key Management Services
|
|
||||||
|
|
||||||
This document describes how to use a key management service or KMS to store the
|
|
||||||
private keys and sign certificates.
|
|
||||||
|
|
||||||
Support for multiple KMS are planned, but currently the only Google's Cloud KMS,
|
|
||||||
and Amazon's AWS KMS are supported. A still experimental version for YubiKeys is
|
|
||||||
also available if you compile [step-ca](https://github.com/smallstep/certificates)
|
|
||||||
yourself.
|
|
||||||
|
|
||||||
## Google's Cloud KMS
|
|
||||||
|
|
||||||
[Cloud KMS](https://cloud.google.com/kms) is the Google's cloud-hosted KMS that
|
|
||||||
allows you to store the cryptographic keys, and sign certificates using their
|
|
||||||
infrastructure. Cloud KMS supports two different protection levels, SOFTWARE and
|
|
||||||
HSM.
|
|
||||||
|
|
||||||
To configure Cloud KMS in your CA you need add the `"kms"` property to you
|
|
||||||
`ca.json`, and replace the property`"key"` with the Cloud KMS key name of your
|
|
||||||
intermediate key:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"key": "projects/<project-id>/locations/global/keyRings/<ring-id>/cryptoKeys/<key-id>/cryptoKeyVersions/<version-number>",
|
|
||||||
...
|
|
||||||
"kms": {
|
|
||||||
"type": "cloudkms",
|
|
||||||
"credentialsFile": "path/to/credentials.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In a similar way, for SSH certificate, the SSH keys must be Cloud KMS names:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"ssh": {
|
|
||||||
"hostKey": "projects/<project-id>/locations/global/keyRings/<ring-id>/cryptoKeys/<key-id>/cryptoKeyVersions/<version-number>",
|
|
||||||
"userKey": "projects/<project-id>/locations/global/keyRings/<ring-id>/cryptoKeys/<key-id>/cryptoKeyVersions/<version-number>"
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Currently [step](https://github.com/smallstep/cli) does not provide an automatic
|
|
||||||
way to initialize the public key infrastructure (PKI) using Cloud KMS, but an
|
|
||||||
experimental tool named `step-cloudkms-init` is available for this use case. At
|
|
||||||
some point this tool will be integrated into `step` and it will be deleted.
|
|
||||||
|
|
||||||
To use `step-cloudkms-init` just enable Cloud KMS in your project and run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
|
|
||||||
$ step-cloudkms-init --project your-project-id --ssh
|
|
||||||
Creating PKI ...
|
|
||||||
✔ Root Key: projects/your-project-id/locations/global/keyRings/pki/cryptoKeys/root/cryptoKeyVersions/1
|
|
||||||
✔ Root Certificate: root_ca.crt
|
|
||||||
✔ Intermediate Key: projects/your-project-id/locations/global/keyRings/pki/cryptoKeys/intermediate/cryptoKeyVersions/1
|
|
||||||
✔ Intermediate Certificate: intermediate_ca.crt
|
|
||||||
|
|
||||||
Creating SSH Keys ...
|
|
||||||
✔ SSH User Public Key: ssh_user_ca_key.pub
|
|
||||||
✔ SSH User Private Key: projects/your-project-id/locations/global/keyRings/pki/cryptoKeys/ssh-user-key/cryptoKeyVersions/1
|
|
||||||
✔ SSH Host Public Key: ssh_host_ca_key.pub
|
|
||||||
✔ SSH Host Private Key: projects/your-project-id/locations/global/keyRings/pki/cryptoKeys/ssh-host-key/cryptoKeyVersions/1
|
|
||||||
```
|
|
||||||
|
|
||||||
See `step-cloudkms-init --help` for more options.
|
|
||||||
|
|
||||||
## AWS KMS
|
|
||||||
|
|
||||||
[AWS KMS](https://docs.aws.amazon.com/kms/index.html) is the Amazon's managed
|
|
||||||
encryption and key management service. It creates and store the cryptographic
|
|
||||||
keys, and use their infrastructure for signing operations. Amazon KMS operations
|
|
||||||
are always backed by hardware security modules (HSMs).
|
|
||||||
|
|
||||||
To configure AWS KMS in your CA you need add the `"kms"` property to you
|
|
||||||
`ca.json`, and replace the property`"key"` with the AWS KMS key name of your
|
|
||||||
intermediate key:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"key": "awskms:key-id=f879f239-feb6-4596-9ed2-b1606277c7fe",
|
|
||||||
...
|
|
||||||
"kms": {
|
|
||||||
"type": "awskms",
|
|
||||||
"region": "us-east-1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default it uses the credentials in `~/.aws/credentials`, but this can be
|
|
||||||
overridden using the `credentialsFile` option, `region` and `profile` can also
|
|
||||||
be configured as options. These can also be configured using environment
|
|
||||||
variables as described by their [session
|
|
||||||
docs](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/).
|
|
||||||
|
|
||||||
To configure SSH certificate signing we do something similar, and replace the
|
|
||||||
ssh keys with the ones in the KMS:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
...
|
|
||||||
"ssh": {
|
|
||||||
"hostKey": "awskms:key-id=d48e502a-09bc-4bf7-9af8-ae1bccedc931",
|
|
||||||
"userKey": "awskms:key-id=cf28e942-1e10-4a08-b84c-5359af1b5f12"
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The keys can also be just the Amazon's Key ID or the ARN, but using the format
|
|
||||||
based on the [RFC7512](https://tools.ietf.org/html/rfc7512) will allow more
|
|
||||||
flexibility for future releases of `step`.
|
|
||||||
|
|
||||||
Currently [step](https://github.com/smallstep/cli) does not provide an automatic
|
|
||||||
way to initialize the public key infrastructure (PKI) using AWS KMS, but an
|
|
||||||
experimental tool named `step-awskms-init` is available for this use case. At
|
|
||||||
some point this tool will be integrated into `step` and it will be deleted.
|
|
||||||
|
|
||||||
To use `step-awskms-init` make sure to have to have your [environment
|
|
||||||
configured](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)
|
|
||||||
running `aws configure` and then just run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ bin/step-awskms-init --ssh --region us-east-1
|
|
||||||
Creating PKI ...
|
|
||||||
✔ Root Key: awskms:key-id=f53fb767-4029-40ff-b650-0dd35fb661df
|
|
||||||
✔ Root Certificate: root_ca.crt
|
|
||||||
✔ Intermediate Key: awskms:key-id=f879f239-feb6-4596-9ed2-b1606277c7fe
|
|
||||||
✔ Intermediate Certificate: intermediate_ca.crt
|
|
||||||
|
|
||||||
Creating SSH Keys ...
|
|
||||||
✔ SSH User Public Key: ssh_user_ca_key.pub
|
|
||||||
✔ SSH User Private Key: awskms:key-id=cf28e942-1e10-4a08-b84c-5359af1b5f12
|
|
||||||
✔ SSH Host Public Key: ssh_host_ca_key.pub
|
|
||||||
✔ SSH Host Private Key: awskms:key-id=cf28e942-1e10-4a08-b84c-5359af1b5f12
|
|
||||||
```
|
|
||||||
|
|
||||||
The `--region` parameter is only required if your aws configuration does not
|
|
||||||
define a region. See `step-awskms-init --help` for more options.
|
|
||||||
|
|
||||||
## YubiKey
|
|
||||||
|
|
||||||
And incomplete and experimental support for [YubiKeys](https://www.yubico.com)
|
|
||||||
is also available. Support for YubiKeys is not enabled by default and only TLS
|
|
||||||
signing can be configured.
|
|
||||||
|
|
||||||
The YubiKey implementation requires cgo, and our build system does not produce
|
|
||||||
binaries with it. To enable YubiKey download the source code and run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make build GOFLAGS=""
|
|
||||||
```
|
|
||||||
|
|
||||||
The implementation uses [piv-go](https://github.com/go-piv/piv-go), and it
|
|
||||||
requires PCSC support, this is available by default on macOS and Windows
|
|
||||||
operating systems, but on Linux piv-go requires PCSC lite.
|
|
||||||
|
|
||||||
To install on Debian-based distributions, run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo apt-get install libpcsclite-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
On Fedora:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo yum install pcsc-lite-devel
|
|
||||||
```
|
|
||||||
|
|
||||||
On CentOS:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo yum install 'dnf-command(config-manager)'
|
|
||||||
sudo yum config-manager --set-enabled PowerTools
|
|
||||||
sudo yum install pcsc-lite-devel
|
|
||||||
```
|
|
||||||
|
|
||||||
The initialization of the public key infrastructure (PKI) for YubiKeys, is not
|
|
||||||
currently integrated into [step](https://github.com/smallstep/cli), but an
|
|
||||||
experimental tool named `step-yubikey-init` is available for this use case. At
|
|
||||||
some point this tool will be integrated into `step` and it will be deleted.
|
|
||||||
|
|
||||||
To configure your YubiKey just run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ bin/step-yubikey-init
|
|
||||||
What is the YubiKey PIN?:
|
|
||||||
Creating PKI ...
|
|
||||||
✔ Root Key: yubikey:slot-id=9a
|
|
||||||
✔ Root Certificate: root_ca.crt
|
|
||||||
✔ Intermediate Key: yubikey:slot-id=9c
|
|
||||||
✔ Intermediate Certificate: intermediate_ca.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
See `step-yubikey-init --help` for more options.
|
|
||||||
|
|
||||||
Finally to enable it in the ca.json, point the `root` and `crt` to the generated
|
|
||||||
certificates, set the `key` with the yubikey URI generated in the previous step
|
|
||||||
and configure the `kms` property with the `type` and your `pin` in it.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"root": "/path/to/root_ca.crt",
|
|
||||||
"crt": "/path/to/intermediate_ca.crt",
|
|
||||||
"key": "yubikey:slot-id=9c",
|
|
||||||
"kms": {
|
|
||||||
"type": "yubikey",
|
|
||||||
"pin": "123456"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## SSHAgentKMS
|
|
||||||
|
|
||||||
SSHAgentKMS is a KMS that wrapps a ssh-agent which has access to the keys to
|
|
||||||
sign ssh certificates. This was primarly written to be able to use gpg-agent
|
|
||||||
to provide the keys stored in a YubiKeys openpgp interface.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"kms": {
|
|
||||||
"type": "sshagentkms"
|
|
||||||
},
|
|
||||||
"ssh": {
|
|
||||||
"hostKey": "sshagentkms:cardno:000123456789",
|
|
||||||
"userKey": "sshagentkms:cardno:000123456789",
|
|
||||||
},
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This KMS requires that "root", "crt" and "key" are stored in plain files as for
|
|
||||||
SoftKMS.
|
|
|
@ -1,586 +0,0 @@
|
||||||
# Provisioners
|
|
||||||
|
|
||||||
> Note: The canonical documentation for `step-ca` provisioners now lives at
|
|
||||||
> https://smallstep.com/docs/step-ca/provisioners. Documentation
|
|
||||||
> found on this page may be out of date.
|
|
||||||
|
|
||||||
Provisioners are people or code that are registered with the CA and authorized
|
|
||||||
to issue "provisioning tokens". Provisioning tokens are single-use tokens that
|
|
||||||
can be used to authenticate with the CA and get a certificate.
|
|
||||||
|
|
||||||
See `step ca provisioner add --help` for documentation and examples on adding
|
|
||||||
provisioners.
|
|
||||||
|
|
||||||
> Attn: We strongly recommend using the `step ca provisioner add ...`
|
|
||||||
> utility to generate provisioners in your `ca.json` configuration. We often
|
|
||||||
> encode fields differently in the JSON than you might expect. And you can
|
|
||||||
> always come in and modify the configuration manually after using the utility.
|
|
||||||
|
|
||||||
## Claims
|
|
||||||
|
|
||||||
Each provisioner can define an optional `claims` attribute. The settings in this
|
|
||||||
attribute override any settings in the global `claims` attribute in the authority
|
|
||||||
configuration.
|
|
||||||
|
|
||||||
Example `claims`:
|
|
||||||
|
|
||||||
```
|
|
||||||
...
|
|
||||||
"claims": {
|
|
||||||
"minTLSCertDuration": "5m",
|
|
||||||
"maxTLSCertDuration": "24h",
|
|
||||||
"defaultTLSCertDuration": "24h",
|
|
||||||
"disableRenewal": false,
|
|
||||||
"minHostSSHCertDuration": "5m",
|
|
||||||
"maxHostSSHCertDuration": "1680h",
|
|
||||||
"defaultHostSSHCertDuration": "720h",
|
|
||||||
"minUserSSHCertDuration": "5m",
|
|
||||||
"maxUserSSHCertDuration": "24h",
|
|
||||||
"defaultUserSSHCertDuration": "16h",
|
|
||||||
"enableSSHCA": true
|
|
||||||
},
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority.
|
|
||||||
You can set one or more of the following claims:
|
|
||||||
|
|
||||||
* `minTLSCertDuration`: do not allow certificates with a duration less than
|
|
||||||
this value.
|
|
||||||
|
|
||||||
* `maxTLSCertDuration`: do not allow certificates with a duration greater than
|
|
||||||
this value.
|
|
||||||
|
|
||||||
* `defaultTLSCertDuration`: if no certificate validity period is specified,
|
|
||||||
use this value.
|
|
||||||
|
|
||||||
* `disableIssuedAtCheck`: disable a check verifying that provisioning tokens
|
|
||||||
must be issued after the CA has booted. This claim is one prevention against
|
|
||||||
token reuse. The default value is `false`. Do not change this unless you
|
|
||||||
know what you are doing.
|
|
||||||
|
|
||||||
SSH CA properties
|
|
||||||
|
|
||||||
* `minUserSSHCertDuration`: do not allow certificates with a duration less
|
|
||||||
than this value.
|
|
||||||
|
|
||||||
* `maxUserSSHCertDuration`: do not allow certificates with a duration
|
|
||||||
greater than this value.
|
|
||||||
|
|
||||||
* `defaultUserSSHCertDuration`: if no certificate validity period is specified,
|
|
||||||
use this value.
|
|
||||||
|
|
||||||
* `minHostSSHCertDuration`: do not allow certificates with a duration less
|
|
||||||
than this value.
|
|
||||||
|
|
||||||
* `maxHostSSHCertDuration`: do not allow certificates with a duration
|
|
||||||
greater than this value.
|
|
||||||
|
|
||||||
* `defaultHostSSHCertDuration`: if no certificate validity period is specified,
|
|
||||||
use this value.
|
|
||||||
|
|
||||||
* `enableSSHCA`: enable all provisioners to generate SSH Certificates.
|
|
||||||
The default value is `false`. You can enable this option per provisioner
|
|
||||||
by setting it to `true` in the provisioner claims.
|
|
||||||
|
|
||||||
## Provisioner Types
|
|
||||||
|
|
||||||
Each provisioner has a different method of authentication with the CA.
|
|
||||||
|
|
||||||
- A JWK provisioner uses a JWT signed by a JWK.
|
|
||||||
- An OIDC provisioner uses a OIDC token signed by an Identity Provider e.g. Google, Okta, Azure.
|
|
||||||
- An AWS provisioner uses an Instance Identity Document signed by AWS.
|
|
||||||
- etc.
|
|
||||||
|
|
||||||
### Capabilities by Type
|
|
||||||
|
|
||||||
Provisioners are used to authenticate certificate signing requests, and every
|
|
||||||
provisioner has a slightly different scope of authorization. Below is a table
|
|
||||||
detailing the authorization capabilities of each provisioner.
|
|
||||||
|
|
||||||
Provisioner Capabilities| x509-sign | x509-renew | x509-revoke | ssh-user-cert-sign | ssh-host-cert-sign | ssh-user-cert-renew | ssh-host-cert-renew | ssh-revoke | ssh-rekey
|
|
||||||
----------- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-:
|
|
||||||
JWK | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | 𝗫 | 𝗫 | ✔️ | 𝗫
|
|
||||||
OIDC | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ <sup id="a1">[1](#f1)</sup> | 𝗫 | 𝗫 | ✔️ | 𝗫
|
|
||||||
X5C | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | 𝗫 | 𝗫 | 𝗫 | 𝗫
|
|
||||||
K8sSA | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | 𝗫 | 𝗫 | 𝗫 | 𝗫
|
|
||||||
ACME | ✔️ | ✔️ | 𝗫 | 𝗫 | 𝗫 | 𝗫 | 𝗫 | 𝗫 | 𝗫
|
|
||||||
SSHPOP | 𝗫 | 𝗫 | 𝗫 | 𝗫 | 𝗫 | 𝗫 | ✔️ | ✔️ | ✔️
|
|
||||||
AWS | ✔️ | ✔️ | 𝗫 | 𝗫 | ✔️ | 𝗫 | 𝗫 | 𝗫 | 𝗫
|
|
||||||
Azure | ✔️ | ✔️ | 𝗫 | 𝗫 | ✔️ | 𝗫 | 𝗫 | 𝗫 | 𝗫
|
|
||||||
GCP | ✔️ | ✔️ | 𝗫 | 𝗫 | ✔️ | 𝗫 | 𝗫 | 𝗫 | 𝗫
|
|
||||||
|
|
||||||
<b id="f1">1</b> Admin OIDC users can generate Host SSH Certificates. Admins can be configured in the OIDC provisioner. [↩](#a1)
|
|
||||||
|
|
||||||
### JWK
|
|
||||||
|
|
||||||
JWK is the default provisioner type. It uses public-key cryptography to sign and
|
|
||||||
validate a JSON Web Token (JWT).
|
|
||||||
|
|
||||||
The [step](https://github.com/smallstep/cli) CLI tool will create a JWK
|
|
||||||
provisioner when `step ca init` is used, and it also contains commands to add
|
|
||||||
(`step ca provisioner add`) and remove (`step ca provisioner remove`) JWK
|
|
||||||
provisioners.
|
|
||||||
|
|
||||||
In the ca.json configuration file, a complete JWK provisioner example looks like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "JWK",
|
|
||||||
"name": "you@smallstep.com",
|
|
||||||
"key": {
|
|
||||||
"use": "sig",
|
|
||||||
"kty": "EC",
|
|
||||||
"kid": "NPM_9Gz_omTqchS6Xx9Yfvs-EuxkYo6VAk4sL7gyyM4",
|
|
||||||
"crv": "P-256",
|
|
||||||
"alg": "ES256",
|
|
||||||
"x": "bBI5AkO9lwvDuWGfOr0F6ttXC-ZRzJo8kKn5wTzRJXI",
|
|
||||||
"y": "rcfaqE-EEZgs34Q9SSH3f9Ua5a8dKopXNfEzDD8KRlU"
|
|
||||||
},
|
|
||||||
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiTlV6MjlEb3hKMVdOaFI3dUNjaGdYZyJ9.YN7xhz6RAbz_9bcuXoymBOj8bOg23ETAdmSCRyHpxGekkV0q3STYYg.vo1oBnZsZjgRu5Ln.Xop8AvZ74h_im2jxeaq-hYYWnaK_eF7MGr4xcZGodMUxp-hGPqS85oWkyprkQLYt1-jXTURfpejtmPeB4-sxgj7OFxMYYus84BdkG9BZgSBmMN9SqZItOv4pqg_NwQA0bv9g9A_e-N6QUFanxuYQsEPX_-IwWBDbNKyN9bXbpEQa0FKNVsTvFahGzOxQngXipi265VADkh8MJLjYerplKIbNeOJJbLd9CbS9fceLvQUNr3ACGgAejSaWmeNUVqbho1lY4882iS8QVx1VzjluTXlAMdSUUDHArHEihz008kCyF0YfvNdGebyEDLvTmF6KkhqMpsWn3zASYBidc9k._ch9BtvRRhcLD838itIQlw",
|
|
||||||
"claims": {
|
|
||||||
"minTLSCertDuration": "5m",
|
|
||||||
"maxTLSCertDuration": "24h",
|
|
||||||
"defaultTLSCertDuration": "24h",
|
|
||||||
"disableRenewal": false,
|
|
||||||
"minHostSSHCertDuration": "5m",
|
|
||||||
"maxHostSSHCertDuration": "1680h",
|
|
||||||
"minUserSSHCertDuration": "5m",
|
|
||||||
"maxUserSSHCertDuration": "24h",
|
|
||||||
"enableSSHCA": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): for a JWK provisioner it must be `JWK`, this field is case
|
|
||||||
insensitive.
|
|
||||||
|
|
||||||
* `name` (mandatory): identifies the provisioner, a good practice is to
|
|
||||||
use an email address or a descriptive string that allows the identification of
|
|
||||||
the owner, but it can be any non-empty string.
|
|
||||||
|
|
||||||
* `key` (mandatory): is the JWK (JSON Web Key) representation of a public key
|
|
||||||
used to validate a signed token.
|
|
||||||
|
|
||||||
* `encryptedKey` (recommended): is the encrypted private key used to sign a
|
|
||||||
token. It's a JWE compact string containing the JWK representation of the
|
|
||||||
private key.
|
|
||||||
|
|
||||||
We can use [step](https://github.com/smallstep/cli) to see the private key
|
|
||||||
encrypted with the password `asdf`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ echo ey...lw | step crypto jwe decrypt | jq
|
|
||||||
Please enter the password to decrypt the content encryption key:
|
|
||||||
{
|
|
||||||
"use": "sig",
|
|
||||||
"kty": "EC",
|
|
||||||
"kid": "NPM_9Gz_omTqchS6Xx9Yfvs-EuxkYo6VAk4sL7gyyM4",
|
|
||||||
"crv": "P-256",
|
|
||||||
"alg": "ES256",
|
|
||||||
"x": "bBI5AkO9lwvDuWGfOr0F6ttXC-ZRzJo8kKn5wTzRJXI",
|
|
||||||
"y": "rcfaqE-EEZgs34Q9SSH3f9Ua5a8dKopXNfEzDD8KRlU",
|
|
||||||
"d": "rsjCCM_2FQ-uk7nywBEQHl84oaPo4mTpYDgXAu63igE"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If the ca.json does not contain the encryptedKey, the private key must be
|
|
||||||
provided using the `--key` flag of the `step ca token` to be able to sign the
|
|
||||||
token.
|
|
||||||
|
|
||||||
### OIDC
|
|
||||||
|
|
||||||
An OIDC provisioner allows a user to get a certificate after authenticating
|
|
||||||
with an OAuth OpenID Connect identity provider. The ID token provided
|
|
||||||
will be used on the CA authentication, and by default, the certificate will only
|
|
||||||
have the user's email as a Subject Alternative Name (SAN) Extension.
|
|
||||||
|
|
||||||
One of the most common providers and the one we'll use in the following example
|
|
||||||
is G-Suite.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "OIDC",
|
|
||||||
"name": "Google",
|
|
||||||
"clientID": "1087160488420-8qt7bavg3qesdhs6it824mhnfgcfe8il.apps.googleusercontent.com",
|
|
||||||
"clientSecret": "udTrOT3gzrO7W9fDPgZQLfYJ",
|
|
||||||
"configurationEndpoint": "https://accounts.google.com/.well-known/openid-configuration",
|
|
||||||
"admins": ["you@smallstep.com"],
|
|
||||||
"domains": ["smallstep.com"],
|
|
||||||
"listenAddress": ":10000",
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "8h",
|
|
||||||
"defaultTLSCertDuration": "2h",
|
|
||||||
"disableRenewal": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `OIDC`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `clientID` (mandatory): the client id provided by the identity provider used
|
|
||||||
to initialize the authentication flow.
|
|
||||||
|
|
||||||
* `clientSecret` (mandatory): the client secret provided by the identity
|
|
||||||
provider used to get the id token. Some identity providers might use an empty
|
|
||||||
string as a secret.
|
|
||||||
|
|
||||||
* `configurationEndpoint` (mandatory): is the HTTP address used by the CA to get
|
|
||||||
the OpenID Connect configuration and public keys used to validate the tokens.
|
|
||||||
|
|
||||||
* `admins` (optional): is the list of emails that will be able to get
|
|
||||||
certificates with custom SANs. If a user is not an admin, it will only be able
|
|
||||||
to get a certificate with its email in it.
|
|
||||||
|
|
||||||
* `domains` (optional): is the list of domains valid. If provided only the
|
|
||||||
emails with the provided domains will be able to authenticate.
|
|
||||||
|
|
||||||
* `listenAddress` (optional): is the loopback address (`:port` or `host:port`)
|
|
||||||
where the authorization server will redirect to complete the authorization
|
|
||||||
flow. If it's not defined `step` will use `127.0.0.1` with a random port. This
|
|
||||||
configuration is only required if the authorization server doesn't allow any
|
|
||||||
port to be specified at the time of the request for loopback IP redirect URIs.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
### X5C
|
|
||||||
|
|
||||||
An X5C provisioner allows a client to get an x509 or SSH certificate using
|
|
||||||
an existing x509 certificate that is trusted by the X5C provisioner.
|
|
||||||
|
|
||||||
An X5C provisioner is configured with a root certificate, supplied by the user,
|
|
||||||
at the time the provisioner is created. The X5C provisioner can authenticate
|
|
||||||
X5C tokens.
|
|
||||||
|
|
||||||
An X5C token is a JWT, signed by the certificate private key, with an `x5c`
|
|
||||||
header that contains the chain.
|
|
||||||
|
|
||||||
If you would like any certificate signed by `step-ca` to become a provisioner,
|
|
||||||
you can configure the X5C provisioner using the root certificate used by
|
|
||||||
`step-ca`, like so:
|
|
||||||
|
|
||||||
```
|
|
||||||
step ca provisioner add x5c-smallstep --type X5C --x5c-root $(step path)/certs/root_ca.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
Or you can configure the X5C provisioner with an outside root, giving provisioner
|
|
||||||
capabilities to a completely separate PKI.
|
|
||||||
|
|
||||||
Below is an example of an X5C provisioner in the `ca.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
...
|
|
||||||
{
|
|
||||||
"type": "X5C",
|
|
||||||
"name": "x5c",
|
|
||||||
"roots": "LS0tLS1 ... Q0FURS0tLS0tCg==",
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "8h",
|
|
||||||
"defaultTLSCertDuration": "2h",
|
|
||||||
"disableRenewal": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `X5C`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `roots` (mandatory): a base64 encoded list of root certificates used for
|
|
||||||
validating X5C tokens.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
### SSHPOP
|
|
||||||
|
|
||||||
An SSHPOP provisioner allows a client to renew, revoke, or rekey an SSH
|
|
||||||
certificate using that certificate for authentication with the CA.
|
|
||||||
The renew and rekey methods can only be used on SSH host certificates.
|
|
||||||
|
|
||||||
An SSHPOP provisioner is configured with the user and host root ssh certificates
|
|
||||||
from the `ca.json`. The SSHPOP provisioner can only authenticate SSHPOP tokens
|
|
||||||
generated using SSH certificates created by `step-ca`.
|
|
||||||
|
|
||||||
An SSHPOP token is a JWT, signed by the certificate private key, with an `sshpop`
|
|
||||||
header that contains the SSH certificate.
|
|
||||||
|
|
||||||
Below is an example of an SSHPOP provisioner in the `ca.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
...
|
|
||||||
{
|
|
||||||
"type": "SSHPOP",
|
|
||||||
"name": "sshpop-smallstep",
|
|
||||||
"claims": {
|
|
||||||
"enableSSHCA": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `SSHPOP`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
### ACME
|
|
||||||
|
|
||||||
An ACME provisioner allows a client to request a certificate from the server
|
|
||||||
using the [ACME Protocol](https://tools.ietf.org/html/rfc8555). The ACME
|
|
||||||
provisioner can only request X509 certificates. All authentication of the CSR
|
|
||||||
is managed by the ACME protocol.
|
|
||||||
|
|
||||||
Below is an example of an ACME provisioner in the `ca.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
...
|
|
||||||
{
|
|
||||||
"type": "ACME",
|
|
||||||
"name": "my-acme-provisioner",
|
|
||||||
"forceCN": true,
|
|
||||||
"requireEAB": false,
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "8h",
|
|
||||||
"defaultTLSCertDuration": "2h",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `ACME`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `forceCN` (optional): force one of the SANs to become the Common Name, if a
|
|
||||||
common name is not provided.
|
|
||||||
|
|
||||||
* `requireEAB` (optional): require clients to provide External Account Binding
|
|
||||||
credentials when creating an ACME Account.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
See our [`step-ca` ACME tutorial](https://app.smallstep.com/docs/[product]/tutorials/acme-provisioners)
|
|
||||||
for more guidance on configuring and using the ACME protocol with `step-ca`.
|
|
||||||
|
|
||||||
### K8sSA - Kubernetes Service Account
|
|
||||||
|
|
||||||
A K8sSA provisioner allows a client to request a certificate from the server
|
|
||||||
using a Kubernetes Service Account Token.
|
|
||||||
|
|
||||||
As of the time when this provisioner was coded, the Kubernetes Service Account
|
|
||||||
API for retrieving the token from a running instance was still in beta. Therefore,
|
|
||||||
our K8sSA provisioner must be configured with the public key that will be used
|
|
||||||
to validate K8sSA tokens.
|
|
||||||
|
|
||||||
K8sSA tokens are very minimal. There is no place for SANs, or other details that
|
|
||||||
a user may want validated in a CSR. It is essentially a bearer token. Therefore,
|
|
||||||
at this time a K8sSA token can be used to sign a CSR with any SANs. Said
|
|
||||||
differently, the **K8sSA provisioner does little to no validation on the CSR
|
|
||||||
before signing it**. You should only configure and use this provisioner if you
|
|
||||||
know what you are doing. If a malicious user obtains the private key they will
|
|
||||||
be able to create certificates with any SANs and Subject.
|
|
||||||
|
|
||||||
Below is an example of a K8sSA provisioner in the `ca.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
...
|
|
||||||
{
|
|
||||||
"type": "K8sSA",
|
|
||||||
"name": "my-kube-provisioner",
|
|
||||||
"publicKeys": "LS0tLS1...LS0tCg==",
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "8h",
|
|
||||||
"defaultTLSCertDuration": "2h",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `K8sSA`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `publicKeys` (mandatory): a base64 encoded list of public keys used to validate
|
|
||||||
K8sSA tokens.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
### Provisioners for Cloud Identities
|
|
||||||
|
|
||||||
[Step certificates](https://github.com/smallstep/certificates) can grant
|
|
||||||
certificates to code running in a machine without any other authentication than
|
|
||||||
the one provided by the cloud. Usually, this is implemented with some kind of
|
|
||||||
signed document, but the information contained on them might not be enough to
|
|
||||||
generate a certificate. Due to this limitation, the cloud identities use by
|
|
||||||
default a trust model called Trust On First Use (TOFU).
|
|
||||||
|
|
||||||
The Trust On First Use model allows the use of more permissive CSRs that can
|
|
||||||
have custom SANs that cannot be validated. But it comes with the limitation that
|
|
||||||
you can only grant a certificate once. After this first grant, the same machine
|
|
||||||
will need to renew the certificate using mTLS, and the CA will block any other
|
|
||||||
attempt to grant a certificate to that instance.
|
|
||||||
|
|
||||||
#### AWS
|
|
||||||
|
|
||||||
The AWS provisioner allows granting a certificate to an Amazon EC2 instance
|
|
||||||
using the [Instance Identity Documents](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html)
|
|
||||||
|
|
||||||
The [step](https://github.com/smallstep/cli) CLI will generate a custom JWT
|
|
||||||
token containing the instance identity document and its signature and the CA
|
|
||||||
will grant a certificate after validating it.
|
|
||||||
|
|
||||||
In the ca.json, an AWS provisioner looks like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "AWS",
|
|
||||||
"name": "Amazon Web Services",
|
|
||||||
"accounts": ["1234567890"],
|
|
||||||
"disableCustomSANs": false,
|
|
||||||
"disableTrustOnFirstUse": false,
|
|
||||||
"instanceAge": "1h",
|
|
||||||
"iidRoots": "/path/to/aws.crt",
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "2160h",
|
|
||||||
"defaultTLSCertDuration": "2160h"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `AWS`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `accounts` (optional): the list of AWS account numbers that are allowed to use
|
|
||||||
this provisioner. If none is specified, all AWS accounts will be valid.
|
|
||||||
|
|
||||||
* `disableCustomSANs` (optional): by default custom SANs are valid, but if this
|
|
||||||
option is set to true only the SANs available in the instance identity
|
|
||||||
document will be valid, these are the private IP and the DNS
|
|
||||||
`ip-<private-ip>.<region>.compute.internal`.
|
|
||||||
|
|
||||||
* `disableTrustOnFirstUse` (optional): by default only one certificate will be
|
|
||||||
granted per instance, but if the option is set to true this limit is not set
|
|
||||||
and different tokens can be used to get different certificates.
|
|
||||||
|
|
||||||
* `instanceAge` (optional): the maximum age of an instance to grant a
|
|
||||||
certificate. The instance age is a string using the duration format.
|
|
||||||
|
|
||||||
* `iidRoots` (optional): the path to one or more public certificates in PEM
|
|
||||||
format used to validate the signature of the instance identity document.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
#### GCP
|
|
||||||
|
|
||||||
The GCP provisioner grants certificates to Google Compute Engine instance using
|
|
||||||
its [identity](https://cloud.google.com/compute/docs/instances/verifying-instance-identity)
|
|
||||||
token. The CA will validate the JWT and grant a certificate.
|
|
||||||
|
|
||||||
In the ca.json, a GCP provisioner looks like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "GCP",
|
|
||||||
"name": "Google Cloud",
|
|
||||||
"serviceAccounts": ["1234567890"],
|
|
||||||
"projectIDs": ["project-id"],
|
|
||||||
"disableCustomSANs": false,
|
|
||||||
"disableTrustOnFirstUse": false,
|
|
||||||
"instanceAge": "1h",
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "2160h",
|
|
||||||
"defaultTLSCertDuration": "2160h"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `GCP`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `serviceAccounts` (optional): the list of service account numbers that are
|
|
||||||
allowed to use this provisioner. If none is specified, all service accounts
|
|
||||||
will be valid.
|
|
||||||
|
|
||||||
* `projectIDs` (optional): the list of project identifiers that are allowed to
|
|
||||||
use this provisioner. If non is specified all project will be valid.
|
|
||||||
|
|
||||||
* `disableCustomSANs` (optional): by default custom SANs are valid, but if this
|
|
||||||
option is set to true only the SANs available in the instance identity
|
|
||||||
document will be valid, these are the DNS
|
|
||||||
`<instance-name>.c.<project-id>.internal` and
|
|
||||||
`<instance-name>.<zone>.c.<project-id>.internal`
|
|
||||||
|
|
||||||
* `disableTrustOnFirstUse` (optional): by default only one certificate will be
|
|
||||||
granted per instance, but if the option is set to true this limit is not set
|
|
||||||
and different tokens can be used to get different certificates.
|
|
||||||
|
|
||||||
* `instanceAge` (optional): the maximum age of an instance to grant a
|
|
||||||
certificate. The instance age is a string using the duration format.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
||||||
|
|
||||||
#### Azure
|
|
||||||
|
|
||||||
The Azure provisioner grants certificates to Microsoft Azure instances using
|
|
||||||
the [managed identities tokens](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token).
|
|
||||||
The CA will validate the JWT and grant a certificate.
|
|
||||||
|
|
||||||
In the ca.json, an Azure provisioner looks like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "Azure",
|
|
||||||
"name": "Microsoft Azure",
|
|
||||||
"tenantId": "b17c217c-84db-43f0-babd-e06a71083cda",
|
|
||||||
"resourceGroups": ["backend", "accounting"],
|
|
||||||
"audience": "https://management.azure.com/",
|
|
||||||
"disableCustomSANs": false,
|
|
||||||
"disableTrustOnFirstUse": false,
|
|
||||||
"claims": {
|
|
||||||
"maxTLSCertDuration": "2160h",
|
|
||||||
"defaultTLSCertDuration": "2160h"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* `type` (mandatory): indicates the provisioner type and must be `Azure`.
|
|
||||||
|
|
||||||
* `name` (mandatory): a string used to identify the provider when the CLI is
|
|
||||||
used.
|
|
||||||
|
|
||||||
* `tenantId` (mandatory): the Azure account tenant id for this provisioner. This
|
|
||||||
id is the Directory ID available in the Azure Active Directory properties.
|
|
||||||
|
|
||||||
* `audience` (optional): defaults to `https://management.azure.com/` but it can
|
|
||||||
be changed if necessary.
|
|
||||||
|
|
||||||
* `resourceGroups` (optional): the list of resource group names that are allowed
|
|
||||||
to use this provisioner. If none is specified, all resource groups will be
|
|
||||||
valid.
|
|
||||||
|
|
||||||
* `disableCustomSANs` (optional): by default custom SANs are valid, but if this
|
|
||||||
option is set to true only the SANs available in the token will be valid, in
|
|
||||||
Azure only the virtual machine name is available.
|
|
||||||
|
|
||||||
* `disableTrustOnFirstUse` (optional): by default only one certificate will be
|
|
||||||
granted per instance, but if the option is set to true this limit is not set
|
|
||||||
and different tokens can be used to get different certificates.
|
|
||||||
|
|
||||||
* `claims` (optional): overwrites the default claims set in the authority, see
|
|
||||||
the [top](#provisioners) section for all the options.
|
|
|
@ -1,409 +0,0 @@
|
||||||
# Frequently Asked Questions
|
|
||||||
|
|
||||||
These are some commonly asked questions on the topics of PKI, TLS, X509,
|
|
||||||
cryptography, threshold-cryptography, etc.
|
|
||||||
Hopefully we will reduce the amount of hand-waving in these responses as we add
|
|
||||||
more features to the Step toolkit over time.
|
|
||||||
|
|
||||||
> We encourage you to read
|
|
||||||
> [our blog post on everything relating to PKI](https://smallstep.com/blog/everything-pki.html)
|
|
||||||
> as we believe it to be a solid resource that answers many of of the questions
|
|
||||||
> listed below.
|
|
||||||
|
|
||||||
## What are TLS & PKI?
|
|
||||||
|
|
||||||
TLS stands for *transport layer security*. It used to be called *secure sockets
|
|
||||||
layer* (or SSL), but technically SSL refers to an older version of the protocol.
|
|
||||||
Normal TCP connections communicate in plain text, allowing attackers to
|
|
||||||
eavesdrop and spoof messages. If used properly, TLS provides *confidentiality*
|
|
||||||
and *integrity* for TCP traffic, ensuring that messages can only be seen by their
|
|
||||||
intended recipient, and cannot be modified in transit.
|
|
||||||
|
|
||||||
TLS is a complicated protocol with lots of options, but the most common mode of
|
|
||||||
operation establishes a secure channel using *asymmetric cryptography* with
|
|
||||||
*digital certificates* (or just certificates for short).
|
|
||||||
|
|
||||||
First, some quick definitions:
|
|
||||||
* *Asymmetric cryptography* (a.k.a., public key cryptography) is an underappreciated
|
|
||||||
gift from mathematics to computer science. It uses a *key pair*: a private key
|
|
||||||
known only to the recipient of the message, and a public key that can be broadly
|
|
||||||
distributed, even to adversaries, without compromising security.
|
|
||||||
* *Digital certificates* are data structures that map a public key to the
|
|
||||||
well-known name of the owner of the corresponding private key (e.g., a DNS host name).
|
|
||||||
They *bind* a name to the public key so you can address recipients by name instead of
|
|
||||||
using public keys directly (which are big random numbers).
|
|
||||||
|
|
||||||
Briefly, there are two functions that can be achieved using asymmetric cryptography:
|
|
||||||
* Messages can be *encrypted* using the public key to ensure that only the
|
|
||||||
private key holder can *decrypt* them, and
|
|
||||||
* Messages can be *signed* using the private key so that anyone with the *public
|
|
||||||
key* knows the message came from the private key holder.
|
|
||||||
With digital certificates, you can replace "private key holder" with "named entity,"
|
|
||||||
which makes things a whole lot more useful. It lets you use names, instead of
|
|
||||||
public keys, to address messages.
|
|
||||||
|
|
||||||
PKI stands for *public key infrastructure*. Abstractly, it's a set of policies
|
|
||||||
and procedures for managing digital certificates (i.e., managing the bindings
|
|
||||||
between names and public keys). Without proper secure PKI, an attacker can fake
|
|
||||||
a binding and undermine security.
|
|
||||||
|
|
||||||
## What's a certificate authority?
|
|
||||||
|
|
||||||
A certificate authority (CA) stores, issues, and signs digital certificates. CAs
|
|
||||||
have their own key pair, with the private key carefully secured (often offline).
|
|
||||||
The CA binds its name to its public key by signing a digital certificate using
|
|
||||||
its own private key (called *self signing*). The CA's self-signed certificate,
|
|
||||||
or *root certificate*, is distributed to all principals in the system (e.g., all
|
|
||||||
of the clients and servers in your infrastructure).
|
|
||||||
|
|
||||||
So, the CA is tasked with securely binding names to public keys. Here's how that process works.
|
|
||||||
1. When a named principal wants a certificate, it generates its own key pair.
|
|
||||||
Nobody else ever needs to know the private key, not even the CA.
|
|
||||||
2. The principal creates a certificate signing request (CSR), containing its
|
|
||||||
name and public key (and some other stuff), and submits it to the CA. The CSR is
|
|
||||||
self-signed, like the root certificate, so the CA knows that the requestor has
|
|
||||||
the corresponding private key.
|
|
||||||
3. The CA performs some form of *identity proofing*, certifying that the request
|
|
||||||
is coming from the principal named in the CSR.
|
|
||||||
4. Once satisfied, the CA issues a certificate by using its own private key to
|
|
||||||
sign a certificate binding the name and public key from the CSR.
|
|
||||||
|
|
||||||
Certificates signed by the CA are used to securely introduce principals that
|
|
||||||
don't already know one anothers' public keys. Assuming both principals agree on
|
|
||||||
a trusted CA, they can exchange digital certificates and authenticate the
|
|
||||||
signatures to gain some assurance that they are communicating with the named entity.
|
|
||||||
|
|
||||||
Technically, smallstep's certificate authority is more than just a certificate
|
|
||||||
authority. It combines several PKI roles into one simple, flexible package. It
|
|
||||||
acts as a *registration authority*, accepting requests for digital certificates
|
|
||||||
and verifying the identity of the requesting entities before establishing bindings.
|
|
||||||
It also acts as a *central directory* and more generally as a *certificate
|
|
||||||
management system*, a secure location for storing and distributing key material.
|
|
||||||
|
|
||||||
## Why not just use Verisign, Entrust, Let's Encrypt, etc?
|
|
||||||
|
|
||||||
The web's *open public key infrastructure* (web PKI), while far from perfect,
|
|
||||||
is an important foundation for securing the web. So why not use it for securing
|
|
||||||
communication for your own internal infrastructure? There are several reasons:
|
|
||||||
* It's expensive to provision certificates from a public CA for all of your services
|
|
||||||
* Public CAs can't handle client certificates (mutual TLS)
|
|
||||||
* It's much harder (and more expensive) to revoke or roll certificates from public CAs
|
|
||||||
* It relies on a third party that can subvert your security
|
|
||||||
|
|
||||||
More broadly, the answer is that web PKI was designed for the web. A lot of the
|
|
||||||
web PKI design decisions aren't appropriate for internal systems.
|
|
||||||
|
|
||||||
## How does identity proofing work?
|
|
||||||
|
|
||||||
In general, trust will always flow back out to you, the operator of your system.
|
|
||||||
With that in mind, the simplest form of identity proofing is manual: [describe
|
|
||||||
token-based manual mechanism here]. As your system grows, this process can become
|
|
||||||
onerous. Automated identity proofing requires careful coordination between
|
|
||||||
different parts of your system. Smallstep provides additional tooling, and vetted
|
|
||||||
designs, to help with this. If you integrate with our other tools its easy to
|
|
||||||
start with a manual identity proofing mechanism and move to a more sophisticated
|
|
||||||
automated method as your system grows.
|
|
||||||
|
|
||||||
## What are the security risks of exposing the OAuth Client Secret in the output of `step ca provisioner list`?
|
|
||||||
|
|
||||||
It would be nice if we could have the CA operate as an OAuth confidential
|
|
||||||
client, keeping the client secret private and redirecting back to the CA
|
|
||||||
instead of to loopback. But, to be clear, this is not an abuse of the OAuth
|
|
||||||
spec. The way this was implemented in step, as an OAuth native application
|
|
||||||
using a public client, is standard, was intentional, (mostly) conforms to best
|
|
||||||
current practices, and the flow we're using is widely used in practice. A
|
|
||||||
confidential client is (strictly?) more secure. But a public client that
|
|
||||||
redirects to loopback isn’t a significant security risk under a normal threat
|
|
||||||
model.
|
|
||||||
|
|
||||||
### The current flow
|
|
||||||
The advantage of the current flow is that it’s more general purpose. For
|
|
||||||
example, `step oauth` works without any additional infrastructure. An issued
|
|
||||||
access token can be used from the command line, and OIDC identity tokens can be
|
|
||||||
safely used to authenticate to remote services (including remote services that
|
|
||||||
don’t speak OAuth OIDC, or don’t even speak HTTP, but can validate a
|
|
||||||
JWT). `step-ca` is one example of a remote service that can authenticate
|
|
||||||
step users via OIDC identity token. You can also use `step crypto jwt verify` to
|
|
||||||
authenticate using OIDC at the command line.
|
|
||||||
|
|
||||||
The particular details of the OAuth flow we selected has pros & cons, as does
|
|
||||||
any flow. The relevant security risks are:
|
|
||||||
|
|
||||||
1. Since the OAuth access token isn’t issued directly to a remote server (e.g.,
|
|
||||||
`step-ca`), remote servers can’t safely use the issued access tokens
|
|
||||||
without significant care. If they did, an attacker might be able to maliciously
|
|
||||||
trick the remote server into using an access token that was issued to a
|
|
||||||
different client.
|
|
||||||
|
|
||||||
2. The redirect back from the OAuth authorization server to the
|
|
||||||
client can be intercepted by another process running on the local machine. This
|
|
||||||
isn’t really necessary though, because...
|
|
||||||
|
|
||||||
3. The `client_secret` is public, so anyone can initiate (and complete) an OAuth
|
|
||||||
flow using our client (but it will always redirect back to 127.0.0.1).
|
|
||||||
|
|
||||||
The first threat is moot since we don't actually use the access token for
|
|
||||||
anything when we're connecting to `step-ca`. Unfortunately there's no way to not
|
|
||||||
get an access token. So we just ignore it.
|
|
||||||
|
|
||||||
Note that it *is* safe to use the access token from the command line to access
|
|
||||||
resources at a remote API. For example, it’s safe to user `step oauth` to obtain
|
|
||||||
an OAuth access token from Google and use it to access Google’s APIs in a bash
|
|
||||||
script.
|
|
||||||
|
|
||||||
More generally, access tokens are for accessing resources (authorization) and
|
|
||||||
are not useful for authenticating a user since they're not audience-addressed.
|
|
||||||
If you and I both have a Google OAuth client, I could get Alice to OAuth into
|
|
||||||
my app and use the issued access token to masquerade as Alice to you. But OIDC
|
|
||||||
identity tokens are audience-addressed. An identity token is a JWT with the
|
|
||||||
`client_id` baked in as the `aud` (audience) parameter. As long as clients check
|
|
||||||
this parameter (which `step-ca` does) they're not susceptible to this attack. In
|
|
||||||
fact, OIDC identity tokens were designed and developed precisely to solve this
|
|
||||||
problem.
|
|
||||||
|
|
||||||
So it's completely safe for one entity to obtain an *identity token* from an IdP
|
|
||||||
on behalf of a user and use it to authenticate to another entity (like `step`
|
|
||||||
does). That's exactly the use case OIDC was designed to support.
|
|
||||||
|
|
||||||
The second and third threats are related. They involve a malicious attempt to
|
|
||||||
initiate an OAuth OIDC flow using our client credentials. There's a lot of
|
|
||||||
analysis we could do here comparing this situation to a non-native (e.g., *web*)
|
|
||||||
client and to other flows (e.g., the *implicit flow*, which also makes the
|
|
||||||
client secret public). Skipping that detail, we know two things for sure:
|
|
||||||
|
|
||||||
1. OAuth flows generally require user consent to complete (e.g., a user has to
|
|
||||||
"approve" an application's authentication / authorization request)
|
|
||||||
|
|
||||||
2. An OAuth flow initiated using our client will always redirect back to 127.0.0.1
|
|
||||||
|
|
||||||
So a malicious attacker trying to obtain an *identity token* needs two things:
|
|
||||||
|
|
||||||
1. They need to get user consent to complete an OAuth flow
|
|
||||||
2. They need to have local access to the user's machine
|
|
||||||
|
|
||||||
This is already a pretty high bar. It’s worth noting, however, that the first
|
|
||||||
part is *much* easier if the user is already logged in and the identity provider
|
|
||||||
is configured to not require consent (i.e., the OAuth flow is automatically
|
|
||||||
completed without the user having to click any buttons). Okta seems to
|
|
||||||
do this for some applications by default.
|
|
||||||
|
|
||||||
It's also worth noting that a process with local access could probably obtain
|
|
||||||
an access/identity token for a *confidential client* without knowing the client
|
|
||||||
secret. That's the main reason I don't think the flow we're using has a
|
|
||||||
meaningful security impact under most threat models. The biggest difference is
|
|
||||||
that attacking a confidential client would probably require privileged (root)
|
|
||||||
access, whereas our flow could be attacked by an unprivileged process. But
|
|
||||||
the fruit of our OAuth flow — the SSH certificate — is also available for
|
|
||||||
use by an unprivileged process running locally via the `ssh-agent`. So the
|
|
||||||
only thing possibly gained is the ability to exfiltrate.
|
|
||||||
|
|
||||||
### Stuff we should consider doing
|
|
||||||
There are at least three OAuth features that are relevant to this discussion.
|
|
||||||
Two have already been mentioned:
|
|
||||||
|
|
||||||
1. OAuth *public clients* for *native applications* can be (er, are *supposed*
|
|
||||||
to be) created without a client secret
|
|
||||||
|
|
||||||
2. Proof Key for Code Exchange (PKCE) helps ensure that the process requesting the access token / identity token is the same process that initiated the flow
|
|
||||||
|
|
||||||
The first feature, clients without secrets, is mostly cosmetic. There's no real
|
|
||||||
difference between a public secret and no secret, except that it's confusing to
|
|
||||||
have something called a "secret" that's not actually secret. (Caveat: IdPs that
|
|
||||||
support "native applications" without secrets typically enforce other rules for
|
|
||||||
these clients — they often require PKCE and might not issue a renew token, for
|
|
||||||
example. But these features can often be turned on/of for other client types,
|
|
||||||
too.)
|
|
||||||
|
|
||||||
The reason we don't assume a *public client* without a secret is that,
|
|
||||||
unfortunately, not all IdPs support them. Significantly, Google does not. In
|
|
||||||
fact, gcloud (Google Cloud's CLI tool) uses OAuth OIDC and uses the exact same
|
|
||||||
technique we're using. If you look at the source you'll find their
|
|
||||||
"NOTSOSECRET" All of that said, we should support "native clients" without
|
|
||||||
secrets at some point.
|
|
||||||
|
|
||||||
We should also implement Proof Key for Code Exchange (PKCE). This has been on
|
|
||||||
our backlog for a while, and it's actually really simple and useful. It's
|
|
||||||
definitely low-hanging fruit. Before initiating the OAuth flow your client
|
|
||||||
generates a random number. It hashes that number and passes the hash to the IdP
|
|
||||||
as part of the authorization request (the URL that users are sent to for
|
|
||||||
login). After authenticating and consenting, when the user is
|
|
||||||
redirected back to the client, the client makes a request to the IdP to get an
|
|
||||||
access token & identity token. In *that* request the client must include the
|
|
||||||
*unhashed* random number. The IdP re-hashes it and compares it to the value it
|
|
||||||
received in the authorization request. If they match, the IdP can be certain
|
|
||||||
that the entity making the access token request is the same entity that
|
|
||||||
initiated the flow. In other words, the request has not been intercepted by
|
|
||||||
some malicious intermediary.
|
|
||||||
|
|
||||||
The last hardening mechanism to be aware of are the `acr` and `amr` parameters.
|
|
||||||
Basically, when the OAuth flow is initiated the client can request that the IdP
|
|
||||||
require consent, do 2FA, and a bunch of other stuff. The issued identity token
|
|
||||||
includes parameters to indicate that these processes did, indeed, occur.
|
|
||||||
Leveraging this mechanism one could configure `step-ca` to check these parameters
|
|
||||||
and be sure that users have consented and undergone a 2FA presence check (e.g.,
|
|
||||||
tapped a security token). Unfortunately, like a bunch of other optional
|
|
||||||
OAuth features, many IdPs (*cough* Google *cough*) don't support this stuff.
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
Implementing PKCE should be our highest priority item. Support for "native"
|
|
||||||
clients without secrets would also be nice. Forcing 2FA & consent via `acr` & `amr`
|
|
||||||
is also a good idea. Support for non-native clients that redirect back to the
|
|
||||||
CA, and where the secret is *actually* secret, would also be nice. But it's a
|
|
||||||
bigger architectural change and the security implications aren't actually that
|
|
||||||
severe.
|
|
||||||
|
|
||||||
## I already have PKI in place. Can I use this with my own root certificate?
|
|
||||||
|
|
||||||
Yes. There's a easy way, and a longer but more secure way to do this.
|
|
||||||
|
|
||||||
### Option 1: The easy way
|
|
||||||
|
|
||||||
If you have your root CA signing key available, you can run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
step ca init --root=[ROOT_CERT_FILE] --key=[ROOT_PRIVATE_KEY_FILE]
|
|
||||||
```
|
|
||||||
|
|
||||||
The root certificate can be in PEM or DER format, and the signing key can be a PEM file containing a PKCS#1, PKCS#8, or RFC5915 (for EC) key.
|
|
||||||
|
|
||||||
### Option 2: More secure
|
|
||||||
|
|
||||||
That said, CAs are usually pretty locked down and it's bad practice to move the private key around. So I'm gonna assume that's not an option and give you the more complex instructions to do this "the right way", by generating a CSR for `step-ca`, getting it signed by your existing root, and configuring `step-ca` to use it.
|
|
||||||
|
|
||||||
When you run `step ca init` we create a couple artifacts under `~/.step/`. The important ones for us are:
|
|
||||||
|
|
||||||
- `~/.step/certs/root_ca.crt` is your root CA certificate
|
|
||||||
- `~/.step/secrets/root_ca_key` is your root CA signing key
|
|
||||||
- `~/.step/certs/intermediate_ca.crt` is your intermediate CA cert
|
|
||||||
- `~/.step/secrets/intermediate_ca_key` is the intermediate signing key used by `step-ca`
|
|
||||||
|
|
||||||
The easiest thing to do is to run `step ca init` to get this scaffolding configuration in place, then remove/replace these artifacts with new ones that are tied to your existing root CA.
|
|
||||||
|
|
||||||
First, `step-ca` does not actually need the root CA signing key. So you can simply remove that file:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rm ~/.step/secrets/root_ca_key
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, replace `step-ca`'s root CA cert with your existing root certificate:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mv /path/to/your/existing/root.crt ~/.step/certs/root_ca.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you need to generate a new signing key and intermediate certificate, signed by your existing root CA. To do that we can use the `step certificate create` subcommand to generate a certificate signing request (CSR) that we'll have your existing root CA sign, producing an intermediate certificate.
|
|
||||||
|
|
||||||
To generate those artifacts run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
step certificate create "Intermediate CA Name" intermediate.csr intermediate_ca_key --csr
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, you'll need to transfer the CSR file (`intermediate.csr`) to your existing root CA and get it signed.
|
|
||||||
|
|
||||||
Now you need to get the CSR executed by your existing root CA.
|
|
||||||
|
|
||||||
**Active Directory Certificate Services**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
certreq -submit -attrib "CertificateTemplate:SubCA" intermediate.csr intermediate.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
**AWS Certificate Manager Private CA**
|
|
||||||
|
|
||||||
Here's a Python script that uses [issue-certificate](https://docs.aws.amazon.com/acm-pca/latest/userguide/PcaIssueCert.html) to process the CSR:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import boto3
|
|
||||||
import sys
|
|
||||||
|
|
||||||
AWS_CA_ARN = '[YOUR_PRIVATE_CA_ARN]'
|
|
||||||
|
|
||||||
csr = ''.join(sys.stdin.readlines())
|
|
||||||
|
|
||||||
client = boto3.client('acm-pca')
|
|
||||||
response = client.issue_certificate(
|
|
||||||
CertificateAuthorityArn=AWS_CA_ARN,
|
|
||||||
Csr=csr,
|
|
||||||
SigningAlgorithm='SHA256WITHRSA',
|
|
||||||
TemplateArn='arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen1/V1',
|
|
||||||
Validity={
|
|
||||||
'Value': 5,
|
|
||||||
'Type': 'YEARS'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
print(f"Creating certificate with ARN {response['CertificateArn']}...", file=sys.stderr, end='')
|
|
||||||
waiter = client.get_waiter('certificate_issued')
|
|
||||||
waiter.wait(
|
|
||||||
CertificateAuthorityArn=AWS_CA_ARN,
|
|
||||||
CertificateArn=response['CertificateArn']
|
|
||||||
)
|
|
||||||
print('done.', file=sys.stderr)
|
|
||||||
response = client.get_certificate(
|
|
||||||
CertificateArn=response['CertificateArn'],
|
|
||||||
CertificateAuthorityArn=AWS_CA_ARN
|
|
||||||
)
|
|
||||||
print(response['Certificate'])
|
|
||||||
```
|
|
||||||
|
|
||||||
To run it, fill in the ARN of your CA and run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python issue_certificate.py < intermediate.csr > intermediate.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
**OpenSSL**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl ca -config [ROOT_CA_CONFIG_FILE] \
|
|
||||||
-extensions v3_intermediate_ca \
|
|
||||||
-days 3650 -notext -md sha512 \
|
|
||||||
-in intermediate.csr \
|
|
||||||
-out intermediate.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
**CFSSL**
|
|
||||||
|
|
||||||
For CFSSL you'll need a signing profile that specifies a 10-year expiry:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > ca-smallstep-config.json <<EOF
|
|
||||||
{
|
|
||||||
"signing": {
|
|
||||||
"profiles": {
|
|
||||||
"smallstep": {
|
|
||||||
"expiry": "87660h",
|
|
||||||
"usages": ["signing"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
Now use that config to sign the intermediate certificate:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cfssl sign -ca ca.pem \
|
|
||||||
-ca-key ca-key.pem \
|
|
||||||
-config ca-smallstep-config.json \
|
|
||||||
-profile smallstep
|
|
||||||
-csr intermediate.csr | cfssljson -bare
|
|
||||||
```
|
|
||||||
|
|
||||||
This process will yield a signed `intermediate.crt` certificate (or `cert.pem` for CFSSL). Transfer this file back to the machine running `step-ca`.
|
|
||||||
|
|
||||||
Finally, replace the intermediate .crt and signing key produced by `step ca init` with the new ones we just created:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mv intermediate.crt ~/.step/certs/intermediate_ca.crt
|
|
||||||
mv intermediate_ca_key ~/.step/secrets/intermediate_ca_key
|
|
||||||
```
|
|
||||||
|
|
||||||
That should be it! You should be able to start `step-ca` and the certificates should be trusted by anything that trusts your existing root CA.
|
|
||||||
|
|
||||||
## Further Reading
|
|
||||||
|
|
||||||
* [Use TLS Everywhere](https://smallstep.com/blog/use-tls.html)
|
|
||||||
* [Everything you should know about certificates and PKI but are too afraid to ask](https://smallstep.com/blog/everything-pki.html)
|
|
|
@ -1,211 +0,0 @@
|
||||||
# Revocation
|
|
||||||
|
|
||||||
**Active Revocation**: A certificate is no longer valid from the moment it has
|
|
||||||
been actively revoked. Clients are required to check against centralized
|
|
||||||
sources of certificate validity information (e.g. by using CRLs (Certificate
|
|
||||||
Revocation Lists) or OCSP (Online Certificate Status Protocol)) to
|
|
||||||
verify that certificates have not been revoked. Active Revocation requires
|
|
||||||
clients to take an active role in certificate validation for the benefit of
|
|
||||||
real time revocation.
|
|
||||||
|
|
||||||
**Passive Revocation**: A certificate that has been passively revoked can no
|
|
||||||
longer be renewed. It will still be valid for the remainder of it's validity period,
|
|
||||||
but cannot be prolonged. The benefit of passive revocation is that clients
|
|
||||||
can verify certificates in a simple, decentralized manner without relying on
|
|
||||||
centralized 3rd parties. Passive revocation works best with short
|
|
||||||
certificate lifetimes.
|
|
||||||
|
|
||||||
`step certificates` currently only supports passive revocation. Active revocation
|
|
||||||
is on our roadmap.
|
|
||||||
|
|
||||||
Run `step help ca revoke` from the command line for full documentation, list of
|
|
||||||
command line flags, and examples.
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
Certificates can be created and revoked through the `step cli`. Let's walk
|
|
||||||
through an example.
|
|
||||||
|
|
||||||
### Requirements
|
|
||||||
|
|
||||||
* `step` (>=v0.10.0) ([install instructions](../README.md#installation-guide))
|
|
||||||
|
|
||||||
### Let's Get To It
|
|
||||||
|
|
||||||
1. Bootstrap your PKI.
|
|
||||||
|
|
||||||
> If you've already done this before and you have a `$STEPPATH` with certs,
|
|
||||||
> secrets, and configuration files then you can move on to step 2.
|
|
||||||
|
|
||||||
Run `step ca init`.
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step ca init --name "Local CA" --provisioner admin --dns localhost --address ":443"</b>
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
Move on to step 3.
|
|
||||||
|
|
||||||
2. Configure a persistence layer in your `ca.json`.
|
|
||||||
|
|
||||||
> If you did step 1 with `step` v0.10.0 or greater then your db will
|
|
||||||
> have been configured in the previous step.
|
|
||||||
|
|
||||||
Get your full step path by running `echo $(step path)`. Now edit
|
|
||||||
your `ca.json` by adding the following stanza as a top-level attribute:
|
|
||||||
> Your `ca.json` should be in `$(step path)/config/ca.json`.
|
|
||||||
|
|
||||||
```
|
|
||||||
...
|
|
||||||
"db": {
|
|
||||||
"type": "badger",
|
|
||||||
"dataSource": "<full step path>/db"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
Check out our [database documentation](./database.md) to see all available
|
|
||||||
database backends and adapters.
|
|
||||||
|
|
||||||
3. Run the CA
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step-ca $(step path)/config/ca.json</b>
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
4. Create a certificate for localhost
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step ca certificate localhost localhost.crt localhost.key</b>
|
|
||||||
✔ Key ID: n2kqNhicCCqVxJidspCQrjXWBtGwsa9zk3eBObrViy8 (sebastian@smallstep.com)
|
|
||||||
✔ Please enter the password to decrypt the provisioner key:
|
|
||||||
✔ CA: https://ca.smallstep.com
|
|
||||||
✔ Certificate: localhost.crt
|
|
||||||
✔ Private Key: localhost.key
|
|
||||||
|
|
||||||
<b>$ step certificate inspect --short localhost.crt</b>
|
|
||||||
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2400...2409]
|
|
||||||
Subject: localhost
|
|
||||||
Issuer: Smallstep Intermediate CA
|
|
||||||
Provisioner: sebastian@smallstep.com [ID: n2kq...Viy8]
|
|
||||||
Valid from: 2019-04-23T22:55:54Z
|
|
||||||
to: 2019-04-24T22:55:54Z
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
5. Renew the certificate (just to prove we can!)
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step ca renew localhost.crt localhost.key</b>
|
|
||||||
✔ Would you like to overwrite localhost.crt [y/n]: y
|
|
||||||
Your certificate has been saved in localhost.crt.
|
|
||||||
|
|
||||||
# Make sure the from timestamp is "newer"
|
|
||||||
<b>$ step certificate inspect --short localhost.crt</b>
|
|
||||||
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 5963...8406]
|
|
||||||
Subject: localhost
|
|
||||||
Issuer: Smallstep Intermediate CA
|
|
||||||
Provisioner: sebastian@smallstep.com [ID: n2kq...Viy8]
|
|
||||||
Valid from: 2019-04-23T22:57:50Z
|
|
||||||
to: 2019-04-24T22:57:50Z
|
|
||||||
</pre></code>
|
|
||||||
|
|
||||||
6. Now let's revoke the certificate
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step certificate inspect --format=json localhost.crt | jq .serial_number</b>
|
|
||||||
"59636004850364466675608080466579278406"
|
|
||||||
# the serial number is unique
|
|
||||||
|
|
||||||
<b>$ step ca revoke 59636004850364466675608080466579278406</b>
|
|
||||||
✔ Key ID: n2kqNhicCCqVxJidspCQrjXWBtGwsa9zk3eBObrViy8 (sebastian@smallstep.com)
|
|
||||||
✔ Please enter the password to decrypt the provisioner key:
|
|
||||||
✔ CA: https://ca.smallstep.com
|
|
||||||
Certificate with Serial Number 59636004850364466675608080466579278406 has been revoked.
|
|
||||||
</pre></code>
|
|
||||||
|
|
||||||
7. Awesome! But did it work?
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step ca renew localhost.crt localhost.key</b>
|
|
||||||
error renewing certificate: Unauthorized
|
|
||||||
|
|
||||||
# log trace from CA:
|
|
||||||
[...]
|
|
||||||
WARN[0569] duration="82.782µs" duration-ns=82782
|
|
||||||
error="renew: certificate has been revoked"
|
|
||||||
fields.time="2019-04-23T16:03:01-07:00" method=POST
|
|
||||||
name=ca path=/renew protocol=HTTP/1.1 referer=
|
|
||||||
remote-address=127.0.0.1 request-id=bivpj9a3q563rpjheh5g
|
|
||||||
size=40 status=401 user-agent=Go-http-client/1.1 user-id=
|
|
||||||
[...]
|
|
||||||
</pre></code>
|
|
||||||
|
|
||||||
8. Other ways to revoke a Certificate
|
|
||||||
|
|
||||||
Use the certificate and key. This method does not require a provisioner
|
|
||||||
because it uses the certificate and key to authenticate the request.
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step ca revoke --cert localhost.crt --key localhost.key</b>
|
|
||||||
Certificate with Serial Number 59636004850364466675608080466579278406 has been revoked.
|
|
||||||
</pre></code>
|
|
||||||
|
|
||||||
Or, revoke a certificate in two steps by first creating a revocation token and
|
|
||||||
then exchanging that token in a revocation request.
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ TOKEN=$(step ca token --revoke 59636004850364466675608080466579278406)</b>
|
|
||||||
✔ Key ID: n2kqNhicCCqVxJidspCQrjXWBtGwsa9zk3eBObrViy8 (sebastian@smallstep.com)
|
|
||||||
✔ Please enter the password to decrypt the provisioner key:
|
|
||||||
|
|
||||||
<b>$ echo $TOKEN | step crypto jwt inspect --insecure</b>
|
|
||||||
{
|
|
||||||
"header": {
|
|
||||||
"alg": "ES256",
|
|
||||||
"kid": "uxEunU9UhUo96lRvKgpEtRevkzbN5Yq88AFFtb1nSGg",
|
|
||||||
"typ": "JWT"
|
|
||||||
},
|
|
||||||
"payload": {
|
|
||||||
"aud": "https://localhost:443/1.0/revoke",
|
|
||||||
"exp": 1556395590,
|
|
||||||
"iat": 1556395290,
|
|
||||||
"iss": "sebastian@smallstep.com",
|
|
||||||
"jti": "1f222fc1a22530b7bcd2a40d7308c566c8e49f90413bc350e07bfabc8002b79b",
|
|
||||||
"nbf": 1556395290,
|
|
||||||
"sha": "fef4c75a050e1f3a31175ca4f4fdb711cbef1efcd374fcae4700596604eb8e5a",
|
|
||||||
"sub": "59636004850364466675608080466579278406"
|
|
||||||
},
|
|
||||||
"signature": "M1wX0ea3VXwS5rIim0TgtcCXHDtvP1GWD15cJSvVkrHNO6XMYl6m3ZmnWdwMi976msv-n2GTG3h6dJ3j2ImdfQ"
|
|
||||||
}
|
|
||||||
|
|
||||||
<b>$ step ca revoke --token $TOKEN 59636004850364466675608080466579278406</b>
|
|
||||||
Certificate with Serial Number 59636004850364466675608080466579278406 has been revoked.
|
|
||||||
</pre></code>
|
|
||||||
|
|
||||||
Or, revoke a certificate in offline mode:
|
|
||||||
|
|
||||||
<pre><code>
|
|
||||||
<b>$ step ca revoke --offline 59636004850364466675608080466579278406</b>
|
|
||||||
Certificate with Serial Number 59636004850364466675608080466579278406 has been revoked.
|
|
||||||
|
|
||||||
<b>$ step ca revoke --offline --cert localhost.crt --key localhost.key</b>
|
|
||||||
Certificate with Serial Number 59636004850364466675608080466579278406 has been revoked.
|
|
||||||
</pre></code>
|
|
||||||
|
|
||||||
> NOTE: you can only revoke a certificate once. Any repeated attempts to revoke
|
|
||||||
> the same serial number will fail.
|
|
||||||
|
|
||||||
Run `step help ca revoke` from the command line for full documentation, list of
|
|
||||||
command line flags, and examples.
|
|
||||||
|
|
||||||
## What's next?
|
|
||||||
|
|
||||||
[Use TLS Everywhere](https://smallstep.com/blog/use-tls.html) and let us know
|
|
||||||
what you think of our tools. Get in touch over
|
|
||||||
[Twitter](twitter.com/smallsteplabs) or through our
|
|
||||||
[GitHub Discussions](https://github.com/smallstep/certificates/discussions) to find answers to frequently asked questions.
|
|
||||||
[Discord](https://bit.ly/step-discord) to chat with us in real time.
|
|
||||||
|
|
||||||
## Further Reading
|
|
||||||
|
|
||||||
* [Use TLS Everywhere](https://smallstep.com/blog/use-tls.html)
|
|
||||||
* [Everything you should know about certificates and PKI but are too afraid to ask](https://smallstep.com/blog/everything-pki.html)
|
|