Helm chart + Ansible role для Authelia 4.38: - Forward-auth для ingress-nginx через аннотации auth-url/auth-signin - OIDC provider: Gitea, Grafana, ArgoCD, MinIO, Vault, Nextcloud - SQLite default или PostgreSQL; опциональный Redis для сессий - RSA ключ OIDC генерируется автоматически если не задан в vault - ConfigMap authelia-forward-auth с готовыми аннотациями для любого сервиса - README: install, users, protect service, OIDC per-service, debug, test
14 KiB
authelia
Self-hosted authentication system providing forward-auth for ingress-nginx and an OIDC provider for Gitea, Grafana, ArgoCD, MinIO, Vault, and Nextcloud.
Architecture
User → ingress-nginx → (auth-url) → Authelia :9091 → allowed/denied
↓
Authelia portal
auth.home.local
↓
users_database.yml
(argon2id passwords)
OIDC flow:
Service → Authelia /api/oidc/authorization → login → token → Service
Traffic routes:
auth.home.local → authelia ClusterIP :9091 (Ingress, NO forward-auth)
sonarr.home.local → sonarr service (Ingress + forward-auth annotations)
gitea.home.local → gitea service (Ingress, no forward-auth — OIDC handles it)
Kubernetes objects:
Deployment: authelia
Service: authelia (ClusterIP :9091)
Secrets: authelia-secrets (jwt, session, storage_encryption, oidc keys)
authelia-config (configuration.yml — contains OIDC client secrets)
authelia-users (users_database.yml)
PVC: authelia-data (SQLite db + notification.txt)
Ingress: authelia (auth.home.local)
ConfigMap: authelia-forward-auth (copy-paste annotation reference)
Deployment: authelia-redis (optional, redis.enabled=true)
1. Installation
Step 1 — Generate secrets
Run these commands and save the output:
# Core secrets
openssl rand -base64 64 # → authelia_jwt_secret
openssl rand -base64 64 # → authelia_session_secret
openssl rand -base64 32 # → authelia_storage_encryption_key
openssl rand -base64 48 # → authelia_oidc_hmac_secret
# OIDC client secrets (one per enabled client)
openssl rand -hex 32 # → authelia_oidc_secret_gitea
openssl rand -hex 32 # → authelia_oidc_secret_grafana
The OIDC RSA private key is auto-generated during deploy. Leave
authelia_oidc_private_key: ""in vault. After first deploy, retrieve and save it (see note at end of deploy output).
Step 2 — Generate admin password hash
docker run --rm authelia/authelia:latest authelia hash-password 'your-password'
# Output: $argon2id$v=19$m=65536,t=3,p=4$...
Copy the full $argon2id$... string.
Step 3 — Edit vault.yml
# group_vars/all/vault.yml (ansible-vault encrypted)
authelia_jwt_secret: "<output of openssl rand -base64 64>"
authelia_session_secret: "<output of openssl rand -base64 64>"
authelia_storage_encryption_key: "<output of openssl rand -base64 32>"
authelia_oidc_hmac_secret: "<output of openssl rand -base64 48>"
authelia_oidc_private_key: "" # auto-generated on first deploy
authelia_oidc_secret_gitea: "<output of openssl rand -hex 32>"
authelia_oidc_secret_grafana: "<output of openssl rand -hex 32>"
authelia_user_admin_password_hash: "$argon2id$v=19$m=65536,t=3,p=4$..."
Step 4 — Configure addons.yml
# group_vars/all/addons.yml
addon_authelia: true
authelia_host: "auth.home.local"
authelia_domain: "home.local"
# OIDC clients to enable
authelia_oidc_gitea_enabled: true
authelia_oidc_grafana_enabled: true
# Domains to protect
authelia_protected_domains:
- sonarr.home.local
- radarr.home.local
- lidarr.home.local
- prowlarr.home.local
- pgadmin.home.local
# Domains requiring admin group
authelia_admin_domains:
- argocd.home.local
- vault.home.local
# Public bypass (no auth)
authelia_bypass_domains:
- plex.home.local
Step 5 — Deploy
make addon-authelia
Step 6 — Add DNS record
Add auth.home.local pointing to the kube-vip/ingress-nginx IP in Technitium DNS (or your DNS server).
2. Managing users
Add a new user
-
Generate password hash:
docker run --rm authelia/authelia:latest authelia hash-password 'newpassword' -
Add to
group_vars/all/addons.yml:authelia_users: admin: displayname: "Administrator" email: "admin@home.local" groups: [admins, users] alice: displayname: "Alice" email: "alice@home.local" groups: [users] -
Add to
vault.yml:authelia_user_alice_password_hash: "$argon2id$..." -
Redeploy:
make addon-authelia
Groups
admins— access toauthelia_admin_domains(ArgoCD, Vault, Harbor, Dashboard)users— access toauthelia_protected_domains(Sonarr, Radarr, etc.)
OIDC claims include the groups scope, so Grafana/Gitea can use group-based role mapping.
3. Protect a new service with forward-auth
Step 1 — Add annotations to the service's Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myservice
namespace: myservice
annotations:
kubernetes.io/ingress.class: nginx
# ── Authelia forward-auth ──────────────────────────────────────────────
nginx.ingress.kubernetes.io/auth-url: "http://authelia.authelia.svc.cluster.local:9091/api/authz/forward-auth"
nginx.ingress.kubernetes.io/auth-signin: "http://auth.home.local/?rd=$scheme://$host$escaped_request_uri"
nginx.ingress.kubernetes.io/auth-response-headers: "Remote-User,Remote-Name,Remote-Groups,Remote-Email"
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header X-Forwarded-Method $request_method;
spec:
rules:
- host: myservice.home.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myservice
port:
number: 8080
Get the exact URLs for your deployment:
kubectl get cm authelia-forward-auth -n authelia -o jsonpath='{.data.annotations\.yaml}'
Step 2 — Add to access control
Add myservice.home.local to the appropriate list in addons.yml:
authelia_protected_domains:
- myservice.home.local
# ... existing entries
Then redeploy: make addon-authelia
4. OIDC client configuration per service
Gitea
In Gitea Admin → Site Administration → Authentication Sources → Add OAuth2:
| Field | Value |
|---|---|
| Name | Authelia |
| OAuth2 Provider | OpenID Connect |
| Client ID | gitea |
| Client Secret | value of authelia_oidc_secret_gitea in vault |
| OpenID Connect Auto Discovery URL | http://auth.home.local/.well-known/openid-configuration |
| Scopes | openid profile email groups |
Restart Gitea. Users can now click "Sign in with Authelia" on the login page.
Optional — auto-create users and map admin group:
# app.ini
[oauth2]
USERNAME = preferred_username
UPDATE_AVATAR = true
[openid]
ENABLE_OPENID_SIGNIN = true
Grafana
Add to Grafana's grafana.ini (or Helm values):
[auth.generic_oauth]
enabled = true
name = Authelia
client_id = grafana
client_secret = <authelia_oidc_secret_grafana from vault>
scopes = openid profile email groups
auth_url = http://auth.home.local/api/oidc/authorization
token_url = http://auth.home.local/api/oidc/token
api_url = http://auth.home.local/api/oidc/userinfo
# Role mapping via Authelia groups
role_attribute_path = contains(groups[*], 'admins') && 'GrafanaAdmin' || 'Viewer'
allow_sign_up = true
Or in Helm values for the prometheus-stack addon:
# group_vars/all/addons.yml
prometheus_grafana_oauth_enabled: true
prometheus_grafana_oauth_client_id: "grafana"
prometheus_grafana_oauth_client_secret: "..." # from vault
prometheus_grafana_oauth_auth_url: "http://auth.home.local/api/oidc/authorization"
prometheus_grafana_oauth_token_url: "http://auth.home.local/api/oidc/token"
prometheus_grafana_oauth_api_url: "http://auth.home.local/api/oidc/userinfo"
ArgoCD
Enable ArgoCD OIDC in argocd-cm ConfigMap:
# values override for argocd Helm chart
server:
config:
oidc.config: |
name: Authelia
issuer: http://auth.home.local
clientID: argocd
clientSecret: $oidc.authelia.clientSecret
requestedScopes:
- openid
- profile
- email
- groups
requestedIDTokenClaims:
groups:
essential: true
Map Authelia groups to ArgoCD RBAC:
# argocd-rbac-cm
policy.csv: |
g, admins, role:admin
policy.default: role:readonly
Store the secret in a K8s Secret argocd-secret:
data:
oidc.authelia.clientSecret: <base64 of authelia_oidc_secret_argocd>
MinIO
In MinIO Console → Identity → OpenID:
| Field | Value |
|---|---|
| Config URL | http://auth.home.local/.well-known/openid-configuration |
| Client ID | minio |
| Client Secret | value of authelia_oidc_secret_minio |
| Claim Name | groups |
| Scopes | openid,profile,email |
Map Authelia group admins to MinIO policy consoleAdmin.
Vault
Configure Vault OIDC auth method:
vault auth enable oidc
vault write auth/oidc/config \
oidc_discovery_url="http://auth.home.local" \
oidc_client_id="vault" \
oidc_client_secret="<authelia_oidc_secret_vault>" \
default_role="reader"
vault write auth/oidc/role/reader \
bound_audiences="vault" \
allowed_redirect_uris="https://vault.home.local/ui/vault/auth/oidc/oidc/callback" \
allowed_redirect_uris="https://vault.home.local/oidc/callback" \
user_claim="sub" \
groups_claim="groups" \
token_policies="default"
5. Debugging auth issues
Check Authelia logs (real-time)
kubectl -n authelia logs -l app.kubernetes.io/name=authelia -f --tail=100
Common log messages:
"ALLOW"— request was allowed"DENY"— request was denied (check domain inprotectedDomains)"Redirecting"— unauthenticated user redirected to login"POST /api/firstfactor"— login attempt
Verify forward-auth endpoint is reachable
From within the cluster:
kubectl run curl-test --rm -it --image=curlimages/curl -- \
curl -v http://authelia.authelia.svc.cluster.local:9091/api/health
# Expected: {"status":"OK"}
Test that a domain's annotations are applied
kubectl get ingress sonarr -n mediaserver -o yaml | grep auth-url
Check current access control configuration
kubectl -n authelia exec deploy/authelia -- \
cat /config/configuration.yml | grep -A 30 "access_control:"
Check active sessions (SQLite)
kubectl -n authelia exec deploy/authelia -- \
sqlite3 /data/db.sqlite3 "SELECT subject, ip, last_activity FROM user_opaque_identifier LIMIT 20;"
Notification log (if SMTP disabled)
kubectl -n authelia exec deploy/authelia -- cat /data/notification.txt
6. Test the login flow
Forward-auth flow (e.g., Sonarr)
- Open
http://sonarr.home.local/in a private browser window - Should redirect to
http://auth.home.local/?rd=http%3A%2F%2Fsonarr.home.local%2F - Enter credentials → should redirect back to Sonarr
- Access granted
Test from command line:
# Step 1: login request (expect redirect to Authelia)
curl -I http://sonarr.home.local/
# Expected: 302 to auth.home.local
# Step 2: verify endpoint directly
curl -I -H "X-Forwarded-Host: sonarr.home.local" \
-H "X-Forwarded-URI: /" \
-H "X-Forwarded-Proto: http" \
http://authelia.authelia.svc.cluster.local:9091/api/authz/forward-auth
# Expected: 401 (unauthenticated) or 200 (if session cookie provided)
OIDC flow (e.g., Gitea)
- Open
http://gitea.home.local/user/oauth2/Authelia
(or click "Sign in with Authelia" on Gitea login page) - Should redirect to Authelia login form
- Login with admin credentials
- Authelia redirects back to Gitea with authorization code
- Gitea exchanges code for token — user is logged in
Check OIDC discovery endpoint
curl -s http://auth.home.local/.well-known/openid-configuration | jq .
# Should return JSON with issuer, authorization_endpoint, token_endpoint, etc.
Variables reference
| Variable | Default | Description |
|---|---|---|
authelia_host |
auth.home.local |
Portal hostname |
authelia_domain |
home.local |
Session cookie domain |
authelia_theme |
dark |
UI theme |
authelia_two_factor_enabled |
false |
Require TOTP/WebAuthn |
authelia_storage_type |
sqlite |
sqlite or postgresql |
authelia_redis_enabled |
false |
Built-in Redis for sessions |
authelia_smtp_enabled |
false |
SMTP for 2FA/password-reset emails |
authelia_oidc_enabled |
true |
Enable OIDC provider |
authelia_oidc_gitea_enabled |
true |
Gitea OIDC client |
authelia_oidc_grafana_enabled |
true |
Grafana OIDC client |
authelia_oidc_argocd_enabled |
false |
ArgoCD OIDC client |
authelia_oidc_minio_enabled |
false |
MinIO OIDC client |
authelia_oidc_vault_enabled |
false |
Vault OIDC client |
authelia_ingress_tls_enabled |
false |
TLS on auth portal |
authelia_protected_domains |
[sonarr, radarr…] |
Domains requiring login |
authelia_admin_domains |
[argocd, vault…] |
Admin-only domains |
authelia_bypass_domains |
[] |
Public bypass domains |
authelia_oidc_domains |
[gitea, grafana, minio] |
OIDC bypass (forward-auth off) |
Vault secrets required
| Variable | Notes |
|---|---|
authelia_jwt_secret |
min 64 chars — openssl rand -base64 64 |
authelia_session_secret |
min 64 chars |
authelia_storage_encryption_key |
min 20 chars — openssl rand -base64 32 |
authelia_oidc_hmac_secret |
min 32 chars — openssl rand -base64 48 |
authelia_oidc_private_key |
RSA PEM — leave empty, auto-generated |
authelia_oidc_secret_gitea |
openssl rand -hex 32 |
authelia_oidc_secret_grafana |
openssl rand -hex 32 |
authelia_user_admin_password_hash |
argon2id hash from authelia hash-password |
Saving the auto-generated OIDC private key
After the first deploy, save the key to vault for reproducibility:
kubectl -n authelia get secret authelia-secrets \
-o jsonpath='{.data.oidc_private_key}' | base64 -d
Paste the PEM output into vault.yml as authelia_oidc_private_key: | (multiline YAML).