Traefik forward-auth middleware that adds Host-header-based ACL for mTLS protected services
Find a file
2026-07-08 23:08:44 +02:00
acl.json init 2026-07-08 23:08:44 +02:00
go.mod init 2026-07-08 23:08:44 +02:00
LICENSE.md init 2026-07-08 23:08:44 +02:00
main.go init 2026-07-08 23:08:44 +02:00
README.md init 2026-07-08 23:08:44 +02:00

authz

This is a pretty hacky approach to add a okay-ish-grained ACL to traefik mTLS via a forwardauth middleware.

Deployment

execute the binary with the acl.json file in the working directory. currently it automatically listens to all interfaces on 8080.

Configuration

ACL

Basically, define a list of hosts that can be accessed with a role, then define what certificate has what role. the certificate is determined by it's Common Name (be careful tho, there currently is a hardcoded manipulation of the CN to fit my setup). The onyl exception is superadmin, which is a hardcoded role that always grants access.

{
  "roles": {
    "infra": [
      "traefik.example.com"
    ],
    "media": [
      "jellyfin.seed.example.com",
      "jellyseerr.seed.example.com"
    ],
    "media-infra": [
      "sonarr.seed.example.com",
      "radarr.seed.example.com",
      "prowlarr.seed.example.com",
      "bazarr.seed.example.com"
    ],
    "secret": [
      "secret.example.com"
    ]
  },
  "certificates": {
    "Max-MacBook": ["superadmin"],
    "Max-iPhone": ["media", "notes"],
    "Max-Linux-Workstation": ["media", "media-infra", "notes"]
  }
}

Everything else

you configure the software by editing the source code. Especially when it comes to validating your cert, I dont care about anyone but me and my specific usecase.

traefik config

you need some sort of root CA setup beforehand. I have one set up with an intermediary CA for the specific use case.

# this configures traefik to use your custom certificates/CA for https and mTLS.
tls:
  certificates: # these are signed by the same intermediate CA as the mTLS certs
    - certFile: /etc/traefik/certs/traefik.crt
      keyFile: /etc/traefik/certs/traefik.key

  options:
    mtls:
      minVersion: VersionTLS12
      clientAuth:
        caFiles:
          - /etc/traefik/certs/ca-chain.crt # This is the chain of rootCA -> Intermediate CA used to validate the certificates in the first step.
        clientAuthType: RequireAndVerifyClientCert

http:
  middlewares:
    client-cert-authz: # this is the actual auth part
      forwardAuth:
        address: "http://host.containers.internal:8080/fw/verify" # change
        trustForwardHeader: true # yes this is correct. HOWEVER this is insecure THE SECOND you don't have client-cert-info in the middleware chain BEFORE client-cert-authz
    client-cert-info: # this ensures that the right values of the cert are passed down
      passTLSClientCert:
        info:
          subject:
            commonName: true
            organization: true
            organizationalUnit: true
            routers:
    dashboard: # and this is how you use it
      rule: "Host(`traefik.home.lan`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
      service: api@internal
      entryPoints: [websecure]
      tls:
        options: mtls@file # this enables mTLS. If you just want plain https via the CA, only put "tls: {}".
      middlewares: # MAKE SURE THEY ARE IN ORDER
        - client-cert-info
        - client-cert-authz

License

AGPL v3