# Authelia access rules — the additions, as text **This file is documentation, not configuration. Never commit the real `~/authelia/configuration.yml`, and never generate a replacement for it.** It contains the AD bind account, session secrets and the Duo integration for every service on the host. The four hostnames below are the only part of it this project touches. ## What has to change Four hostnames join the existing `HTTPS_UserAccess` `two_factor` rule in `~/authelia/configuration.yml`, under `access_control.rules`: | Hostname | Phase | Serves | |---|---|---| | `lf.yokogawa.tech` | 2 | Langfuse — traces, prompts, eval runs | | `cube.yokogawa.tech` | 5 | Cube semantic layer, playground and REST API — **not essential**, see below | | `api.yokogawa.tech` | 6 | `ai-api` FastAPI | | `ai.yokogawa.tech` | 7 | `ai-web` operator UI | Phase 9 adds no hostname. It adds one **path-scoped rule** on an existing one — see "Phase 9: the document publisher rule" below. The shape of the addition — the domain list on the existing trailing rule gains these entries, the policy and subject stay exactly as they already are: ```yaml access_control: rules: # ... existing rules unchanged ... - domain: # ... existing domains unchanged ... - lf.yokogawa.tech # added , AI PoC Phase 2 - cube.yokogawa.tech # added , AI PoC Phase 5 - api.yokogawa.tech # added , AI PoC Phase 6 - ai.yokogawa.tech # added , AI PoC Phase 7 policy: two_factor subject: - group:HTTPS_UserAccess ``` Add each hostname at the phase that needs it. Every domain added here must also have a Caddyfile block with `import authelia` (`caddy/ai-routes.caddy`), and every Caddyfile block must have a rule here. One without the other is a hole. **`cube.yokogawa.tech` is the one to drop first** if the host is being tidied or the hostname is wanted for something else. Nothing depends on it — `ai-api` reaches Cube as `cube:4000` over the proxy network and never by name, and the operator UI never touches Cube. It exists so an engineer can open the playground to hand-verify a measure, which an SSH tunnel does equally well. Removing it means deleting the Caddy block **and** this domain; batch that with an Authelia restart that is happening anyway rather than spending an all-user logout on it. The same note is on the host, in `~/Caddyfile` above the block and inline on this rule. **Applied on lin001:** `lf` on 2026-08-20; `cube`, `api` and `ai` on 2026-08-27, in one Authelia restart. Backup `~/authelia/configuration.yml.bak-ai-20260827`. All four now return 302 to the auth portal. Between the Caddy blocks going in and this rule landing, the three new hostnames returned **403** — Caddy serving a hostname Authelia has no rule for means `default_policy: deny`, which is the safe direction but is not obvious from the status code alone. `verify.sh` names that case explicitly. ## Phase 9: the document publisher rule Operator document upload splits the API in two. Anyone in `HTTPS_UserAccess` may ask a question and upload a document for review. **Approving** a document — which is what makes it citable, and what decides whether a superseded revision stops being citable — needs a second group, `AI_DocPublishers`. ```yaml access_control: rules: # ... existing rules unchanged ... # MUST come BEFORE the general api.yokogawa.tech rule. Authelia applies the # FIRST matching rule and stops. Below it, this rule is dead and every # authenticated user can approve a procedure revision. - domain: api.yokogawa.tech resources: - '^/docs/.*' policy: two_factor subject: - group:AI_DocPublishers # added , AI PoC Phase 9 # ... the existing trailing rule, unchanged, still carries # api.yokogawa.tech for everyone in HTTPS_UserAccess ... ``` Three things about this rule specifically: - **`AI_DocPublishers` must be created in AD with DIRECT membership.** The same trap as `HTTPS_UserAccess`: a user inside a nested group is silently denied, with no useful log line. `svc-authelia` is read-only and cannot fix it. - **It is not the only check.** `ai-api` re-reads `Remote-Groups` and returns 403 on approve, reject and supersede. This rule protects the whole `/docs` path; the API protects the three operations that matter, and survives this rule being reordered or dropped in a future edit of a file nobody diffs. - **Verify it by calling the API directly**, as a user who is authenticated but not a publisher. The UI hides the buttons from that user, which proves nothing at all: ```bash curl -si https://api.yokogawa.tech/docs/uploads//approve -X POST -H 'Content-Type: application/json' -d '{}' # expect 403 ``` ## How to apply it ```bash # 1. Back up first. There are plenty of .bak-* precedents on the host. sudo cp ~/authelia/configuration.yml ~/authelia/configuration.yml.bak-ai-$(date +%Y%m%d) # 2. Edit with sudo - the file is root-owned. ~/apply_rule.py rewrites the # trailing rule if you prefer it to hand-editing. sudo nano ~/authelia/configuration.yml # 3. ANNOUNCE FIRST - this logs out every active user on every service. docker compose -f ~/authelia-compose.yml restart authelia # 4. Verify. "Up" is not proof. curl -sI https://ai.yokogawa.tech # expect 302 -> auth portal docker logs --tail 50 authelia ``` ## Things that bite - **Restarting Authelia logs out every active user on the host**, including whoever is mid-demo on Grafana. Announce it, and batch the domain additions so you restart once per phase rather than once per hostname. - **AD group membership must be DIRECT.** Authelia resolves direct membership only; a user inside a nested group silently gets denied with no useful log line. Before Phase 7, confirm the demo operator account is a direct member of `HTTPS_UserAccess` and is Duo-enrolled. `svc-authelia` is read-only and cannot fix membership for you. - **Rule order is a security control, not a style choice.** First match wins. A path-scoped rule placed after the domain rule it narrows is inert, and nothing warns you — the service keeps working, for everybody. - **A missing rule fails open at the wrong layer.** Caddy will happily serve a hostname that has `import authelia` before the rule exists — Authelia then applies its default policy. Add the rule in the same change as the Caddyfile block and verify the 302 before telling anyone the URL. - Restarting Authelia is also the supported way to refresh someone's group membership after an AD change.