diff --git a/apps/base/arrstack/arrproxy/api-deployment.yaml b/apps/base/arrstack/arrproxy/api-deployment.yaml index 17228b8..5ae82b9 100644 --- a/apps/base/arrstack/arrproxy/api-deployment.yaml +++ b/apps/base/arrstack/arrproxy/api-deployment.yaml @@ -7,7 +7,7 @@ metadata: annotations: # Wave 2: serve only after the wave-1 migrate Job completes. argocd.argoproj.io/sync-wave: "2" - secret.reloader.stakater.com/reload: "arrproxy-pepper,arrproxy-db-app,sonarr-apikey,radarr-apikey,prowlarr-apikey" + secret.reloader.stakater.com/reload: "arrproxy-pepper,arrproxy-admin-token,arrproxy-db-app,sonarr-apikey,radarr-apikey,prowlarr-apikey" spec: replicas: 2 selector: @@ -33,7 +33,7 @@ spec: type: RuntimeDefault containers: - name: api - image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-api:v0.1.0 + image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-api:v0.2.0 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 @@ -59,6 +59,15 @@ spec: secretKeyRef: name: arrproxy-pepper key: pepper + # Machine-mint admin bearer, synced from Vault KV via the + # arrproxy-admin-token VSO. Gates the /api/admin/ route that + # oauth2-proxy intentionally skip-auths so OpenBao on the VMs can + # mint tokens against arrproxy's own bearer. + - name: ARRPROXY_ADMIN_TOKEN + valueFrom: + secretKeyRef: + name: arrproxy-admin-token + key: token # DSN assembled from the CNPG-generated arrproxy-db-app Secret; # $(VAR) expansion resolves the two env entries defined above it. - name: ARRPROXY_DB_USER diff --git a/apps/base/arrstack/arrproxy/oauth2-proxy-configmap.yaml b/apps/base/arrstack/arrproxy/oauth2-proxy-configmap.yaml index a7eee62..8cae392 100644 --- a/apps/base/arrstack/arrproxy/oauth2-proxy-configmap.yaml +++ b/apps/base/arrstack/arrproxy/oauth2-proxy-configmap.yaml @@ -33,9 +33,14 @@ data: # set-xauthrequest is intentionally NOT set -- it only populates auth_request # *response* headers, which never reach an --upstreams-proxied backend. OAUTH2_PROXY_PASS_USER_HEADERS: "true" - # Bypass auth ONLY for the *arr proxy API (//api...): this matches - # /sonarr/api but NOT /api/tokens or /api/me (which stay authenticated). - OAUTH2_PROXY_SKIP_AUTH_REGEX: "^/[^/]+/api" + # Bypass auth for the *arr proxy API (//api...) and the machine-mint + # admin route (/api/admin/...). The first matches /sonarr/api; the second + # matches /api/admin/ only -- both routed to the arrproxy-api upstream by the + # catch-all /api/ prefix above. /api/admin/ is protected by arrproxy's OWN + # ARRPROXY_ADMIN_TOKEN bearer (OpenBao on the VMs reaches it via the ingress), + # so it is intentionally oauth-skipped. /api/tokens and /api/me are NOT + # matched and stay oauth-authenticated. + OAUTH2_PROXY_SKIP_AUTH_REGEX: "^/[^/]+/api,^/api/admin/" OAUTH2_PROXY_EMAIL_DOMAINS: "*" # Authentik hardcodes email_verified=false in the id_token; without this # oauth2-proxy rejects the session ("email ... isn't verified") -> 500 on diff --git a/apps/base/arrstack/arrproxy/ui-deployment.yaml b/apps/base/arrstack/arrproxy/ui-deployment.yaml index f216f1f..9e62343 100644 --- a/apps/base/arrstack/arrproxy/ui-deployment.yaml +++ b/apps/base/arrstack/arrproxy/ui-deployment.yaml @@ -31,7 +31,7 @@ spec: type: RuntimeDefault containers: - name: ui - image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-ui:v0.1.0 + image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-ui:v0.2.0 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 diff --git a/apps/base/arrstack/arrproxy/vaultstaticsecret.yaml b/apps/base/arrstack/arrproxy/vaultstaticsecret.yaml index 8b24a28..34dc111 100644 --- a/apps/base/arrstack/arrproxy/vaultstaticsecret.yaml +++ b/apps/base/arrstack/arrproxy/vaultstaticsecret.yaml @@ -25,6 +25,33 @@ spec: type: kv-v2 vaultAuthRef: default --- +# Machine-mint admin bearer token. Seeded (openssl rand) at +# kv/kubernetes/namespace/arrstack/default/arrproxy-admin-token (key: token) and +# shared as the source of truth with the future Vault engine. The default k8s +# role's templated policy already grants read on +# kv/data/kubernetes/namespace/{{sa_namespace}}/{{sa_name}}/* for the +# arrstack/default ServiceAccount, so no terraform-vault change is needed. VSO +# syncs it into the arrproxy-admin-token Secret consumed by arrproxy-api as +# ARRPROXY_ADMIN_TOKEN to gate the bearer-protected /api/admin/ route. +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: arrproxy-admin-token + namespace: arrstack + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + destination: + create: true + name: arrproxy-admin-token + overwrite: true + hmacSecretData: true + mount: kv + path: kubernetes/namespace/arrstack/default/arrproxy-admin-token + refreshAfter: 5m + type: kv-v2 + vaultAuthRef: default +--- # Authentik OIDC client for the arrstack front door (client_id, client_secret, # cookie_secret), created by terraform-authentik at # kv/kubernetes/namespace/arrstack/default/oauth-credentials. VSO syncs it into