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 on /n2n) are secured using mutual TLS (both client and server present a X.509 certificate). This must be a certificate issued by a Certificate Authority which is trusted by the other nodes in the network.

  • Connections from the “outside world” (HTTP on /public), e.g. mobile devices, are secured using TLS with only a server certificate. This must be a publicly trusted certificate, e.g. issued by Let’s Encrypt.

Note

The Nuts node currently does not support configuring multiple TLS certificates, meaning you MUST offload TLS using a reverse proxy (with 2 different certificates) if your users authenticate on the Nuts node (e.g. IRMA/Yivi/EmployeeID). This is true for almost all use cases of the Nuts node.

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.

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

TLS Offloading

In most 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                     on;
      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 / {
        # During synchronization of a new Nuts node it is possible that the gRPC stream contains messages larger than NGINX is willing to accept.
        # The following config disables buffering and increases the max. message a client can send to some sanely large number.
        # If not configured, NGINX will drop the connection when syncing lots of transactions at once.
        proxy_buffering off;
        client_max_body_size 128m;

        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
      }
    }
}

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.

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: server
    n2n:
      address: :8443
      tls: server-client

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.

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.