How to Use TLSGuard Middleware for Traefik

TLSGuard is a authentication plugin for Traefik that combines certificate-based authentication with IP whitelisting and rule-based access control. Here’s a detailed guide on how to set it up and use it effectively.

Complete Setup Guide

Step 1: Enable the Plugin in Traefik

First, you need to enable the TLSGuard plugin in your Traefik configuration:

For Traefik Hub/Pilot:

# traefik.yml (static configuration)
experimental:
  plugins:
    tlsguard:
      moduleName: github.com/hhftechnology/tlsguard
      version: v1.0.0

For local development:

# traefik.yml (static configuration)
experimental:
  localPlugins:
    tlsguard:
      moduleName: github.com/hhftechnology/tlsguard

Step 2: Set Up Your Certificate Authority

  1. Create a Certificate Authority (CA) if you don’t have one:

    openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 365 -nodes -subj "/CN=My Custom CA"
    
  2. Create client certificates for your users:

    # Create private key
    openssl genrsa -out client.key 4096
    
    # Create CSR (Certificate Signing Request)
    openssl req -new -key client.key -out client.csr -subj "/CN=alice"
    
    # Sign the certificate with your CA
    openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
    
    # Create combined PEM file for the client
    cat client.crt client.key > client.pem
    
  3. Export the certificate’s serial number for later use:

    openssl x509 -in client.crt -noout -serial
    # Output example: serial=1234567890ABCDEF1234567890ABCDEF12345678
    

Step 3: Configure TLS Options for Client Authentication

In your Traefik dynamic configuration, set up TLS options to require client certificates:

# dynamic.yaml
tls:
  options:
    clientauth:
      clientAuth:
        caFiles:
          - /path/to/ca.crt
        clientAuthType: VerifyClientCertIfGiven  # Or RequireAndVerifyClientCert for stricter security

Step 4: Configure the TLSGuard Middleware

There are two ways to set up the middleware: allowing by certificate serial number or by certificate identity.

Option A: Allow by Certificate Serial Number

To allow a specific certificate by its serial number, use the header rule type to check the X-TLSGuard-Cert-SN header:

# dynamic.yaml
http:
  middlewares:
    tlsguard:
      plugin:
        tlsguard:
          requestHeaders:
            X-Client-CN: "[[.Cert.Subject.CommonName]]"
          rules:
            - type: header
              headers:
                X-TLSGuard-Cert-SN: "1234567890ABCDEF1234567890ABCDEF12345678"  # The serial number from step 2

Option B: Allow by Certificate Identity (Common Name, DNS Names, or Email)

This is the more typical approach using the users configuration:

# dynamic.yaml
http:
  middlewares:
    tlsguard:
      plugin:
        tlsguard:
          usernameHeader: "User"
          users:
            alice: alice         # Common Name "alice" maps to username "alice"
            bob1: bob            # Common Name "bob1" maps to username "bob"
            charlie@example.org: charlie  # Email address maps to username "charlie"

Step 5: Apply the Middleware to Your Router

# dynamic.yaml
http:
  routers:
    secure:
      rule: "Host(`secure.example.com`)"
      service: my-service
      tls:
        options: clientauth  # Reference your TLS options from Step 3
      middlewares:
        - tlsguard  # Apply the TLSGuard middleware

Step 6: Verify Your Setup

Test access with a valid client certificate:

curl --cert client.pem --insecure https://secure.example.com

JSON Configuration for Serial Number Validation if needed

Configuring TLSGuard to allow only certificates with specific serial numbers, here’s the complete JSON configuration:

{
  "http": {
    "middlewares": {
      "tlsguard": {
        "plugin": {
          "tlsguard": {
            "requestHeaders": {
              "X-Client-CN": "[[.Cert.Subject.CommonName]]"
            },
            "rules": [
              {
                "type": "header",
                "headers": {
                  "X-TLSGuard-Cert-SN": "1234567890ABCDEF1234567890ABCDEF12345678"
                }
              }
            ]
          }
        }
      }
    },
    "routers": {
      "secure": {
        "rule": "Host(`secure.example.com`)",
        "service": "my-service",
        "tls": {
          "options": "clientauth"
        },
        "middlewares": [
          "tlsguard"
        ]
      }
    }
  },
  "tls": {
    "options": {
      "clientauth": {
        "clientAuth": {
          "caFiles": [
            "/path/to/ca.crt"
          ],
          "clientAuthType": "RequireAndVerifyClientCert"
        }
      }
    }
  }
}

