TraefikEE: Tcp Router Ipwhitelist Middleware

Service delivery consists of more than just HTTP reverse proxies and SSL termination. This post will explore exposing a TCP service within a cluster as well as limiting access to said service. It’s written specifically for TraefikEE users but easily adapted to CE.

We’ll be working with the following components:

  • Proxy stacks
  • Static configuration
  • Dynamic configuration
  • Docker stacks

Proxy Stacks

If you want your service to access the source IP of incoming connections you’ll need to enable host networking. You can skip this step if you don’t have the source IP requirement. Open up your proxies.yaml file and configure the ports section as shown below, the service we’re adding will use port 1234. You will have to allow port 1234 to any network filters/firewalls.

For more details on host networking see this post by Sebastián Ramírez.

services:
  proxies:
    image: traefik/traefikee:v2.6.0
    deploy:
    ...
    networks:
    ...
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
      - target: 1234
        published: 1234
        protocol: tcp
        mode: host

If you’ve switched to host networking you’ll have to redeploy the proxy service via docker stack deploy -c proxies.yaml traefikee.

Static Configuration

Next up we’ll add the pertinent details to our static configuration. Specifically, the entrypoint.

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
  # Example tcp service running on port 1234
  tcp_1234:
    address: ":1234/tcp"

Dynamic Configuration

Our dynamic configuration is used to define the ipwhitelist middleware that our tcp service will use. This is a list of IPs/networks you wish to allow.

tcp:
  middlewares:
    internal-restricted:
      ipwhitelist:
        sourcerange:
          - "123.123.123.123"
          - "234.234.234.234"
          - "128.128.128.128"
          - "128.199.15.184"
          - "165.227.41.247"

Apply our static and dynamic configuration files

teectl apply --file="static.yaml"
teectl apply --file="dynamicweb.yaml"

Docker Stacks

The remaining step is to add the Traefik labels to our docker stack. In this example, the tcp service running inside the container is also using port 1234. If that differs then you can change the loadbalancer port on the last line.

  tcpservice:
    image: yourimage:3

    networks:
      - traefikee_ingress
      - dev_env

    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.docker.network=traefikee_ingress"
        - "traefik.tcp.routers.tcp_1234.entrypoints=tcp_1234"
        - "traefik.tcp.routers.tcp_1234.service=tcp_1234"
        - "traefik.tcp.routers.tcp_1234.tls=false"
        - "traefik.tcp.routers.tcp_1234.tls.passthrough=true"
        - "traefik.tcp.routers.tcp_1234.rule=HostSNI(`*`)"
        - "traefik.tcp.routers.tcp_1234.middlewares=internal-restricted@traefikee"
        - "traefik.tcp.services.tcp_1234.loadbalancer.server.port=1234"

Save your changes and redeploy the stack. The Traefik dashboard should now display the tcp router and your service should be accessible from the addresses listed in the ipwhitelist.


Illustration of Vince

Vince Hillier is the President and Founder of Revenni Inc. He is an opensource advocate specializing in system engineering and infrastructure. Outside of building solid infrastructure that doesn't break the bank, he's interested in information security, privacy, and performance.