Revamp docs and add Traefik Basic Auth guide
This commit is contained in:
430
TRAEFIK_BASIC_AUTH.md
Normal file
430
TRAEFIK_BASIC_AUTH.md
Normal file
@@ -0,0 +1,430 @@
|
||||
# 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
|
||||
|
||||
### Option 1: Using htpasswd (Recommended)
|
||||
|
||||
Generate a hashed password for your basic auth user:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```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:
|
||||
|
||||
```bash
|
||||
helm upgrade traefik traefik/traefik \
|
||||
-n traefik \
|
||||
-f values.yaml
|
||||
```
|
||||
|
||||
## Multiple Users
|
||||
|
||||
To add multiple users to the basic auth secret:
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
openssl rand -base64 16
|
||||
# Generate: dRw3k8F9P2mL7qX1nV4bZ6
|
||||
```
|
||||
|
||||
2. **Use HTTPS/TLS**: Configure TLS for the dashboard in production
|
||||
```yaml
|
||||
tls:
|
||||
secretName: traefik-tls # Your TLS certificate secret
|
||||
```
|
||||
|
||||
3. **Restrict Access**: Use IP-based access restrictions
|
||||
```yaml
|
||||
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
|
||||
```yaml
|
||||
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:**
|
||||
```bash
|
||||
# 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:**
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
- [Traefik BasicAuth Middleware](https://doc.traefik.io/traefik/middlewares/http/basicauth/)
|
||||
- [Traefik Helm Chart](https://github.com/traefik/traefik-helm-chart)
|
||||
- [Kubernetes Secrets Documentation](https://kubernetes.io/docs/concepts/configuration/secret/)
|
||||
Reference in New Issue
Block a user