Troubleshooting

If your configuration is recognized but you’re still being denied access:

  1. Check TLS Options: Ensure your TLS options are properly configured with the correct CA file.

  2. Verify Certificate Identity: If using the users configuration, check that the certificate’s Common Name, DNS Names, or Email Addresses match exactly what’s in your configuration.

  3. Check Serial Number: If restricting by serial number, verify the exact format of the serial number in the X-TLSGuard-Cert-SN header (you can debug this by adding the header to a test endpoint).

  4. Enable Debug Logging: Add the following to your Traefik static configuration to see detailed logs:

    log:
      level: DEBUG
    
  5. Check Middleware Order: Ensure that TLSGuard is applied before other authentication middlewares.

Key Differences from Standard Traefik TLS Options

The standard Traefik TLS configuration only verifies that the client certificate is signed by a trusted CA. TLSGuard adds:

  1. User Identity Mapping: Maps certificate identities to usernames
  2. Fine-grained Access Control: Controls access by specific certificate serial numbers
  3. Fallback to IP-based Rules: Allows configuring alternative authentication methods
  4. Custom Headers: Adds certificate information as request headers

For simple CA-based authentication, the standard Traefik TLS options are sufficient. Use TLSGuard when you need more advanced features like username mapping, fallback authentication, or certificate serial number verification.

How to use with middleware manager with template.yaml

TLSGuard Configuration Examples

Here are several practical examples using our template structure for different authentication scenarios:

Example 1: Basic Certificate Authentication

This configuration allows access only to users with valid certificates that match the identifiers in the users map:

- id: "tlsguard"
  name: "Certificate Authentication Only"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      users:
        john.doe: john
        jane.smith: jane
        admin@company.com: administrator
      
      requestHeaders:
        X-Cert-Mail: "[[.Cert.Subject.CommonName]]@company.com"
        X-User-Department: "[[.Cert.Subject.OrganizationalUnit]]"
        X-Certificate-Issuer: "[[.Cert.Issuer.CommonName]]"

Example 2: Certificate Serial Number Validation

This configuration allows access only to certificates with specific serial numbers:

- id: "tlsguard"
  name: "Certificate Serial Number Validation"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      requestHeaders:
        X-Cert-Serial: "[[.Cert.SerialNumber.String]]"
      
      rules:
        - type: "anyOf"
          rules:
            - type: "header"
              headers:
                X-TLSGuard-Cert-SN: "1A2B3C4D5E6F7890"  # Serial number of trusted certificate 1
            - type: "header"
              headers:
                X-TLSGuard-Cert-SN: "F9E8D7C6B5A43210"  # Serial number of trusted certificate 2

Example 3: Certificate Authentication with Fallback to IP Whitelist

This configuration first tries to authenticate via certificate, but allows access to specific IP ranges if no valid certificate is provided:

- id: "tlsguard"
  name: "Certificate Auth with IP Fallback"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      users:
        john.doe: john
        jane.smith: jane
        admin@company.com: administrator
      
      requestHeaders:
        X-Cert-Mail: "[[.Cert.Subject.CommonName]]@company.com"
      
      rules:
        - type: "ipRange"
          ranges:
            - "10.0.0.0/8"       # Internal network
            - "192.168.0.0/16"   # VPN network
            - "172.16.0.0/12"    # Development network
          addInterface: true

Example 4: Complex Access Rules with Logical Operators

This example shows how to create sophisticated access rules combining IP ranges, certificate checks, and header validation:

- id: "tlsguard"
  name: "Complex Rules Example"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      users:
        john.doe: john
        jane.smith: jane
      
      rules:
        - type: "anyOf"
          rules:
            # Access path 1: Valid certificate for specific users
            - type: "header"
              headers:
                User: "(john|jane)"  # Regex pattern to match either john or jane
            
            # Access path 2: Special header AND from trusted network
            - type: "allOf"
              rules:
                - type: "header"
                  headers:
                    X-Special-Access-Token: "s3cr3t-t0k3n-v4lu3"
                - type: "ipRange"
                  ranges:
                    - "10.50.0.0/16"  # Trusted network segment
            
            # Access path 3: From monitoring system but NOT from testing subnet
            - type: "allOf"
              rules:
                - type: "header"
                  headers:
                    User-Agent: "MonitoringSystem/1.0"
                - type: "noneOf"
                  rules:
                    - type: "ipRange"
                      ranges: 
                        - "10.99.0.0/16"  # Testing subnet

