Files
k3s-ansible/TRAEFIK_BASIC_AUTH.md

9.4 KiB

Traefik Basic Authentication for Dashboard and API

Overview

This guide explains how to enable basic authentication for the Traefik dashboard (/dashboard) and API (/api) endpoints in your Helm-deployed Traefik instance.

Prerequisites

  • Traefik deployed via Helm with IngressRoute enabled
  • htpasswd utility (usually comes with Apache utilities)
  • kubectl configured and access to your cluster

Step 1: Generate Credentials

Generate a hashed password for your basic auth user:

# Install htpasswd if not already installed
# macOS:
brew install httpd

# Linux:
sudo apt-get install apache2-utils

# Create credentials file (replace 'admin' with your desired username)
htpasswd -c auth admin
# You'll be prompted to enter a password

# View the generated credentials
cat auth
# Output example: admin:$apr1$H6uskkkW$FTbVJriq9dMj0O/3YbCzC0

Option 2: Using Python

python3 << 'EOF'
import bcrypt
import base64

username = "admin"
password = "your_secure_password"

# Hash password using bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

# Format for htpasswd
htpasswd_line = f"{username}:{hashed.decode()}"
print(htpasswd_line)
EOF

Step 2: Create Kubernetes Secret

Once you have the credentials, create a Kubernetes Secret:

# Using the auth file from htpasswd
kubectl create secret generic traefik-basic-auth \
  --from-file=users=auth \
  -n traefik

Or create it directly without a file:

# Replace 'admin' and hashed_password with your actual values
kubectl create secret generic traefik-basic-auth \
  --from-literal=users='admin:$apr1$H6uskkkW$FTbVJriq9dMj0O/3YbCzC0' \
  -n traefik

Verify Secret Creation

kubectl get secret traefik-basic-auth -n traefik
kubectl get secret traefik-basic-auth -n traefik -o yaml

Step 3: Create BasicAuth Middleware

Create a Traefik BasicAuth middleware that references the secret:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: traefik-basic-auth
  namespace: kube-system
spec:
  basicAuth:
    secret: traefik-basic-auth
    removeHeader: true  # Remove Authorization header after auth
    headerField: Authorization  # Standard HTTP auth header

Save this to a file and apply it:

kubectl apply -f - <<'EOF'
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: traefik-basic-auth
  namespace: traefik
spec:
  basicAuth:
    secret: traefik-basic-auth
    removeHeader: true
EOF

Step 4: Update IngressRoute with Middleware

Now update your Traefik IngressRoute to use the BasicAuth middleware:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: traefik
spec:
  entryPoints:
    - traefik
  routes:
    - match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
      kind: Rule
      services:
        - kind: TraefikService
          name: api@internal
      middlewares:
        - name: traefik-basic-auth
          namespace: traefik
  tls: {}

Apply Updated IngressRoute

kubectl apply -f - <<'EOF'
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: traefik
spec:
  entryPoints:
    - traefik
  routes:
    - match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
      kind: Rule
      services:
        - kind: TraefikService
          name: api@internal
      middlewares:
        - name: traefik-basic-auth
          namespace: kube-system
  tls: {}
EOF

Step 5: Test Basic Auth

Test Dashboard Access

# Port-forward to Traefik
kubectl port-forward -n traefik svc/traefik 8080:8080 &

# Test without credentials (should fail with 401)
curl -i http://localhost:8080/dashboard/
# Output: HTTP/1.1 401 Unauthorized

# Test with correct credentials
curl -i -u admin:your_password http://localhost:8080/dashboard/
# Output: HTTP/1.1 200 OK

# Test with wrong credentials (should fail)
curl -i -u admin:wrong_password http://localhost:8080/dashboard/
# Output: HTTP/1.1 401 Unauthorized

Test API Access

# Without auth
curl http://localhost:8080/api/http/routers

# With auth
curl -u admin:your_password http://localhost:8080/api/http/routers

Using with Helm Chart Values

If you want to configure this permanently via Helm, add to your values.yaml:

ingressRoute:
  dashboard:
    enabled: true
    entryPoints:
      - traefik
    matchRule: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
    middlewares:
      - name: traefik-basic-auth
        namespace: traefik
    services:
      - kind: TraefikService
        name: api@internal
    tls: {}

