TCP routing to Database

Hello,

I'm doing some test with TCP routing with traefik 2. I'va wrote a basic test with MSSql and Postgres database

traefik.yml

################################################################
### Commons configuration ######################################
################################################################
global:
  checkNewVersion: true
  sendAnonymousUsage: true

entryPoints:
  web:
    address: :80
  web-secure:
    address: :443
  internal:
    address: :8181
  postgres:
    address: :5432
  mssql:
    address: :1433

http:
  middlewares:
    http-compress:
      compress: {}
    redirect:
      redirectScheme:
        scheme: https

tls:
  certificates:
    - certFile: /run/secrets/atheneo_cloud_cer
      keyFile: /run/secrets/atheneo_cloud_key

################################################################
### Docker Swarm configuration #################################
################################################################
providers:
  docker:
    watch: true
    swarmMode: true
  file:
    watch: true
    filename: /etc/traefik/traefik.yml

################################################################
### API and dashboard configuration ############################
################################################################
api:
  insecure: true
  dashboard: true

log:
  level: DEBUG

docker-compose.yml

version: '3.4'

networks:
  traefik-net:

configs:
  traefik.yml:
    file: traefik.yml

secrets:
  toto_cer:
    file: toto.cer
  toto_key:
    file: toto.key

services:
  traefik:
    image: traefik:v2.0
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
      - target: 8181
        published: 8080
        protocol: tcp
        mode: host
      - target: 1433
        published: 1433
        protocol: tcp
        mode: host
      - target: 5432
        published: 5432
        protocol: tcp
        mode: host
    networks:
      - traefik-net
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      labels:
        - traefik.http.services.traefik.loadbalancer.server.port=8080
        - traefik.http.routers.traefik.rule=Host(`traefik.toto`)
        - traefik.http.routers.traefik.entrypoints=web
        - traefik.http.routers.traefik.middlewares=redirect@file
        - traefik.http.routers.traefik-secured.rule=Host(`traefik.toto`)
        - traefik.http.routers.traefik-secured.entrypoints=web-secure
        - traefik.http.routers.traefik-secured.tls=true
    configs:
      - source: traefik.yml
        target: /etc/traefik/traefik.yml
    secrets:
      - toto_cer
      - toto_key

  mssql:
    image: mcr.microsoft.com/mssql/server:2017-latest-ubuntu
    networks:
      - traefik-net
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_SA_PASSWORD: "MismO2019*"
    deploy:
      labels:
        - traefik.tcp.services.mssql.loadbalancer.server.port=1433
        - traefik.tcp.routers.mssql.entrypoints=mssql
        - traefik.tcp.routers.mssql.rule=HostSNI(`*`)
        - traefik.tcp.routers.mssql.tls=true
        - traefik.tcp.routers.mssql.service=mssql

  postgres:
    image: postgres
    networks:
      - traefik-net
    environment:
      POSTGRES_PASSWORD: example
    deploy:
      labels:
        - traefik.tcp.services.postgres.loadbalancer.server.port=5432
        - traefik.tcp.routers.postgres.entrypoints=postgres
        - traefik.tcp.routers.postgres.rule=HostSNI(`*`)
        - traefik.tcp.routers.postgres.tls=true
        - traefik.tcp.routers.postgres.service=postgres

Everything start without error, but i can't connect to both databaase.

For Postgres from Adminer: Timeout
For MSSQL from MSSQL Studio : Timeout

I see something weird into Traefik Dashbord, server status is flagged as waring (i think)

Did you have any idea ?

Thx

Hi @gprime44, thanks for your interest!

Does the databases work if you disable TLS on their TCP routers?

E.g. removing the 2 following lines:

        - traefik.tcp.routers.mssql.tls=true
(...)
        - traefik.tcp.routers.postgres.tls=true

The reasoning behind is the following: enabling TLS termination (or even TLS passthrough) on Traefik TCP routers require the application protocol served to support "SNI" (Server Name Indication) during a standard TLS handshake.

Alas some protocols as Postgres or MySQL does not support it (ref. https://www.postgresql.org/message-id/d05341b9-033f-d5fe-966e-889f5f9218e5@proxel.se for Postgres).

In these cases, don't worry: disabling TLS on Traefik is not disabling encryption at all. Database client (mysql or pgqsl) will encrypt their packets on their own, and Traefik will pass the packet as normal TCP packets, without trying to decrypt its. Then packets are routed to the database server who takes care of decryption.

Hi,

Thx for your answer.

Without TLS both works. But I need to open a specific port by database :frowning:

I will try with MSSQL 2019 to see if SNI is supported.

Thanks again.

Hi @gprime44, thanks for the feedback.

You're right, it is mandatory to open one port (e.g. defining 1 entrypoint) per database. This is a "TCP proxy" limitation also present in HAProxy or Nginx alas, as there is no technical solution.

Happy to learn if MSSQL 2019 works if SNI (or not) :slight_smile: