HTTPS Proxy with mutualTLS

Hi,

I am trying to proxy a HTTP request to a HTTPS backend that requires mutualTLS (defined within the file provider).

However my client certificate is never presented:
{"status":496,"message":"Client certificate not presented"}

This is what I am trying to achieve:

                                                                            +---------------+
                                                                            | API Server A  |
                                                              HTTPS         |---------------|
                                                              Mutual TLS    | serverA.crt   |
                                                         +----------------->| serverA.key   |
                                                         |                  |               |
                                                         |                  |               |
                                                         |                  +---------------+
                                                         |
      +----------+               +----------------------+|tlsA.crt
      |Client    |               |  Traefik             ++tlsA.key
      |----------|    HTTP       |----------------------|
      |          |+------------> |                      |
      |          |               |                      |
      |          |               |                      ++
      +----------+               +----------------------+|tlsB.crt
                                                         |tlsB.key          +---------------+
                                                         |                  | API Server B  |
                                                         |                  |---------------|
                                                         |     Mutual TLS   | serverB.crt   |
                                                         +----------------->| serverB.key   |
                                                                HTTPS       |               |
                                                                            |               |
                                                                            +---------------+

I have managed to do this successfully via nginx with a simple proxy_pass configuration:

server {
  listen 80;
  ssl_protocols TLSv1.2;

  location / {
    proxy_ssl_certificate           /etc/nginx/certs/client.crt;
    proxy_ssl_certificate_key       /etc/nginx/certs/client.key;
    proxy_ssl_trusted_certificate   /etc/nginx/certs/ca.crt;
    proxy_ssl_verify on;
    proxy_ssl_verify_depth  2;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
    proxy_pass https://my-secure-backend.domain.com:8443;
  }
}

Here is my file provider:

[[tls.certificates]]
   certFile = "/certs/client.crt"
   keyFile = "/certs/client.key"

[http]
  # Add the router
  [http.routers]
    [http.routers.proxy]
      entryPoints = ["http", "https"]
      service = "proxy"
      rule = "Host(`my-secure-backend-proxy`)"
  # Add the service
  [http.services]
    [http.services.proxy]
      [http.services.proxy.loadBalancer]
        passHostHeader = false
        [[http.services.proxy.loadBalancer.servers]]
          url = "https://my-secure-backend.domain.com:8443/"
          scheme = "https"

Am I missing something or is this use case not possible with Traefik 2.2?

Thanks in advance.

2 Likes

following...

There really needs to be a library of nginx -> traefik config maps, would make adoption much much easier

I totally understand what you want to do, since I've used client certficates with nginx to connect to the backend(or upstream) using a similar nginx configuration as you posted.

I went looking for similar capabilities in the traefik documentation and perhaps I'm totally missing something but I can't find it.

I'm aware client certificates could be used in the following scenarios

  1. Between client and traefik
    (browser)------>Traefik
  2. Between Traefik and backend service
    Traefik---->Backend service

I'm referencing this page within the documentation: https://doc.traefik.io/traefik/https/tls/
From what you posted with:

[[tls.certificates]]
   certFile = "/certs/client.crt"
   keyFile = "/certs/client.key"

I believe this actually refers to the domain certificates that traefik presents to the client (ie Scenario One)

According to documentation it looks like you could try:

[tls.stores]
  [tls.stores.default]
    [tls.stores.default.defaultCertificate]
      certFile = "path/to/cert.crt"
      keyFile  = "path/to/cert.key"

Now assuming you were connecting to the backend and you wanted to verify the domain certs presented by the backend, I think you use add this capability within the static config file (like traefik.yml or traefik.toml): I posted this below however it should help you. It's in yaml format but I found this in the documentation here:

serversTransport:
insecureSkipVerify: false
rootCAs:
- /etc/ssl/certs/ca-certificates.crt

My understanding as of right now Traefik 2.3 can't do a domain certificate verification on a site by site basis (hence why this is in the static configuration file). With 2.4 (currently RC) I believe they will add domain certificate verification on a more dynamic level so you can verify certain backends and not others (so hence it will be in the dynamic configuration file).

Does this help at all? I admit I'm a little confused.
I have npt used client certificates for the backend with traefik. I have passed proxy passed https to the backend and used the serversTransport section. The backend servers were presenting Let's Encrypt certificates (sometimes easier for me to just use LE server certificates than self-signed for this purpose) and I verified the LE certs through the ca-certificates.crt file which I think is pretty much present in one form or another on any linux distribution which contains a massive concatenated list of many valid and recognized CAs as through the mozilla project.

***Yea I just re-read what I wrote and did a lot more searching.
I don't think traefik can use client certs (traefik being the client) and the backend service being the server. I've seen other questions regarding this situation and it seemed the answer was use TLS passthrough. This feature was on the request list but I dont know if it will make it into 2.4

Hi,

Thank, thank you for taking the time to reply...much appreciated.

So I am trying to use it as per scenario 2 of your response:

Client makes HTTP call to traefik.
Traefik makes HTTPS call to backend that requires a client certificate.

I have tried both of the above configurations with respect to the dynamic tls options and tls.certificates blocks in file config both to no avail - traefik just will not send the client certificate after the server requests it.

You are correct re server certificate verification, that works with the cli flag:

  • --serversTransport.rootCAs=/certs/ca.crt

Its a shame but I don't think traefik can act as the client with regards to mutualTLS with server side client certificate requests.

PassThroughTLS is not good for us in this scenario as the service making the call is legacy and we do not wish to redevelop it to handle the TLS from the application side.

Thanks anyway for your help, we may just have to keep nginx in the mix in order to achieve this currently until Traefik can handle "being the client" :slight_smile:

Ta

Jon