# Create BasicAuth middleware as an extra object
extraObjects:
  - apiVersion: v1
    kind: Secret
    metadata:
      name: traefik-basic-auth
      namespace: traefik
    type: Opaque
    stringData:
      users: |
        admin:$apr1$H6uskkkW$FTbVJriq9dMj0O/3YbCzC0

  - apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: traefik-basic-auth
      namespace: traefik
    spec:
      basicAuth:
        secret: traefik-basic-auth
        removeHeader: true

Then update via Helm:

helm upgrade traefik traefik/traefik \
  -n traefik \
  -f values.yaml

Multiple Users

To add multiple users to the basic auth secret:

# Create auth file with multiple users
htpasswd -c auth admin
htpasswd -B auth user2
htpasswd -B auth user3

# View the file
cat auth
# Output:
# admin:$apr1$H6uskkkW$FTbVJriq9dMj0O/3YbCzC0
# user2:$2y$05$...
# user3:$2y$05$...

# Create secret
kubectl create secret generic traefik-basic-auth \
  --from-file=users=auth \
  -n traefik \
  -o yaml --dry-run=client | kubectl apply -f -

Rotate Credentials

To update credentials without recreating the middleware:

# Delete old secret
kubectl delete secret traefik-basic-auth -n traefik

# Create new secret with updated credentials
htpasswd -c auth admin  # Enter new password
kubectl create secret generic traefik-basic-auth \
  --from-file=users=auth \
  -n kube-system

Traefik will automatically reload the secret without needing a pod restart.

Security Best Practices

  1. Use Strong Passwords: Generate strong random passwords

    openssl rand -base64 16
    # Generate: dRw3k8F9P2mL7qX1nV4bZ6
    
  2. Use HTTPS/TLS: Configure TLS for the dashboard in production

    tls:
      secretName: traefik-tls  # Your TLS certificate secret
    
  3. Restrict Access: Use IP-based access restrictions

    middlewares:
      - name: traefik-basic-auth
        namespace: kube-system
      - name: ip-whitelist
        namespace: kube-system
    ---
    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: ip-whitelist
      namespace: kube-system
    spec:
      ipWhiteList:
        sourceRange:
          - 192.168.1.0/24  # Your IP range
    
  4. Rotate Credentials Regularly: Update passwords every 90 days

  5. Use Network Policies: Restrict access to Traefik API port

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: traefik-api-restrict
      namespace: kube-system
    spec:
      podSelector:
        matchLabels:
          app.kubernetes.io/name: traefik
      policyTypes:
        - Ingress
      ingress:
        - from:
            - namespaceSelector:
                matchLabels:
                  name: kube-system
          ports:
            - protocol: TCP
              port: 8080
    

Troubleshooting

Secret not found error

Error: secret "traefik-basic-auth" not found

Solution:

# Verify secret exists in correct namespace
kubectl get secret traefik-basic-auth -n kube-system

# If missing, recreate it
kubectl create secret generic traefik-basic-auth \
  --from-file=users=auth \
  -n traefik

401 Unauthorized even with correct credentials

Possible causes:

  • Secret format is wrong
  • Middleware not applied to IngressRoute
  • Password hash algorithm mismatch

Debug:

# Check secret content
kubectl get secret traefik-basic-auth -n traefik -o yaml

# Check IngressRoute
kubectl get ingressroute traefik-dashboard -n traefik -o yaml

# Check Traefik logs
kubectl logs -n traefik -l app.kubernetes.io/name=traefik -f | grep -i auth

Htpasswd format issues

Valid formats:

  • APR1: $apr1$... (from htpasswd -b)
  • Bcrypt: $2y$... (from htpasswd -B)
  • SHA: {SHA}... (from htpasswd -s)

Use APR1 or Bcrypt for best compatibility.

Quick Reference Commands

# Generate credentials
htpasswd -c auth admin

# Create secret
kubectl create secret generic traefik-basic-auth --from-file=users=auth -n traefik

# Create middleware
kubectl apply -f - <<'EOF'
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: traefik-basic-auth
  namespace: traefik
spec:
  basicAuth:
    secret: traefik-basic-auth
    removeHeader: true
EOF

# Update IngressRoute
kubectl patch ingressroute traefik-dashboard -n traefik --type merge \
  -p '{"spec":{"routes":[{"middlewares":[{"name":"traefik-basic-auth","namespace":"traefik"}]}]}}'

# Test access
curl -u admin:password http://localhost:8080/dashboard/

# Verify middleware is applied
kubectl get middleware -n traefik
kubectl describe middleware traefik-basic-auth -n traefik

References