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
-
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"
-
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
-
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:
-
Check TLS Options: Ensure your TLS options are properly configured with the correct CA file.
-
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. -
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). -
Enable Debug Logging: Add the following to your Traefik static configuration to see detailed logs:
log: level: DEBUG
-
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:
- User Identity Mapping: Maps certificate identities to usernames
- Fine-grained Access Control: Controls access by specific certificate serial numbers
- Fallback to IP-based Rules: Allows configuring alternative authentication methods
- 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!