Authelia
Deploy Authelia on Kubernetes — a full-featured authentication and authorization server with single sign-on (SSO), multi-factor authentication (TOTP, WebAuthn/FIDO2), OpenID Connect identity provider, and forward-auth middleware support for Traefik, nginx, Caddy, and Envoy.
Authelia requires three secrets before it can start. The most critical is storageEncryptionKey (20+ chars), which
encrypts all MFA secrets stored in the database — TOTP keys and WebAuthn credentials. If this key is lost or rotated,
all MFA device registrations become permanently unreadable and users must re-enroll. Always persist all three
secrets via secrets.existingSecret before the first deployment.
| Secret | Minimum Length | Purpose |
|---|---|---|
jwtSecret |
64 chars | Signs identity tokens for password resets. |
sessionSecret |
64 chars | Encrypts session cookies. |
storageEncryptionKey |
20 chars | Encrypts MFA secrets (TOTP, WebAuthn) in the DB. |
Generate with: openssl rand -base64 64 | head -c 64
Key Features
- Forward auth middleware — native Traefik, nginx, Caddy, and Envoy integration
- MFA — TOTP, WebAuthn/FIDO2, and Duo Push
- OpenID Connect IdP — certified OIDC provider for app SSO
- File or LDAP auth backends — local YAML user database or LDAP/AD directory
- Access control rules — domain, user, group, network, and method policies
- Brute force protection — configurable regulation (
max_retries,ban_time) - Prometheus metrics with optional ServiceMonitor
Architecture
The chart runs the official Authelia image behind a named-port Service and
optional Ingress or HTTPRoute. A rendered configuration Secret and separate
credential/user Secrets are mounted read-only. SQLite uses the application PVC;
production profiles can select bundled or external PostgreSQL/MySQL and optional
Redis session storage. Native health and metrics listeners follow
containerPorts, while the ingress-only NetworkPolicy limits reachable Pod
ports without blocking external identity, mail or storage dependencies.
Upgrades from releases before 1.5.18 may retain config.server.address and
config.telemetry.metrics.address. Those legacy values remain supported and
take precedence over the new default ports. Migrate them to containerPorts
when editing the configuration.
Installation
HTTPS repository:
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install authelia helmforge/authelia -f values.yaml
OCI registry:
helm install authelia oci://ghcr.io/helmforgedev/helm/authelia -f values.yaml
Deployment Examples
# values.yaml — Authelia with SQLite and file-based user database
secrets:
existingSecret: authelia-master-secrets
existingSecretJwtKey: jwt-secret # 64+ chars
existingSecretSessionKey: session-secret # 64+ chars
existingSecretStorageEncryptionKey: storage-encryption-key # 20+ chars
config:
session:
cookies:
- domain: example.com
authelia_url: 'https://auth.example.com'
default_redirection_url: 'https://www.example.com'
access_control:
default_policy: one_factor
rules:
- domain: 'public.example.com'
policy: bypass
- domain: '*.example.com'
policy: two_factor
notifier:
# filesystem notifier logs to /data/notification.txt — email not sent
# Switch to smtp notifier for production email delivery
filesystem:
filename: /data/notification.txt
usersDatabase:
enabled: true
users:
admin:
displayname: 'Administrator'
email: '[email protected]'
# Generate password hash: authelia crypto hash generate argon2 --password 'mypassword'
password: '$argon2id$v=19$m=65536,t=3,p=4$...'
groups:
- admins
persistence:
enabled: true
size: 1Gi
ingress:
enabled: true
ingressClassName: traefik
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: auth.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: authelia-tls
hosts:
- auth.example.com# values.yaml — Authelia HA: PostgreSQL + Redis (required for multi-replica)
replicaCount: 2 # requires Redis for session coordination
secrets:
existingSecret: authelia-master-secrets
config:
session:
cookies:
- domain: example.com
authelia_url: 'https://auth.example.com'
access_control:
default_policy: two_factor
notifier:
smtp:
address: 'submissions://smtp.example.com:465'
sender: 'Authelia <[email protected]>'
username: '[email protected]'
password: 'smtp-password' # use extraEnv with secretKeyRef in production
postgresql:
enabled: true
auth:
database: authelia
username: authelia
password: 'strong-db-password'
redis:
enabled: true
auth:
password: 'strong-redis-password'
database:
type: postgres
persistence:
enabled: true
size: 1Gi
backup:
enabled: true
schedule: '0 2 * * *'
s3:
endpoint: https://s3.amazonaws.com
bucket: authelia-backups
existingSecret: authelia-s3-credentials
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: auth.example.com
paths:
- path: /
pathType: Prefix# values.yaml — Authelia configured for Traefik forwardAuth middleware
# After deploying, create a Traefik Middleware resource in the same namespace:
#
# apiVersion: traefik.io/v1alpha1
# kind: Middleware
# metadata:
# name: authelia
# spec:
# forwardAuth:
# address: http://authelia.authelia.svc.cluster.local/api/authz/forward-auth
# trustForwardHeader: true
# authResponseHeaders:
# - Remote-User
# - Remote-Groups
# - Remote-Name
# - Remote-Email
#
# Then add annotation to protected services:
# traefik.ingress.kubernetes.io/router.middlewares: <namespace>-authelia@kubernetescrd
secrets:
existingSecret: authelia-master-secrets
config:
session:
cookies:
- domain: example.com
authelia_url: 'https://auth.example.com'
access_control:
default_policy: one_factor
rules:
- domain: 'auth.example.com'
policy: bypass
- domain: '*.example.com'
policy: one_factor
usersDatabase:
enabled: true
users:
admin:
displayname: 'Admin'
email: '[email protected]'
password: '$argon2id$v=19$m=65536,t=3,p=4$...'
groups:
- admins
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: auth.example.com
paths:
- path: /
pathType: Prefix# values.yaml — Authelia as OIDC identity provider
secrets:
existingSecret: authelia-master-secrets
existingSecretOidcHmacKey: oidc-hmac-secret # required for OIDC
config:
session:
cookies:
- domain: example.com
authelia_url: 'https://auth.example.com'
access_control:
default_policy: two_factor
identity_providers:
oidc:
clients:
- client_id: grafana
client_name: Grafana
client_secret: '$pbkdf2-sha512$310000$...' # hashed client secret
public: false
authorization_policy: two_factor
redirect_uris:
- 'https://grafana.example.com/login/generic_oauth'
scopes:
- openid
- profile
- email
- groups
userinfo_signed_response_alg: none
postgresql:
enabled: true
auth:
password: 'strong-db-password'
redis:
enabled: true
auth:
password: 'strong-redis-password'
database:
type: postgres
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: auth.example.com
paths:
- path: /
pathType: PrefixConfiguration Reference
Image
| Parameter | Type | Default | Description |
|---|---|---|---|
image.repository |
string | docker.io/authelia/authelia |
Authelia image. |
image.tag |
string | "4.39.28" |
Image tag. |
Secrets
| Parameter | Type | Default | Description |
|---|---|---|---|
secrets.jwtSecret |
string | "" |
JWT signing secret (64+ chars). Required. |
secrets.sessionSecret |
string | "" |
Session cookie encryption secret (64+ chars). Required. |
secrets.storageEncryptionKey |
string | "" |
MFA data encryption key (20+ chars). Required. Never rotate. |
secrets.oidcHmacSecret |
string | "" |
OIDC HMAC secret. Required only when using OIDC. |
secrets.existingSecret |
string | "" |
Existing secret containing all secret keys. |
secrets.existingSecretJwtKey |
string | jwt-secret |
Key for JWT secret. |
secrets.existingSecretSessionKey |
string | session-secret |
Key for session secret. |
secrets.existingSecretStorageEncryptionKey |
string | storage-encryption-key |
Key for storage encryption key. |
secrets.existingSecretOidcHmacKey |
string | oidc-hmac-secret |
Key for OIDC HMAC secret. |
Configuration
The config block is rendered as Authelia’s configuration.yml. Key sub-sections:
| Section | Description |
|---|---|
config.session.cookies |
Domain and Authelia URL for cookie scope (must match ingress). |
config.access_control.rules |
Access control policies per domain, group, user, and network. |
config.access_control.default_policy |
Default policy: bypass, one_factor, two_factor, deny. |
config.notifier.filesystem |
Log notifications to file (no email). Default. |
config.notifier.smtp |
SMTP notifier for email delivery (password resets, device enroll). |
config.totp |
TOTP algorithm, period, digits. |
config.webauthn |
WebAuthn/FIDO2 display name and timeout. |
config.regulation |
Brute force: max_retries, find_time, ban_time. |
config.identity_providers.oidc |
OIDC client registrations. |
Users Database
| Parameter | Type | Default | Description |
|---|---|---|---|
usersDatabase.enabled |
boolean | true |
Enable file-based user database at /config/users_database.yml. |
usersDatabase.existingSecret |
string | "" |
Existing secret with the users_database.yml content. |
usersDatabase.users |
object | {} |
Inline user definitions. Passwords must be Argon2 hashes. |
Authelia enforces Argon2id hashes for user passwords. Generate a hash using the CLI:
docker run --rm authelia/authelia:4.39.28 authelia crypto hash generate argon2 --password 'mypassword'The output hash goes in usersDatabase.users.<user>.password.
Database
| Parameter | Type | Default | Description |
|---|---|---|---|
database.type |
string | sqlite |
Storage backend: sqlite, postgres, mysql. |
database.external.host |
string | "" |
External database hostname. |
database.external.existingSecret |
string | "" |
Existing secret with database password. |
database.external.existingSecretPasswordKey |
string | password |
Key for the database password. |
Subcharts
| Parameter | Type | Default | Description |
|---|---|---|---|
postgresql.enabled |
boolean | false |
Deploy the bundled PostgreSQL subchart. |
postgresql.auth.password |
string | "" |
Password. Required when using the subchart. |
mysql.enabled |
boolean | false |
Deploy the bundled MySQL subchart. |
redis.enabled |
boolean | false |
Deploy the bundled Redis subchart (required for HA). |
redis.auth.password |
string | "" |
Password. Required when using the subchart. |
Persistence, Service, Metrics
| Parameter | Type | Default | Description |
|---|---|---|---|
persistence.enabled |
boolean | true |
Enable PVC for /data (SQLite DB, filesystem notifier). |
persistence.size |
string | 1Gi |
PVC size. |
containerPorts.http |
integer | 9091 |
Native Authelia HTTP listener. |
containerPorts.metrics |
integer | 9959 |
Native Prometheus listener. |
service.port |
integer | 80 |
Client-facing Service port. |
networkPolicy.enabled |
boolean | true |
Restrict ingress to declared listeners. |
metrics.enabled |
boolean | false |
Enable the separate metrics Service. |
metrics.serviceMonitor.enabled |
boolean | false |
Enable Prometheus ServiceMonitor. |
The container ports are the listener source of truth. The chart generates
Authelia’s server.address and telemetry.metrics.address from them, keeping the
process, probes and named Service targets aligned.
Backup
| Parameter | Type | Default | Description |
|---|---|---|---|
backup.enabled |
boolean | false |
Enable scheduled S3 backup CronJob. |
backup.schedule |
string | "0 2 * * *" |
Cron schedule. |
backup.s3.endpoint |
string | "" |
S3-compatible endpoint URL. |
backup.s3.bucket |
string | "" |
Target bucket name. |
backup.s3.existingSecret |
string | "" |
Existing secret with S3 credentials. |
extraManifests |
array | [] |
Extra Kubernetes manifests. |
Upgrading to 4.39.28
Patches 4.39.23-4.39.28 fix OIDC client authentication, resource grants,
client-credentials subjects, JARM responses, storage queries, SMTP IPv6
addresses, consent redirects and Envoy authorization paths. Remove the obsolete
website attribute from custom configuration. The 4.39.28 container introduces
no chart-facing configuration, port, persistence or probe changes.
Review 4.39.23,
4.39.24,
4.39.25, and
4.39.26,
4.39.27, and
4.39.28.
The bundled dependency baseline is PostgreSQL 2.1.1, MySQL 2.1.1 and Redis 3.1.0.
These updates retain the documented storage and authentication contracts.
Security and recovery
Use stable existing Secrets or External Secrets for the JWT, session and storage
encryption keys. Treat those values and the selected database as one recovery
set; losing the storage encryption key permanently makes enrolled TOTP and
WebAuthn data unreadable. Terminate TLS at a trusted proxy and restrict access to
the rendered configuration Secret. The default read-only root filesystem uses a
bounded /tmp volume, disables API token mounting and restricts ingress to the
HTTP and optional metrics listeners. Configure explicit
networkPolicy.ingressFrom peers for trusted proxy namespaces.
Troubleshooting
- If the Pod does not become ready, inspect
/api/health, application logs and database or Redis endpoints before restarting it. - If a custom port fails, confirm
containerPorts.httporcontainerPorts.metrics; legacy listener addresses underconfigtake precedence when retained from an older release. - If login redirects or cookies fail, verify the public Authelia URL, cookie domain, TLS scheme and reverse-proxy forwarded headers.
- If MFA data cannot be decrypted, restore the matching database and original storage encryption key. Generating a replacement key does not recover data.
Authelia 4.39.21 changes storage encryption to use HKDF and authenticated additional data; 4.39.22 fixes the access-token JWT session migration. Back up the database and retain the storage encryption key before upgrading. Allow startup migrations to complete before serving traffic. A rollback may require restoring the matching database backup and key.
Generated credentials are retained through Helm cluster lookup. Use an existing
Secret for GitOps or offline rendering, where lookup cannot retrieve the installed
key. Do not rotate the storage key during this update. After rollout, run
authelia storage encryption check --config /config/configuration.yml inside the
Authelia container and verify application health and MFA enrollment.
See the 4.39.21 release notes and 4.39.22 migration fix.