Files
K3S/addons/authelia/README.md
Sergey Antropoff 225f77598a feat: добавить аддон authelia — SSO forward-auth и OIDC provider
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
2026-04-26 18:18:46 +03:00

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

  1. Generate password hash:

    docker run --rm authelia/authelia:latest authelia hash-password 'newpassword'
    
  2. 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]
    
  3. Add to vault.yml:

    authelia_user_alice_password_hash: "$argon2id$..."
    
  4. Redeploy: make addon-authelia

Groups

  • admins — access to authelia_admin_domains (ArgoCD, Vault, Harbor, Dashboard)
  • users — access to authelia_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 in protectedDomains)
  • "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)

  1. Open http://sonarr.home.local/ in a private browser window
  2. Should redirect to http://auth.home.local/?rd=http%3A%2F%2Fsonarr.home.local%2F
  3. Enter credentials → should redirect back to Sonarr
  4. 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)

  1. Open http://gitea.home.local/user/oauth2/Authelia
    (or click "Sign in with Authelia" on Gitea login page)
  2. Should redirect to Authelia login form
  3. Login with admin credentials
  4. Authelia redirects back to Gitea with authorization code
  5. 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).