199 lines
7.2 KiB
Markdown
199 lines
7.2 KiB
Markdown
---
|
|
layout: "docs"
|
|
page_title: "Creating Certificates"
|
|
sidebar_current: "docs-guides-creating-certificates"
|
|
description: |-
|
|
Learn how to create certificates for Consul.
|
|
---
|
|
|
|
# Creating Certificates
|
|
|
|
Correctly configuring TLS can be a complex process, especially given the wide
|
|
range of deployment methodologies. This guide will provide you with a
|
|
production ready TLS configuration.
|
|
|
|
~> Note that while Consul's TLS configuration will be production ready, key
|
|
management and rotation is a complex subject not covered by this guide.
|
|
[Vault][vault] is the suggested solution for key generation and management.
|
|
|
|
The first step to configuring TLS for Consul is generating certificates. In
|
|
order to prevent unauthorized cluster access, Consul requires all certificates
|
|
be signed by the same Certificate Authority (CA). This should be a _private_ CA
|
|
and not a public one like [Let's Encrypt][letsencrypt] as any certificate
|
|
signed by this CA will be allowed to communicate with the cluster.
|
|
|
|
~> Consul certificates may be signed by intermediate CAs as long as the root CA
|
|
is the same. Append all intermediate CAs to the `cert_file`.
|
|
|
|
|
|
## Reference Material
|
|
|
|
- [Encryption](/docs/agent/encryption.html)
|
|
|
|
## Estimated Time to Complete
|
|
|
|
20 minutes
|
|
|
|
## Prerequisites
|
|
|
|
This guide assumes you have [cfssl][cfssl] installed (be sure to install
|
|
cfssljson as well).
|
|
|
|
## Steps
|
|
|
|
### Step 1: Create Certificate Authority
|
|
|
|
There are a variety of tools for managing your own CA, [like the PKI secret
|
|
backend in Vault][vault-pki], but for the sake of simplicity this guide will
|
|
use [cfssl][cfssl]. You can generate a private CA certificate and key with
|
|
[cfssl][cfssl]:
|
|
|
|
```shell
|
|
# Generate a default CSR
|
|
$ cfssl print-defaults csr > ca-csr.json
|
|
```
|
|
Change the `key` field to use RSA with a size of 2048
|
|
|
|
```json
|
|
{
|
|
"CN": "example.net",
|
|
"hosts": [
|
|
"example.net",
|
|
"www.example.net"
|
|
],
|
|
"key": {
|
|
"algo": "rsa",
|
|
"size": 2048
|
|
},
|
|
"names": [
|
|
{
|
|
"C": "US",
|
|
"ST": "CA",
|
|
"L": "San Francisco"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
```shell
|
|
# Generate the CA's private key and certificate
|
|
$ cfssl gencert -initca ca-csr.json | cfssljson -bare consul-ca
|
|
```
|
|
|
|
The CA key (`consul-ca-key.pem`) will be used to sign certificates for Consul
|
|
nodes and must be kept private. The CA certificate (`consul-ca.pem`) contains
|
|
the public key necessary to validate Consul certificates and therefore must be
|
|
distributed to every node that requires access.
|
|
|
|
### Step 2: Generate and Sign Node Certificates
|
|
|
|
Once you have a CA certificate and key you can generate and sign the
|
|
certificates Consul will use directly. TLS certificates commonly use the
|
|
fully-qualified domain name of the system being identified as the certificate's
|
|
Common Name (CN). However, hosts (and therefore hostnames and IPs) are often
|
|
ephemeral in Consul clusters. Not only would signing a new certificate per
|
|
Consul node be difficult, but using a hostname provides no security or
|
|
functional benefits to Consul. To fulfill the desired security properties
|
|
(above) Consul certificates are signed with their region and role such as:
|
|
|
|
* `client.node.global.consul` for a client node in the `global` region
|
|
* `server.node.us-west.consul` for a server node in the `us-west` region
|
|
|
|
To create certificates for the client and server in the cluster with
|
|
[cfssl][cfssl], create the following configuration file as `cfssl.json` to increase the default certificate expiration time:
|
|
|
|
```json
|
|
{
|
|
"signing": {
|
|
"default": {
|
|
"expiry": "87600h",
|
|
"usages": [
|
|
"signing",
|
|
"key encipherment",
|
|
"server auth",
|
|
"client auth"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
```shell
|
|
# Generate a certificate for the Consul server
|
|
$ echo '{"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=consul-ca.pem -ca-key=consul-ca-key.pem -config=cfssl.json \
|
|
-hostname="server.node.global.consul,localhost,127.0.0.1" - | cfssljson -bare server
|
|
|
|
# Generate a certificate for the Consul client
|
|
$ echo '{"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=consul-ca.pem -ca-key=consul-ca-key.pem -config=cfssl.json \
|
|
-hostname="client.node.global.consul,localhost,127.0.0.1" - | cfssljson -bare client
|
|
|
|
# Generate a certificate for the CLI
|
|
$ echo '{"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=consul-ca.pem -ca-key=consul-ca-key.pem -profile=client \
|
|
- | cfssljson -bare cli
|
|
```
|
|
|
|
Using `localhost` and `127.0.0.1` as subject alternate names (SANs) allows
|
|
tools like `curl` to be able to communicate with Consul's HTTP API when run on
|
|
the same host. Other SANs may be added including a DNS resolvable hostname to
|
|
allow remote HTTP requests from third party tools.
|
|
|
|
You should now have the following files:
|
|
|
|
* `cfssl.json` - cfssl configuration.
|
|
* `consul-ca.csr` - CA signing request.
|
|
* `consul-ca-key.pem` - CA private key. Keep safe!
|
|
* `consul-ca.pem` - CA public certificate.
|
|
* `cli.csr` - Consul CLI certificate signing request.
|
|
* `cli-key.pem` - Consul CLI private key.
|
|
* `cli.pem` - Consul CLI certificate.
|
|
* `client.csr` - Consul client node certificate signing request for the `global` region.
|
|
* `client-key.pem` - Consul client node private key for the `global` region.
|
|
* `client.pem` - Consul client node public certificate for the `global` region.
|
|
* `server.csr` - Consul server node certificate signing request for the `global` region.
|
|
* `server-key.pem` - Consul server node private key for the `global` region.
|
|
* `server.pem` - Consul server node public certificate for the `global` region.
|
|
|
|
Each Consul node should have the appropriate key (`-key.pem`) and certificate
|
|
(`.pem`) file for its region and role. In addition each node needs the CA's
|
|
public certificate (`consul-ca.pem`).
|
|
|
|
Please note you will need the keys for the CLI if you choose to disable
|
|
HTTP (in which case running the command `consul members` will return an error).
|
|
This is because the Consul CLI defaults to communicating via HTTP instead of
|
|
HTTPS. We can configure the local Consul client to connect using TLS and specify
|
|
our custom keys and certificates using the command line:
|
|
|
|
```shell
|
|
$ consul members -ca-file=consul-ca.pem -client-cert=cli.pem -client-key=cli-key.pem -http-addr="https://localhost:9090"
|
|
```
|
|
(The command is assuming HTTPS is configured to use port 9090. To see how
|
|
you can change this, visit the [Configuration](/docs/agent/options.html) page)
|
|
|
|
This process can be cumbersome to type each time, so the Consul CLI also
|
|
searches environment variables for default values. Set the following
|
|
environment variables in your shell:
|
|
|
|
```shell
|
|
$ export CONSUL_HTTP_ADDR=https://localhost:9090
|
|
$ export CONSUL_CACERT=consul-ca.pem
|
|
$ export CONSUL_CLIENT_CERT=cli.pem
|
|
$ export CONSUL_CLIENT_KEY=cli-key.pem
|
|
```
|
|
|
|
* `CONSUL_HTTP_ADDR` is the URL of the Consul agent and sets the default for
|
|
`-http-addr`.
|
|
* `CONSUL_CACERT` is the location of your CA certificate and sets the default
|
|
for `-ca-file`.
|
|
* `CONSUL_CLIENT_CERT` is the location of your CLI certificate and sets the
|
|
default for `-client-cert`.
|
|
* `CONSUL_CLIENT_KEY` is the location of your CLI key and sets the default for
|
|
`-client-key`.
|
|
|
|
After these environment variables are correctly configured, the CLI will
|
|
respond as expected.
|
|
|
|
[cfssl]: https://cfssl.org/
|
|
[letsencrypt]: https://letsencrypt.org/
|
|
[vault]: https://www.vaultproject.io/
|
|
[vault-pki]: https://www.vaultproject.io/docs/secrets/pki/index.html
|