1
0
mirror of https://github.com/taigrr/nats.docs synced 2025-01-18 04:03:23 -08:00

Incorporate cert generation, use in examples, mention order of verify_and_map

Signed-off-by: Matthias Hanel <mh@synadia.com>
This commit is contained in:
Matthias Hanel 2020-03-11 16:57:05 -04:00
parent c36e4d018e
commit 787cf70132
2 changed files with 121 additions and 24 deletions

View File

@ -5,15 +5,20 @@ The server can require TLS certificates from a client. When needed, you can use
* Validate the client certificate matches a known or trusted CA * Validate the client certificate matches a known or trusted CA
* Extract information from a trusted certificate to provide authentication * Extract information from a trusted certificate to provide authentication
> Note: To simplify the common scenario of maintainers looking at the monitoring endpoint, `verify` and `verify_and_map` do not apply to the monitoring port.
The examples in the following sections make use of the certificates you [generated](../tls.md#Self-Signed-Certificates-for-Testing) locally.
For simplicity it is assumed that you copied `rootCA.pem` into the same folder where the certificates are generated in and you start `nats-server`.
## Validating a Client Certificate ## Validating a Client Certificate
The server can verify a client certificate using a CA certificate. To require verification, add the option `verify` to the TLS configuration section as follows: The server can verify a client certificate using a CA certificate. To require verification, add the option `verify` to the TLS configuration section as follows:
```text ```text
tls { tls {
cert_file: "./configs/certs/server-cert.pem" cert_file: "server-cert.pem"
key_file: "./configs/certs/server-key.pem" key_file: "server-key.pem"
ca_file: "./configs/certs/ca.pem" ca_file: "rootCA.pem"
verify: true verify: true
} }
``` ```
@ -21,10 +26,12 @@ tls {
Or via the command line: Or via the command line:
```bash ```bash
> ./nats-server --tlsverify --tlscert=./test/configs/certs/server-cert.pem --tlskey=./test/configs/certs/server-key.pem --tlscacert=./test/configs/certs/ca.pem > ./nats-server --tlsverify --tlscert=server-cert.pem --tlskey=server-key.pem --tlscacert=rootCA.pem
``` ```
This option verifies the client's certificate is signed by the CA specified in the `ca_file` option. This option verifies the client's certificate is signed by the CA specified in the `ca_file` option.
When `ca_file` is not present it will default to CAs in the system trust store.
It also makes sure that the client provides a certificate with the extended key usage `TLS Web Client Authentication`.
## Mapping Client Certificates To A User ## Mapping Client Certificates To A User
@ -34,9 +41,9 @@ To have TLS Mutual Authentication map certificate attributes to the user's ident
```text ```text
tls { tls {
cert_file: "./configs/certs/server-cert.pem" cert_file: "server-cert.pem"
key_file: "./configs/certs/server-key.pem" key_file: "server-key.pem"
ca_file: "./configs/certs/ca.pem" ca_file: "rootCA.pem"
# Require a client certificate and map user id from certificate # Require a client certificate and map user id from certificate
verify_and_map: true verify_and_map: true
} }
@ -44,49 +51,52 @@ tls {
> Note that `verify` was changed to `verify_and_map`. > Note that `verify` was changed to `verify_and_map`.
There are two options for certificate attributes that can be mapped to user names. The first is the email address in the Subject Alternative Name \(SAN\) field of the certificate. While generating a certificate with this attribute is outside the scope of this document, you can view one with `openssl`: When present, the server will check if a Subject Alternative Name \(SAN\) maps to a user. It will search all email addresses first, then all DNS names. If no user could be found, it will try the certificate subject.
> Note: This mechanism will pick the user it finds first. There is no configuration to restrict this.
```text ```text
$ openssl x509 -noout -text -in test/configs/certs/client-id-auth-cert.pem $ openssl x509 -noout -text -in client-cert.pem
Certificate: Certificate:
... ...
X509v3 extensions: X509v3 extensions:
X509v3 Subject Alternative Name: X509v3 Subject Alternative Name:
DNS:localhost, IP Address:127.0.0.1, email:derek@nats.io DNS:localhost, IP Address:0:0:0:0:0:0:0:1, email:email@localhost
X509v3 Extended Key Usage: X509v3 Extended Key Usage:
TLS Web Client Authentication TLS Web Client Authentication
... ...
``` ```
The configuration to authorize this user would be as follows: The configuration to authorize this user would be as follow:
```text ```text
authorization { authorization {
users = [ users = [
{user: "derek@nats.io"} {user: "email@localhost"}
] ]
} }
``` ```
> Note: This configuration only works for the first email address if there are multiple emails in the SAN field. Use the [RFC 2253 Distinguished Names](https://tools.ietf.org/html/rfc2253) syntax to specify a user corresponding to the certificate subject:
The second option is to use the RFC 2253 Distinguished Names syntax from the certificate subject as follows:
```text ```text
$ openssl x509 -noout -text -in test/configs/certs/tlsauth/client2.pem $ openssl x509 -noout -text -in client-cert.pem
Certificate: Certificate:
Data: Data:
... ...
Subject: OU=CNCF, CN=example.com Subject: O=mkcert development certificate, OU=testuser@MacBook-Pro.local (Test User)
... ...
``` ```
> Note that for this example to work you will have to modify the user to match what is in your certificates subject.
> In doing so, watch out for the order of attributes!
The configuration to authorize this user would be as follows: The configuration to authorize this user would be as follows:
```text ```text
authorization { authorization {
users = [ users = [
{user: "CN=example.com,OU=CNCF"} {user: "OU=testuser@MacBook-Pro.local (Test User),O=mkcert development certificate"}
] ]
} }
``` ```

View File

@ -4,15 +4,15 @@ The NATS server uses modern TLS semantics to encrypt client, route, and monitori
| Property | Description | | Property | Description |
| :--- | :--- | | :--- | :--- |
| `ca_file` | TLS certificate authority file. |
| `cert_file` | TLS certificate file. | | `cert_file` | TLS certificate file. |
| `key_file` | TLS certificate key file. |
| `ca_file` | TLS certificate authority file. When not present, default to the system trust store. |
| `cipher_suites` | When set, only the specified TLS cipher suites will be allowed. Values must match the golang version used to build the server. | | `cipher_suites` | When set, only the specified TLS cipher suites will be allowed. Values must match the golang version used to build the server. |
| `curve_preferences` | List of TLS cipher curves to use in order. | | `curve_preferences` | List of TLS cipher curves to use in order. |
| `insecure` | Skip certificate verification. | | `insecure` | Skip certificate verification. **NOT Recommended** |
| `key_file` | TLS certificate key file. | | `timeout` | TLS handshake [timeout](#TLS-Timeout) in fractional seconds. Default set to `0.5` seconds. |
| `timeout` | TLS handshake timeout in fractional seconds. Default set to 2 seconds. | | `verify` | If `true`, require and [verify](auth_intro/tls_mutual_auth.md#Validating-a-Client-Certificate) client certificates. To support use by Browser, this option does not apply to monitoring. |
| `verify_and_map` | If `true`, require and verify client certificates and map certificate values for authentication purposes. | | `verify_and_map` | If `true`, require and verify client certificates and [map](auth_intro/tls_mutual_auth.md#Mapping-Client-Certificates-To-A-User) certificate values for authentication purposes. Does not apply to monitoring either. |
| `verify` | If `true`, require and verify client certificates. |
The simplest configuration: The simplest configuration:
@ -59,3 +59,90 @@ tls: {
} }
``` ```
## Self Signed Certificates for Testing
Explaining [Public key infrastructure](https://en.wikipedia.org/wiki/Public_key_infrastructure), [Certificate Authorities (CA)](https://en.wikipedia.org/wiki/Certificate_authority) and [x509](https://tools.ietf.org/html/rfc5280) [certificates](https://en.wikipedia.org/wiki/Public_key_certificate) fall well outside the scope of this document.
So does an explanation on how to obtain a properly trusted certificates.
If anybody outside your organization needs to connect, get certs from a public certificate authority.
Think carefully about revocation and cycling times, as well as automation, when picking a CA.
If arbitrary applications inside your organization need to connect, use a cert from your in-house CA.
If only resources inside a specific environment need to connect, that environment might have its own dedicated automatic CA, eg in Kubernetes clusters, so use that.
**Only** for **testing** purposes does it makes sense to generate self signed certificates, even your own CA.
This is a **short** guide on how to do just that and what to watch out for.
> **DO NOT USE these certificates in production!!!**
### Problems With Self Signed Certificates
#### Missing in Relevant Trust Stores
As they should, these are **not trusted** by the system your server or clients are running on.
One option is to specify the CA in every client you are using.
In case you make use of `verify` and `verify_and_map` you need to specify `ca_file` in the server.
If you are having a more complex setup involving cluster, gateways or leaf nodes, `ca_file` needs to be present in `tls` maps used to connect to the server with self signed certificates.
While this works for server and libraries from the NATS eco system, you will experience issues when connecting with other tools such as your Browser.
Another option is to configure your system's trust store to include self signed certificate(s).
Which trust store needs to be configured depends on what you are testing.
* This may be your OS for server and certain clients.
* The runtime environment for other clients like Java or Python.
* Your browser for monitoring endpoints and websockets.
Please check your system's documentation on how to trust a particular self signed certificate.
#### Missing Subject Alternative Name
Another common problem is failed [identity validation](https://tools.ietf.org/html/rfc6125).
The IP or DNS name to connect to needs to match a [Subject Alternative Name (SAN)](https://tools.ietf.org/html/rfc4985) inside the certificate.
Meaning, if a client/browser/server connect via tls to `127.0.0.1`, the server needs to present a certificate with a SAN containing the IP `127.0.0.1` or the connection will be closed with a handshake error.
### Creating Self Signed Certificates for Testing
The simplest way to generate a CA as well as client and server certificates is [mkcert](https://github.com/FiloSottile/mkcert).
This zero config tool generates and installs the CA into your **local** system trust store(s) and makes providing SAN straight forward.
Here is an example:
Generate a CA and output the location of the root CA cert file `rootCA.pem`.
Next generate a certificate, valid for use by `localhost` and the IP `::1`(`-cert-file` and `-key-file` overwrite default file names).
Then start a nats server using the generated certificate.
```bash
mkcert -install
mkcert -CAROOT
mkcert -cert-file server-cert.pem -key-file server-key.pem localhost ::1
nats-server --tls --tlscert=server-cert.pem --tlskey=server-key.pem -ms 8222
```
Now you should be able to access the monitoring endpoint `https://localhost:8222` with your browser.
`https://127.0.0.1:8222` however should result in an error as `127.0.0.1` is not listed as SAN.
You will not be able to establish a connection from another computer either.
For that to work you have to provide appropriate DNS and/or IP [SAN(s)](#Missing-Subject-Alternative-Name)
To generate certificates that work with `verify` provide the `-client` option.
This will cause it to add an appropriate key usage for client authentication.
Please note that client refers to connecting process, not necessarily a NATS client.
Also add a SAN email for usage as user name in `verify_and_map`.
```bash
mkcert -client -cert-file client-cert.pem -key-file client-key.pem localhost ::1 email@localhost
```
Once you are done testing, remove the CA from your **local** system trust store(s).
```
mkcert -uninstall
```
Alternatively, you can also use [openssl](https://www.openssl.org/) to [generate certificates](https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs).
This tool allows a lot more customization of the generated certificates.
It is a lot **more complex** and does **not manage** installation into the system trust store(s).
However, for inspecting certificates it is quite handy. To inspect the certificates from the above example execute these commands:
```bash
openssl x509 -noout -text -in server-cert.pem
openssl x509 -noout -text -in client-cert.pem
```