bind-lane.py gains per-lane Secret keys. Authelia keeps its bind user in authelia-config, so setup refuses unless the live configuration binds uid=svc-authelia, and only the ldap_password key is decoded. The ESO manifest merges ldap_password alone into authelia-secrets. The tests are parametrized per lane (12). tools/service-binds is now listed in security-tools.json, which fixes the index test that failed after the pilot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 896183@bnt-lap001 Assistant-Session: 3a18c01a-3205-4d02-94db-9efff25649a2 |
||
|---|---|---|
| .. | ||
| tests | ||
| bind-eso.yaml | ||
| configmap.yaml | ||
| create-secrets.sh | ||
| deployment.yaml | ||
| ingress.yaml | ||
| pvc.yaml | ||
| README.md | ||
| smtp-custody.yaml | ||
| smtp-networkpolicy.yaml | ||
T05b — Authelia (Authentication Frontend)
Exercise status: unknown for the procedures in this runbook; no per-procedure successful-run receipt with operator attribution was established in the 2026-09-05 review. See procedure inventory.
Authelia is the password-authentication frontend for the net-kingdom SSO stack. It acts as an upstream OIDC provider for KeyCape: users are redirected here to enter their password; Authelia validates credentials against LLDAP and returns an authorization code to KeyCape, which then performs the MFA step via privacyIDEA.
Important: Authelia's access control policy is set to one_factor (password only).
MFA is handled exclusively by KeyCape + privacyIDEA. Do not change this to two_factor.
Prerequisites
- T05a complete (LLDAP is Running and healthy, application groups created)
bootstrap/gen-secrets.shrun andsecrets/authelia/secrets.envpopulated in KeePassXCkubectlconfigured with cluster access
Apply order
# 1. Create K8s Secret
cd sso-mfa/k8s/authelia
chmod +x create-secrets.sh
./create-secrets.sh
# 2. Apply manifests (order matters)
kubectl apply -f pvc.yaml
kubectl apply -f configmap.yaml
kubectl apply -f deployment.yaml
kubectl apply -f ingress.yaml
# 3. Wait for pod to be ready
# The startup probe allows 90 s for the initial LLDAP connection.
kubectl rollout status deployment/authelia -n sso --timeout=120s
Configuration
All non-sensitive configuration is in configmap.yaml (mounted as configuration.yml).
Sensitive values are injected via *_FILE environment variables pointing to
Secret-mounted files (see deployment.yaml env section).
Key config points:
authentication_backend.ldap.url— points to LLDAP cluster-internal serviceidentity_providers.oidc.clients[0].redirect_uris— must match CP-NK-004 (kc.coulomb.social)session.domain— set to parent domaincoulomb.socialso cookies are valid across bothauth.coulomb.socialandkc.coulomb.socialdefault_redirection_url—https://users.coulomb.socialwhen the visitor opened the portal with no follow-up. A providedrdstill winsaccess_control.default_policy: one_factor— fleet default; MFA is not Authelia’s jobaccess_control.rules— domain allowlists by LLDAP group (see below)
Domain rules (app operator groups)
Authelia evaluates rules top-down; first match wins. A rule that matches
domain but not subject is skipped, so non-members would fall through to
default_policy and stay allowed unless a later domain-only deny rule exists.
Pattern used for activity-core public hosts (NK-WP-0021):
access_control:
default_policy: one_factor
rules:
- domain: app.example.com
subject: "group:app-operators"
policy: one_factor
- domain: app.example.com
policy: deny
| Host | Required LLDAP group |
|---|---|
activity.coulomb.social |
activity-core-operators |
temporal.coulomb.social |
activity-core-operators |
Membership: sso-mfa/k8s/lldap/OPERATOR-GROUPS.md. Do not set two_factor
on these rules. Do not invent KeyCape OIDC clients for Traefik ForwardAuth
apps — the edge already calls Authelia /api/verify.
Secrets managed
| Secret name | Keys | Purpose |
|---|---|---|
authelia-secrets |
jwt_secret |
Session JWT signing |
session_secret |
Session cookie encryption | |
storage_encryption_key |
SQLite database encryption | |
ldap_password |
LDAP bind password (= LLDAP_LDAP_USER_PASS) |
|
oidc_hmac_secret |
OIDC HMAC signing | |
oidc_issuer_private_key |
RSA-2048 private key for OIDC token signing | |
keycape_client_secret_hash |
Bcrypt hash of AUTHELIA_KEYCAPE_CLIENT_SECRET |
create-secrets.sh reads plaintext values from secrets/authelia/secrets.env and
secrets/lldap/secrets.env as private literal input (requires Python 3 + bcrypt).
First creation stores a new signing key privately in authelia/oidc_private_key.pem
unless an explicit private absolute key path is supplied. Existing deployments
preserve their issuer key and matching bcrypt hash. Normal reapplication verifies
matching values; session rotation must explicitly select AUTHELIA_SESSION_SECRET.
See service Secret custody and rotation
for conflict handling, recovery custody and native acceptance limits.
Storage
authelia-data PVC (1 Gi, ReadWriteOnce) holds:
db.sqlite3— SQLite database (user sessions, regulation data)notification.txt— notification log (filesystem notifier)
Back this PVC up alongside the LLDAP PVC.
Verify
# Pod status
kubectl get pod -n sso -l app.kubernetes.io/name=authelia
# Health check
kubectl run -n sso --rm -it auth-test --image=busybox --restart=Never \
-- wget -qO- http://authelia.sso.svc.cluster.local:9091/api/health
# OIDC discovery (should return issuer + endpoints)
curl -s https://auth.coulomb.social/.well-known/openid-configuration | jq .
4.39 compatibility and regression check
KeyCape needs preferred_username in the signed upstream ID token for its
directory and MFA lookup. Authelia 4.39 requires the explicit keycape
claims policy in configmap.yaml; deploy it together with the pinned image.
KeyCape's in-cluster token requests must also carry the public HTTPS forwarded
scheme and host (KeyCape 3b0446e or later). Neither a health check nor an
authorization redirect exercises these requirements.
Run the isolated token regression with an Authelia 4.39.28 binary and Python
requests, PyYAML, and cryptography installed:
python3 sso-mfa/k8s/authelia/tests/probe_claims.py --authelia-bin /path/to/authelia
It uses disposable local users, keys and SQLite databases, checks real signed authorization-code tokens with and without the policy, and terminates the scratch processes. It uses a file backend, so it does not prove LDAP email lookup. Live acceptance also requires a fresh plus-addressed email sign-in through KeyCape to both Vergabe and the account portal, with successful callback and token issuance evidence.
Before a 4.38 → 4.39 rollout, stop Authelia and preserve the SQLite database
and any sidecar files. Keep the previous ConfigMap and image reference too.
Rollback requires stopping 4.39 and restoring all three: database, ConfigMap,
and image. The migrated database and 4.39 claims policy cannot be used by
4.38. See NK-WP-0041 for the exercised rollout and backup receipt.
Platform reset mail — NK-WP-0047 (prepared, not active)
The csoc-platform-mail review branch replaces the filesystem notifier with native SMTP from platform@coulomb.social through IONOS submission/STARTTLS. Its password is a mounted file, never ConfigMap/env plaintext. smtp-custody.yaml projects only SMTP_PASSWORD from the existing platform-owned mailbox entry into sso/authelia-smtp. A dedicated sso/authelia-smtp-eso identity must first be admitted by railiance-platform (RPF-WP-0052, CCR-2026-0035). Do not reuse telemetry's role or copy its Secret.
Order: founder approves exact custody/rollout; attended owner admission; apply service account/SecretStore/ExternalSecret with dry-run/diff; wait Ready; apply smtp-networkpolicy.yaml (Authelia only, public IPv4 TCP587; existing DNS/LDAP rules remain); compare live ConfigMap/deployment for unrelated drift; native Authelia validate; apply notifier/mount change and restart Authelia with headroom/recovery checks. Do not apply the changed ConfigMap/deployment while the runtime Secret is absent. Startup SMTP check stays enabled, TLS/certificate verification mandatory. SMTP startup check does not send mail. Request a NEW reset through the user's own browser, then verify actual inbox receipt and completed sign-in. Do not read old filesystem reset links or put fresh links into logs/evidence.
Rollback notifier/mount to pre-change owner revision, preserving Authelia SQLite and all existing authentication Secret references. Record failed send privately using redacted outcome only. This does not reset a user's password by itself or add automated ReichelAg protocol email sending. Reference: https://www.authelia.com/configuration/notifications/smtp/