TLS Configuration

The Nuts nodes uses 2 kinds of connections: HTTP and gRPC. gRPC connections and some HTTP endpoints require TLS to be set up, either for being able to connect to other nodes and/or secure access to the local Nuts node. You can review these requirements in the Interfaces/Endpoints section of the deployment documentation.

Generally speaking:

  • Connections between Nuts nodes (gRPC and HTTP) are secured using mutual TLS (both client and server present a X.509 certificate).

  • Connections from the “outside world” (HTTP), e.g. mobile devices, are secured using TLS with only a server certificate.

Your TLS configuration depends mostly on where you terminate the TLS connection. This page describes the different layouts for TLS and how to configure them.

In all layouts your node’s certificate must be issued by a Certificate Authority which is trusted by the other nodes in the network. Any case using TLS requires tls.certfile, tls.certkeyfile and tls.truststorefile to be configured.

Note

You can find working setups in the end-2-end test suite.

End-to-end TLS (no offloading)

Having no TLS offloading means the secure connection starts at the remote system and ends at the Nuts node. No systems in between can alter or inspect the TLS connection.

gRPC / HTTP2 over TLS %3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Behind%20reverse%20proxy%26lt%3Bbr%26gt%3BSSL%20terminator%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dleft%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D20%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22250%22%20y%3D%2240%22%20width%3D%22350%22%20height%3D%2220%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E 
gRPC / HTTP2 over TLS %3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Behind%20reverse%20proxy%26lt%3Bbr%26gt%3BSSL%20terminator%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dleft%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D20%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22250%22%20y%3D%2240%22%20width%3D%22350%22%20height%3D%2220%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E 
Nuts Node
Nuts Node
Public
Internet
Public...


Server Certificate
[ Private Key ]
Server Certificat...
Uses
Uses
Viewer does not support full SVG 1.1

For this setup you need to configure TLS and set up the HTTP interfaces so the endpoints are properly secured. The example below shows how to:

  • configure TLS for HTTP and gRPC connections,

  • enable TLS (with required client certificate) for node-to-node (/n2n) HTTPS connections on port 8443,

  • enable TLS (server certificate only) for /public HTTPS connections on port 443.

Your Nuts node configuration could look like this:

tls:
  certfile: my-certificate.pem
  certkeyfile: my-certificate.pem
  truststorefile: truststore.pem
http:
  default:
    address: :1323
  alt:
    public:
      address: :443
      tls: tls
    n2n:
      address: :8443
      tls: mutual-tls

Note

In the example above /internal endpoints bind to the default HTTP interface, which does not apply any access control. To secure your node you must restrict access this endpoint, e.g. by not exposing it to the outside world. It’s generally preferable to use an external load balancer (see “TLS Pass-through”) or firewall to decrease the risk of misconfiguration of the node. You can bind /internal to its own HTTP interface to further decrease the risk.

TLS Pass-through

When using a (level 4) load balancer that does not inspect or alter requests, TLS is still terminated on the Nuts node.

gRPC / HTTP2 over TLS%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Behind%20reverse%20proxy%26lt%3Bbr%26gt%3BSSL%20terminator%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dleft%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D20%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22250%22%20y%3D%2240%22%20width%3D%22350%22%20height%3D%2220%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
gRPC / HTTP2 over TLS%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Behind%20reverse%20proxy%26lt%3Bbr%26gt%3BSSL%20terminator%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Balign%3Dleft%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D20%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22250%22%20y%3D%2240%22%20width%3D%22350%22%20height%3D%2220%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
Nuts Node
Nuts Node
Public
Internet
Public...
gRPC / HTTP2 over TLS
gRPC / HTTP2 over TLS
Load Balancer
Load Balancer
Uses
Uses


Server Certificate
[ Private Key ]
Server Certificat...
Viewer does not support full SVG 1.1

This setup does not need additional configuration.

Configuration for HAProxy could look like this (given the TLS configuration in the previous section):

listen grpc
    bind *:5555
    mode tcp
    server node1 nodeA-backend:5555 check

listen public
    bind *:443
    mode tcp
    server node1 nodeA-backend:443 check

listen n2n
    bind *:8443
    mode tcp
    server node1 nodeA-backend:8443 check

Refer to the HAProxy documentation for more information.

Note

In a (level 4) pass-through configuration, the Nuts node will see the load balancer as origin (IP) for all incoming connections.

TLS Offloading

In many setups TLS is terminated on a reverse proxy in front of the backend services over plain HTTP or HTTP/2 (for gRPC connections).

