From 108d1cb2139f3caba19ee313dd947ba99266f242 Mon Sep 17 00:00:00 2001 From: Unkin Agent Date: Tue, 18 Aug 2026 20:03:18 +1000 Subject: [PATCH] arrstack: set *arr AuthenticationMethod=External (proxy-trusted) (#382) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why The *arr UIs reached through **arrproxy** were prompting **"Authentication Required"**. Sonarr v4 (and Radarr/Prowlarr on the same Servarr auth code) refuses remote access when `AuthenticationMethod=None`, so the web UI kept demanding a login even though **arrproxy + oauth2-proxy already authenticate every user at the front door**. That is a double prompt with no purpose. ## Change Extend the existing `apikey-init` container for **sonarr / radarr / prowlarr** to also idempotently enforce, in `/config/config.xml`: - `External` - `Enabled` Create-or-replace both elements (same idempotent sed/printf pattern already used for ``/``), without disturbing ApiKey or UrlBase. Pods use `Recreate`, so they roll and re-run the init container on apply. ## Why this is the correct, header-less fix In the Servarr v4 source, `AddExternal()` registers the **identical `NoAuthenticationHandler` as `AddNone()`** — `External` requires **no** username header (no `X-Forwarded-User` / `Remote-User`). It differs from `None` only in that it is **exempt from the None remote-access block**, so the UI stops prompting while remote access is permitted. This matters because arrproxy's `trustBoundary` deliberately **strips all inbound identity headers** and forwards only the real `X-Api-Key` to the upstream *arr — it forwards no username header. Because `External` needs none, that stripping is irrelevant and **no arrproxy change is required**. The API path is unaffected (arrproxy injects the real key; *arr API auth is key-based regardless of AuthenticationMethod). ## Validation - `kustomize build --enable-helm apps/overlays/au-syd1/arrstack` → OK (rendered init carries the auth logic for all 3 apps) - pre-commit (yamllint + all hooks) → Passed Versions in scope: sonarr 4.0.19, radarr 6.3.0, prowlarr 2.5.2 (all share the Servarr v4 auth handler). --------- Co-authored-by: unkin-agent Reviewed-on: https://git.unkin.net/unkin/argocd-apps/pulls/382 Co-authored-by: Unkin Agent Co-committed-by: Unkin Agent --- apps/base/arrstack/prowlarr/deployment.yaml | 21 ++++++++++++++++++--- apps/base/arrstack/radarr/deployment.yaml | 21 ++++++++++++++++++--- apps/base/arrstack/sonarr/deployment.yaml | 21 ++++++++++++++++++--- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/apps/base/arrstack/prowlarr/deployment.yaml b/apps/base/arrstack/prowlarr/deployment.yaml index 4e79607..0987f90 100644 --- a/apps/base/arrstack/prowlarr/deployment.yaml +++ b/apps/base/arrstack/prowlarr/deployment.yaml @@ -26,7 +26,10 @@ spec: # (override bootstrap): the key is minted in Vault, synced by VSO into the # prowlarr-apikey Secret, and written here. UrlBase=/prowlarr lets arrproxy # forward arrstack.unkin.net/prowlarr/... with the prefix preserved (no 307). - # Runs as root to fix ownership; touches only and . + # Runs as root to fix ownership; touches only , , and + # =External + . External makes + # the *arr defer UI login to arrproxy/oauth2-proxy (same no-auth request + # handler as None, but permits remote access without prompting). - name: apikey-init image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/busybox:1.37.0 imagePullPolicy: IfNotPresent @@ -50,9 +53,11 @@ spec: ;; esac URL_BASE=/prowlarr + AUTH_METHOD=External + AUTH_REQUIRED=Enabled CFG=/config/config.xml if [ ! -f "$CFG" ]; then - printf '\n %s\n %s\n\n' "$API_KEY" "$URL_BASE" > "$CFG" + printf '\n %s\n %s\n %s\n %s\n\n' "$API_KEY" "$URL_BASE" "$AUTH_METHOD" "$AUTH_REQUIRED" > "$CFG" else if grep -q '' "$CFG"; then sed -i "s|[^<]*|${API_KEY}|" "$CFG" @@ -64,10 +69,20 @@ spec: else sed -i "s||\n ${URL_BASE}|" "$CFG" fi + if grep -q '' "$CFG"; then + sed -i "s|[^<]*|${AUTH_METHOD}|" "$CFG" + else + sed -i "s||\n ${AUTH_METHOD}|" "$CFG" + fi + if grep -q '' "$CFG"; then + sed -i "s|[^<]*|${AUTH_REQUIRED}|" "$CFG" + else + sed -i "s||\n ${AUTH_REQUIRED}|" "$CFG" + fi fi chown 1000:1000 "$CFG" chmod 600 "$CFG" - echo "config-init: and =${URL_BASE} enforced from Vault" + echo "config-init: , =${URL_BASE}, =${AUTH_METHOD}, =${AUTH_REQUIRED} enforced from Vault" resources: requests: cpu: 50m diff --git a/apps/base/arrstack/radarr/deployment.yaml b/apps/base/arrstack/radarr/deployment.yaml index 7a09cf1..47bd03a 100644 --- a/apps/base/arrstack/radarr/deployment.yaml +++ b/apps/base/arrstack/radarr/deployment.yaml @@ -26,7 +26,10 @@ spec: # (override bootstrap): the key is minted in Vault, synced by VSO into the # radarr-apikey Secret, and written here. UrlBase=/radarr lets arrproxy # forward arrstack.unkin.net/radarr/... with the prefix preserved (no 307). - # Runs as root to fix ownership; touches only and . + # Runs as root to fix ownership; touches only , , and + # =External + . External makes + # the *arr defer UI login to arrproxy/oauth2-proxy (same no-auth request + # handler as None, but permits remote access without prompting). - name: apikey-init image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/busybox:1.37.0 imagePullPolicy: IfNotPresent @@ -50,9 +53,11 @@ spec: ;; esac URL_BASE=/radarr + AUTH_METHOD=External + AUTH_REQUIRED=Enabled CFG=/config/config.xml if [ ! -f "$CFG" ]; then - printf '\n %s\n %s\n\n' "$API_KEY" "$URL_BASE" > "$CFG" + printf '\n %s\n %s\n %s\n %s\n\n' "$API_KEY" "$URL_BASE" "$AUTH_METHOD" "$AUTH_REQUIRED" > "$CFG" else if grep -q '' "$CFG"; then sed -i "s|[^<]*|${API_KEY}|" "$CFG" @@ -64,10 +69,20 @@ spec: else sed -i "s||\n ${URL_BASE}|" "$CFG" fi + if grep -q '' "$CFG"; then + sed -i "s|[^<]*|${AUTH_METHOD}|" "$CFG" + else + sed -i "s||\n ${AUTH_METHOD}|" "$CFG" + fi + if grep -q '' "$CFG"; then + sed -i "s|[^<]*|${AUTH_REQUIRED}|" "$CFG" + else + sed -i "s||\n ${AUTH_REQUIRED}|" "$CFG" + fi fi chown 1000:1000 "$CFG" chmod 600 "$CFG" - echo "config-init: and =${URL_BASE} enforced from Vault" + echo "config-init: , =${URL_BASE}, =${AUTH_METHOD}, =${AUTH_REQUIRED} enforced from Vault" resources: requests: cpu: 50m diff --git a/apps/base/arrstack/sonarr/deployment.yaml b/apps/base/arrstack/sonarr/deployment.yaml index 230208a..9ce95a6 100644 --- a/apps/base/arrstack/sonarr/deployment.yaml +++ b/apps/base/arrstack/sonarr/deployment.yaml @@ -29,7 +29,10 @@ spec: # (override bootstrap): the key is minted in Vault, synced by VSO into the # sonarr-apikey Secret, and written here. UrlBase=/sonarr lets arrproxy # forward arrstack.unkin.net/sonarr/... with the prefix preserved (no 307). - # Runs as root to fix ownership; touches only and . + # Runs as root to fix ownership; touches only , , and + # =External + . External makes + # the *arr defer UI login to arrproxy/oauth2-proxy (same no-auth request + # handler as None, but permits remote access without prompting). - name: apikey-init image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/busybox:1.37.0 imagePullPolicy: IfNotPresent @@ -53,9 +56,11 @@ spec: ;; esac URL_BASE=/sonarr + AUTH_METHOD=External + AUTH_REQUIRED=Enabled CFG=/config/config.xml if [ ! -f "$CFG" ]; then - printf '\n %s\n %s\n\n' "$API_KEY" "$URL_BASE" > "$CFG" + printf '\n %s\n %s\n %s\n %s\n\n' "$API_KEY" "$URL_BASE" "$AUTH_METHOD" "$AUTH_REQUIRED" > "$CFG" else if grep -q '' "$CFG"; then sed -i "s|[^<]*|${API_KEY}|" "$CFG" @@ -67,10 +72,20 @@ spec: else sed -i "s||\n ${URL_BASE}|" "$CFG" fi + if grep -q '' "$CFG"; then + sed -i "s|[^<]*|${AUTH_METHOD}|" "$CFG" + else + sed -i "s||\n ${AUTH_METHOD}|" "$CFG" + fi + if grep -q '' "$CFG"; then + sed -i "s|[^<]*|${AUTH_REQUIRED}|" "$CFG" + else + sed -i "s||\n ${AUTH_REQUIRED}|" "$CFG" + fi fi chown 1000:1000 "$CFG" chmod 600 "$CFG" - echo "config-init: and =${URL_BASE} enforced from Vault" + echo "config-init: , =${URL_BASE}, =${AUTH_METHOD}, =${AUTH_REQUIRED} enforced from Vault" resources: requests: cpu: 50m