Files
homelab-infra/apps/authelia/values.yaml
T
panxiao81 47042d4df4
yaml / yaml (push) Successful in 20s
ansible / collection-test (push) Successful in 1m10s
ansible / lint (push) Successful in 13m9s
完善内存监控并迁移 Grafana 内网入口
Co-authored-by: panxiao81 <[email protected]>
2026-09-16 12:47:52 +00:00

289 lines
13 KiB
YAML

# Authelia — official Helm chart (authelia/authelia). Config-as-code lives here.
# Install: helm upgrade --install authelia authelia/authelia -n authelia --create-namespace -f values.yaml
# Exposure: via cloudflared (auth.ddupan.top -> authelia.authelia.svc:9091), NOT the chart ingress.
# Secrets: NONE are inline here. All seven live in Kubernetes Secrets and are referenced
# by path — see secret.example.yaml. This file is safe to commit.
image:
tag: '4.39.20'
# We expose via cloudflared, so the chart's own ingress stays off.
ingress:
enabled: false
# Mount our own Secret instead of letting the chart generate one from inline
# `value:` fields. Its keys are exactly the ones the chart used to generate, plus
# identity_providers.oidc.jwks.main.pem for the OIDC signing key — so every
# `path:` below resolves, and no key material changed when this was introduced
# (the Secret was built from the live chart-generated one). See secret.example.yaml.
secret:
existingSecret: authelia-secrets
# The JWKS signing key needs its OWN Secret, mounted separately.
#
# ⚠ WHY not just add a 7th key to authelia-secrets: the chart projects the
# existingSecret volume with an explicit `items:` list containing only the six
# keys it generates. An extra key is stored in the Secret but NEVER mounted, so
# the file is missing at runtime and Authelia dies with
# "no such file or directory" — which cascades into every other config option
# appearing "required". Verified the hard way 2026-07-28.
#
# additionalSecrets mounts at {secret.mountPath}/{key} = /secrets/authelia-oidc-jwks
additionalSecrets:
authelia-oidc-jwks:
items:
- key: 'main.pem'
path: 'main.pem'
configMap:
authentication_backend:
password_reset:
disable: true # AD owns passwords (reset via ADUC / Windows)
refresh_interval: '5 minutes'
ldap:
enabled: true
implementation: 'activedirectory'
# MUST be the hostname, NOT 192.168.10.5: dc1's LDAPS cert is issued by
# OpenBao's ACME with a DNS SAN only (no IP SAN), so connecting by IP fails
# verification with "IP address mismatch". In-cluster pods resolve this name.
address: 'ldaps://dc1.ad.ddupan.top:636'
tls:
# Was skip_verify: true ("DC self-signed cert; add CA to trust later").
# Later arrived: dc1 now serves a cert from the OpenBao internal CA, which
# is mounted below via certificates.values, so the bind is really verified.
skip_verify: false
base_dn: 'DC=ad,DC=ddupan,DC=top'
additional_users_dn: 'CN=Users'
additional_groups_dn: 'CN=Users'
user: 'CN=svc-authelia,CN=Users,DC=ad,DC=ddupan,DC=top'
password:
# From the authelia-secrets Secret (secret.example.yaml). Relative path
# resolves to {secret.mountPath}/{secret.existingSecret}/{path}.
path: 'authentication.ldap.password.txt'
# Authorization endpoints. `ext-authz` is what Envoy Gateway's SecurityPolicy calls
# (Envoy's HTTP ExtAuthz filter). Declared explicitly rather than relying on the
# default set, so the contract with ../../platform/envoy-gateway is visible here.
server:
endpoints:
authz:
ext-authz:
implementation: 'ExtAuthz'
access_control:
default_policy: 'two_factor' # require a second factor for every request
rules:
# ⚠ ORDER MATTERS — Authelia evaluates top-down, FIRST MATCH WINS. This bypass
# must precede the two_factor rule below or the API stays unreachable.
#
# WHY BYPASS: forward-auth intercepts every request, including API calls that
# carry a valid NetBox token — Authelia has no idea what a NetBox token is, sees
# no session cookie, and 302s the caller to the login portal. That breaks the
# entire point of a source of truth (Ansible/Terraform reading from it).
#
# This is NOT unauthenticated access: NetBox enforces its own token auth on these
# paths and LOGIN_REQUIRED makes an anonymous call return 403. We are choosing
# which authenticator guards the API — NetBox's tokens — not removing one.
- domain: 'netbox.ad.ddupan.top'
resources:
- '^/api/'
- '^/graphql/'
policy: 'bypass'
# Everything else on NetBox: browser traffic. default_policy would already force
# 2FA, but this rule additionally restricts WHO gets in — without a subject match
# any AD account passing 2FA would be auto-provisioned a NetBox user.
- domain: 'netbox.ad.ddupan.top'
policy: 'two_factor'
subject:
- 'group:netbox-admins'
# Second factors. Both are on by chart default; we brand them and enable passkeys.
totp:
disable: false
issuer: 'ddupan.top' # shown in authenticator apps
webauthn:
disable: false
display_name: 'ddupan.top' # shown in the browser passkey/security-key prompt
enable_passkey_login: true # allow usernameless passkey login at the portal
session:
expiration: '1 hour'
inactivity: '5 minutes'
cookies:
- subdomain: 'auth'
domain: 'ddupan.top' # -> https://auth.ddupan.top, SSO across *.ddupan.top
regulation:
max_retries: 3
find_time: '2 minutes'
ban_time: '5 minutes'
storage:
encryption_key:
path: 'storage.encryption.key'
postgres:
enabled: true
address: 'tcp://shared-postgresql.shared-db.svc.cluster.local:5432'
database: 'authelia'
username: 'authelia'
password:
path: 'storage.postgres.password.txt'
notifier:
# Sends via the in-cluster Postfix+OAuth relay (see ../smtp-relay/). Plain hop on
# :25 — the relay handles STARTTLS + OAuth to Microsoft 365. No auth to the relay
# (it trusts the pod network).
smtp:
enabled: true
address: 'smtp://smtp-relay.smtp-relay.svc.cluster.local:25'
sender: 'Authelia <[email protected]>'
subject: '[Authelia] {title}'
disable_require_tls: true
disable_starttls: true
startup_check_address: '[email protected]'
username: ''
password:
disabled: true # relay needs no auth; stop Authelia attempting SMTP AUTH
# OIDC provider — replaces Keycloak as the SSO/OIDC issuer (https://auth.ddupan.top).
# Crypto material generated with `authelia crypto` (hmac_secret, RSA JWKS key). Client
# secrets are stored HASHED here (pbkdf2-sha512); the RP (Gitea) holds the plaintext.
identity_providers:
oidc:
enabled: true
hmac_secret:
path: 'identity_providers.oidc.hmac.key'
# Authelia 4.39 only returns standard claims from the UserInfo endpoint by
# default. Gitea reads email/preferred_username from the ID Token, so we
# inject them there via a claims policy referenced by the client below.
claims_policies:
gitea:
id_token:
- 'preferred_username'
- 'email'
- 'email_verified'
- 'name'
- 'groups'
# Grafana maps AD groups -> roles from the `groups` claim; inject it (and
# profile/email) into the ID Token so role_attribute_path can resolve.
grafana:
id_token:
- 'preferred_username'
- 'email'
- 'email_verified'
- 'name'
- 'groups'
# NOTE: there is deliberately no `netbox` claims policy. NetBox was migrated
# off OIDC to forward-auth (../netbox/securitypolicy.yaml) precisely because
# NetBox has no SSO group->role mapping — see netbox/README.md.
# OpenBao maps user_claim=preferred_username and groups_claim=groups onto
# policies; inject those (Authelia returns only standard claims by default).
openbao:
id_token:
- 'preferred_username'
- 'email'
- 'email_verified'
- 'name'
- 'groups'
jwks:
- key_id: 'main'
algorithm: 'RS256'
use: 'sig'
key:
# ⚠ WHY path and NOT value: the chart inlines a `value:` jwks key
# straight into the ConfigMap (files/configuration.oidc.jwk.yaml), so
# the OIDC SIGNING KEY ends up in a ConfigMap in plaintext. `path:`
# reads it from the mounted Secret instead.
#
# NOTE the two different mount points: the existingSecret volume lands
# at /secrets/internal (not /secrets/<secretName>), while each
# additionalSecrets entry lands at /secrets/<its own name>.
path: '/secrets/authelia-oidc-jwks/main.pem'
clients:
- client_id: 'gitea'
client_name: 'Gitea'
# pbkdf2-sha512 hash of the plaintext secret Gitea holds (gitea-keycloak-secret).
client_secret: '$pbkdf2-sha512$310000$M7VHgkBsYT.PDUH99k4JWw$qI6vVq1zDp.3z2oNecBP5bwzPu.XHtmA.tGW4osvHlp1rwZISak5pG7.fctHa5eNdeSEIuhaZ6HSeajtPzSkOw'
public: false
authorization_policy: 'two_factor' # SSO logins also require a second factor
claims_policy: 'gitea' # inject email/preferred_username into the ID Token
require_pkce: false
token_endpoint_auth_method: 'client_secret_basic'
redirect_uris:
- 'https://git.ddupan.top/user/oauth2/authelia/callback'
scopes:
- 'openid'
- 'profile'
- 'email'
- 'groups'
userinfo_signed_response_alg: 'none'
- client_id: 'grafana'
client_name: 'Grafana'
# pbkdf2-sha512 hash of the plaintext secret Grafana holds (grafana-oidc Secret).
# Generate the pair: authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72
client_secret: '$pbkdf2-sha512$310000$Hhni5VBeqfz3IM1ULxbKbQ$o/Q7xRp82OI2Y43qSpGZig8Md3uMLkm6SGViJ6XszMLw2MNZYYJizOyQfRLvQvGz7Q1p5DK2v10lOfdhs8gHpg'
public: false
authorization_policy: 'two_factor' # SSO logins also require a second factor
claims_policy: 'grafana' # inject groups/email into the ID Token
require_pkce: false
token_endpoint_auth_method: 'client_secret_basic'
redirect_uris:
- 'https://grafana.ad.ddupan.top/login/generic_oauth'
scopes:
- 'openid'
- 'profile'
- 'email'
- 'groups'
userinfo_signed_response_alg: 'none'
- client_id: 'openbao'
client_name: 'OpenBao'
# pbkdf2-sha512 hash; OpenBao holds the plaintext (its oidc config / vault).
# Regenerate: authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72
client_secret: '$pbkdf2-sha512$310000$un1B3DyN5dgvwfedazLFtw$ORSxfE4EkkSfSUtXGERV5Wmzxnmsw8hJw37frksHgbYFHppRaHVAfpaUxQ/2XCXgVefyVfMxU8K.FcgBC7c35A'
public: false
authorization_policy: 'two_factor' # SSO logins also require a second factor
claims_policy: 'openbao' # inject groups/email into the ID Token
require_pkce: false
token_endpoint_auth_method: 'client_secret_basic'
grant_types:
- 'authorization_code' # UI + CLI (client/direct callback modes)
- 'urn:ietf:params:oauth:grant-type:device_code' # headless: bao login -method=oidc callbackmode=device
redirect_uris:
- 'https://bao.ad.ddupan.top:8200/ui/vault/auth/oidc/oidc/callback' # UI login
- 'http://localhost:8250/oidc/callback' # CLI: bao login -method=oidc
scopes:
- 'openid'
- 'profile'
- 'email'
- 'groups'
userinfo_signed_response_alg: 'none'
# Trust anchors mounted into the container and loaded by Authelia. Needed so the
# LDAPS bind to dc1 can be VERIFIED rather than skipped. Fetched from OpenBao's
# unauthenticated PKI endpoint: https://bao.ad.ddupan.top:8200/v1/pki/ca/pem
certificates:
values:
- name: 'ddupan_internal_ca.pem'
value: |
-----BEGIN CERTIFICATE-----
MIIDMzCCAhugAwIBAgIUMs0iV657yC9UhA2p2vomLIbFnzgwDQYJKoZIhvcNAQEL
BQAwITEfMB0GA1UEAxMWZGR1cGFuLnRvcCBJbnRlcm5hbCBDQTAeFw0yNjA3MjQy
MDE1MDFaFw0zNjA3MjEyMDE1MzFaMCExHzAdBgNVBAMTFmRkdXBhbi50b3AgSW50
ZXJuYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6QWlwBe6f
t7Ca3KCTvr4Pz+jVO60WrMBoEDYYM8Mp04btBHzhAQHf9Pp8+15aEW9iUcQhqqm+
2vT6H0JEhIbplyCWY6Guv0mTu8f+lvFknJIl2b3JqnMLHJKjh/rBrsE12XZ3i17M
2tCr34BWcei85IZyQl5HMW6dB8lAE6bdom+YynK4oLJdej9DD6bSyM8WcL0OsneZ
NsjwOlNMy3zjbtaH6mH71SgbFinxLp3AAAuLVe1DIKhFxuTQeVr/WaPum5y/oOsc
0gJp9If6nsC33lpRGcPLiZE9kfFZa4fPe8laCaN8q1K253qZ0rjRiDhbTAppW4Fy
r5P67h+2D+TbAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
AQH/MB0GA1UdDgQWBBSOgk1fR0qhz/Bo4wD9g2BnOAzDXzAfBgNVHSMEGDAWgBSO
gk1fR0qhz/Bo4wD9g2BnOAzDXzANBgkqhkiG9w0BAQsFAAOCAQEANm5kKkts1Ar2
7IlS+TxLFrZ/C9yhIdGcBk2SL5E+5E8S3skQWLEPGLRwvV4RmiB8gQ2V6UyGLrCx
1MuuSmCDaSYL9G66sGX1MIHlQ0F0bHIOxxtsTwIYzb5Sl8h3MfsARabmOhE3xUkn
jaAT9YUweHhjF4vi0U1Q4F8oOSvu4eJp5dMx1r7b2bLN90A1xh9sfdkEenSBX0tm
xK82ROYXI2Ejv/EO+lPUIn3jfqbqrS2itw75Xz/ECHjIfSxvW98puP69U54a1gf6
gWdXslr0pGkyMHqxw4dmaecpK0QK3jvqCNycNwNBfMdCypS2QRy03adcUosEAP3O
LZU7Kd8aeg==
-----END CERTIFICATE-----