Example 5: Integration with External API for Dynamic Rules

This example shows how to load IP whitelists and other rules from an external API:

- id: "tlsguard"
  name: "External API Integration"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      users:
        john.doe: john
        jane.smith: jane
      
      refreshInterval: "15m"  # Refresh every 15 minutes
      
      externalData:
        url: "https://security-api.internal/access-config"
        dataKey: "accessRules"
        skipTlsVerify: false
        headers:
          Authorization: "Bearer [[ file \"/secrets/api-token\" ]]"
          X-System-ID: "frontend-cluster"
      
      rules:
        - type: "anyOf"
          rules:
            # Use IP ranges from external API
            - type: "ipRange"
              ranges:
                - "[[ .data.allowedIpRanges ]]"
            
            # Use API key patterns from external API
            - type: "header"
              headers:
                X-Api-Key: "[[ .data.apiKeyPattern ]]"

Example 6: Highly Secure Environment (Air-gapped)

This configuration is suitable for high-security environments with no external connectivity:

- id: "tlsguard"
  name: "Air-gapped Secure Environment"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      users:
        secure-admin: admin
        secure-operator: operator
      
      requestHeaders:
        X-Security-Level: "[[.Cert.Subject.OrganizationalUnit]]"
        X-Auth-Source: "client-certificate"
      
      rules:
        - type: "allOf"
          rules:
            # Must have valid certificate with specific organizational unit
            - type: "header"
              headers:
                X-Security-Level: "LEVEL-[45]"  # Regex to match LEVEL-4 or LEVEL-5
            
            # Must be from secure management network
            - type: "ipRange"
              ranges:
                - "10.10.0.0/16"  # Secure management network
            
            # Must NOT be from any other network
            - type: "noneOf"
              rules:
                - type: "ipRange"
                  ranges:
                    - "0.0.0.0/0"  # All IPs
                  addInterface: false

Example 7: Multi-tenant Environment

This configuration allows different access policies for different tenants:

- id: "tlsguard"
  name: "Multi-tenant Access Control"
  type: "plugin"
  config:
    tlsguard:
      usernameHeader: "X-Auth-User"
      users:
        tenant1-admin: tenant1-admin
        tenant1-user: tenant1-user
        tenant2-admin: tenant2-admin
        tenant2-user: tenant2-user
      
      requestHeaders:
        X-Tenant-ID: "[[.Cert.Subject.OrganizationalUnit]]"
      
      rules:
        - type: "anyOf"
          rules:
            # Tenant 1 access rules
            - type: "allOf"
              rules:
                - type: "header"
                  headers:
                    X-Tenant-ID: "tenant1"
                - type: "ipRange"
                  ranges:
                    - "10.1.0.0/16"  # Tenant 1 network
            
            # Tenant 2 access rules
            - type: "allOf"
              rules:
                - type: "header"
                  headers:
                    X-Tenant-ID: "tenant2"
                - type: "ipRange"
                  ranges:
                    - "10.2.0.0/16"  # Tenant 2 network

Integration with Traefik

To apply any of these TLSGuard configurations, you’ll need to reference the middleware in your Traefik router configuration:

# In your Traefik dynamic configuration
http:
  routers:
    my-secure-service:
      rule: "Host(`secure.example.com`)"
      service: "my-backend-service"
      middlewares:
        - tlsguard
      tls:
        options: "client-auth"

  services:
    my-backend-service:
      loadBalancer:
        servers:
          - url: "http://internal-service:8080"

tls:
  options:
    client-auth:
      clientAuth:
        caFiles:
          - "/path/to/ca.crt"
        clientAuthType: "VerifyClientCertIfGiven"  # Or "RequireAndVerifyClientCert" for stricter security

Remember to restart or reload Traefik after changing your configuration. You can validate your TLSGuard configuration by examining the Traefik logs (with log level set to DEBUG) to see authentication decisions and rule evaluations.

Let me know if you need any further clarification or have additional questions!

1 Like