430 lines
9.4 KiB
Markdown
430 lines
9.4 KiB
Markdown
# 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/) |