gRPC / HTTP2 over TLS
gRPC / HTTP2 over TLS
Authenticates
server certs. using
Authenticates...
Nuts Node
Nuts Node
Public
Internet
Public...
Plain gRPC / HTTP2
Plain gRPC / HTTP2
TLS offloader
[ HAProxy / Nginx ]
TLS offloader...
Uses
(inbound connections)
Uses...


Server Certificate
[ Private Key ]
Server Certificate...
Authenticates
client certs. using
Authenticates...


Truststore
[ X.509 certificate bundle ]
Truststore...
Uses
(outbound connections)
Uses...
Viewer does not support full SVG 1.1

To configure this setup your proxy needs to support HTTP/2 for gRPC traffic. For gRPC traffic your proxy must add the TLS client certificate as request header. The certificate can either be in PEM (Apache HTTPD/NGINX) or DER (HAProxy) format and URL encoded.

In addition to the general TLS configuration, you need to configure the following options:

  • tls.offload needs to be set to incoming

  • tls.certheader needs to be set to the name of the header in which your proxy sets the certificate (e.g. X-SSl-CERT). The certificate must be in PEM or base64 encoded DER format.

  • Disable/remove TLS configuration for HTTP interfaces.

  • Bind the /n2n and /public endpoints to specific different HTTP interfaces to avoid accidentally exposing internal HTTP endpoints.

Your Nuts node configuration could look like this:

tls:
  certfile: my-certificate.pem
  certkeyfile: my-certificate.pem
  truststorefile: truststore.pem
  offload: incoming
  certheader: X-SSL-CERT
http:
  default:
    address: :1323
  alt:
    public:
      address: :80
    n2n:
      address: :8080

The certificate and truststore will still need to be available to the Nuts node for making outbound connections.

For NGINX the proxy configuration could look as follows:

http {
    server {
      server_name nuts-grpc;
      listen                    5555 ssl http2;
      ssl_certificate           /etc/nginx/ssl/server.pem;
      ssl_certificate_key       /etc/nginx/ssl/key.pem;
      ssl_client_certificate    /etc/nginx/ssl/truststore.pem;
      ssl_verify_client         on;
      ssl_verify_depth          1;

      location / {
        grpc_pass grpc://nuts-node:5555;
        grpc_set_header X-SSL-CERT $ssl_client_escaped_cert;        # add peer's SSL cert
        grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # for correct IP logging
      }
    }


    server {
      server_name nuts-n2n;
      listen                    443 ssl;
      ssl_certificate           /etc/nginx/ssl/server.pem;
      ssl_certificate_key       /etc/nginx/ssl/key.pem;
      ssl_client_certificate    /etc/nginx/ssl/truststore.pem;
      ssl_verify_client         on;
      ssl_verify_depth          1;

      location /n2n {
        proxy_pass http://nuts-node:8080;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # for correct IP logging
      }
    }

    server {
      server_name nuts-public;
      listen                    443 ssl;
      ssl_certificate           /etc/nginx/ssl/server.pem;
      ssl_certificate_key       /etc/nginx/ssl/key.pem;

      location /public {
        proxy_pass http://nuts-node:80;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # for correct IP logging
      }
    }
}

Note

During synchronization of a new Nuts node it is possible that the gRPC stream contains messages larger than NGINX is willing to accept. To limit these issues add proxy_buffering off to the gRPC config section, and increase the buffer size to some sanely large number e.g., client_max_body_size 128m.

For HAProxy the proxy configuration could look as follows:

frontend grpc_service
    mode http
    bind :5555 proto h2 ssl crt /certificate.pem ca-file /truststore.pem verify required
    default_backend grpc_servers

backend grpc_servers
    mode http
    option forwardfor  # for correct IP logging
    http-request set-header X-SSL-CERT %{+Q}[ssl_c_der,base64]
    server node1 nuts_node:5555 check proto h2

Revoked Certificates

Proxies should always check whether the presented client certificate is revoked, e.g. in case its private was leaked. Many proxies don’t automatically check certification revocation status unless explicitly configured. For HAProxy and NGINX you need to download/update the CRLs yourself and configure the proxy to use it (generally achieved using a scheduled script). This is not included in the examples above.

No TLS

You can disable TLS by setting network.enabletls to false, but this feature is only meant for development/demo purposes. It should never be used in a production environment. If you disable TLS, you can only connect to nodes that have disabled TLS as well.