In case `verify_server_hostname` is set in the configuration, Consul checks the certificate against `server.<datacenter>.<domain>`. The name suggested by the guide generates errors like the following: ``` 2018/10/10 12:42:20 [ERR] consul: Failed to confirm peer status for consul-3: rpc error getting client: failed to get conn: x509: certificate is valid for server.node.consul.labs, localhost, not server.consul.labs. Retrying in 16s... ``` Removing the `node` part from the certificate permits them to work also when that option is set.
7.2 KiB
layout | page_title | sidebar_current | description |
---|---|---|---|
docs | Creating Certificates | docs-guides-creating-certificates | 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 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 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
Estimated Time to Complete
20 minutes
Prerequisites
This guide assumes you have 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, but for the sake of simplicity this guide will use cfssl. You can generate a private CA certificate and key with cfssl:
# Generate a default CSR
$ cfssl print-defaults csr > ca-csr.json
Change the key
field to use RSA with a size of 2048
{
"CN": "example.net",
"hosts": [
"example.net",
"www.example.net"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"ST": "CA",
"L": "San Francisco"
}
]
}
# 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.global.consul
for a client node in theglobal
regionserver.us-west.consul
for a server node in theus-west
region
To create certificates for the client and server in the cluster with
cfssl, create the following configuration file as cfssl.json
to increase the default certificate expiration time:
{
"signing": {
"default": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
# 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.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.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 theglobal
region.client-key.pem
- Consul client node private key for theglobal
region.client.pem
- Consul client node public certificate for theglobal
region.server.csr
- Consul server node certificate signing request for theglobal
region.server-key.pem
- Consul server node private key for theglobal
region.server.pem
- Consul server node public certificate for theglobal
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:
$ 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 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:
$ 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.