Skip to content

arr-stack SSO Implementation Guide

This guide documents how to add Authentik forward auth to arr-stack services.

General Pattern: See Authentik Forward Auth Pattern for the reusable template.

Overview

arr-stack apps (Sonarr, Radarr, Jellyseerr, etc.) don't support native LDAP/OIDC. We use Authentik forward auth via K8s Ingress to control access.

Architecture:

User → jellyseerr.bogocat.com → K8s Ingress (10.89.97.220)
                         ┌─────────────────────┐
                         │ nginx auth_request  │
                         │ → Authentik server  │
                         └─────────────────────┘
                     ┌─────────────┴─────────────┐
                     │                           │
              (not authenticated)         (authenticated)
                     │                           │
                     ▼                           ▼
           Redirect to Authentik        Proxy to arr-stack
           login via /outpost.go...     VM 100 (10.89.97.50)

Prerequisites

  • Authentik deployed in K8s (authentik namespace)
  • Embedded outpost configured (type: proxy)
  • DNS entries pointing to K8s ingress (10.89.97.220)
  • arr-stack running on VM 100 (10.89.97.50)

Access Groups

Group Services Members
arr-users Jellyseerr, Overseerr jake, akadmin, guest
arr-admins Sonarr, Radarr, Lidarr, Prowlarr, Bazarr, SABnzbd, Deluge jake, akadmin

Groups are already created in Authentik.

Services Reference

Service Port DNS Group Status
Jellyseerr 5056 jellyseerr.bogocat.com arr-users ✅ Done
Overseerr 5055 overseerr.bogocat.com arr-users ✅ Done
Sonarr 8989 sonarr.bogocat.com arr-admins ✅ Done
Radarr 7878 radarr.bogocat.com arr-admins ✅ Done
Lidarr 8686 lidarr.bogocat.com arr-admins ✅ Done
Prowlarr 9696 prowlarr.bogocat.com arr-admins ✅ Done
Bazarr 6767 bazarr.bogocat.com arr-admins ✅ Done
SABnzbd 8080 sabnzbd.bogocat.com arr-admins ✅ Done
Deluge 8112 deluge.bogocat.com arr-admins ✅ Done

Adding a New App (Step-by-Step)

Step 1: Create Proxy Provider in Authentik

  1. Go to http://auth.bogocat.com → Login as akadmin
  2. Navigate to Providers → Create → Proxy Provider
  3. Configure:
Field Value
Name {app-name}-proxy (e.g., sonarr-proxy)
Authorization flow default-provider-authorization-implicit-consent
Forward auth mode Forward auth (single application)
External host http://{app-name}.bogocat.com (e.g., http://sonarr.bogocat.com)

Step 2: Create Application

  1. Navigate to Applications → Create
  2. Configure:
Field Value
Name {App Name} (e.g., Sonarr)
Slug {app-name} (e.g., sonarr)
Provider Select {app-name}-proxy
  1. Click Create
  2. Click on the new application → Policy / Group / User Bindings
  3. Create BindingGroup → Select appropriate group (arr-users or arr-admins)

Step 3: Assign to Embedded Outpost

  1. Navigate to Applications → Outposts
  2. Click authentik Embedded Outpost → Edit
  3. In Applications, add the new application
  4. Click Update

Step 4: Create K8s Manifest

Copy and modify the template below, save as /root/tower-fleet/manifests/arr-stack/{app-name}.yaml:

# {App Name} Forward Auth Configuration
---
# ConfigMap for auth request headers
apiVersion: v1
kind: ConfigMap
metadata:
  name: {app-name}-auth-headers
  namespace: arr-stack
data:
  X-Forwarded-Host: "{app-name}.bogocat.com"
  X-Forwarded-Proto: "http"
---
# Headless service + Endpoints for external IP routing
apiVersion: v1
kind: Service
metadata:
  name: {app-name}-external
  namespace: arr-stack
  labels:
    app.kubernetes.io/name: {app-name}
    app.kubernetes.io/managed-by: tower-fleet
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - name: http
      port: {PORT}
      targetPort: {PORT}
---
apiVersion: v1
kind: Endpoints
metadata:
  name: {app-name}-external
  namespace: arr-stack
  labels:
    app.kubernetes.io/name: {app-name}
    app.kubernetes.io/managed-by: tower-fleet
subsets:
  - addresses:
      - ip: 10.89.97.50
    ports:
      - name: http
        port: {PORT}
---
# Service to reach Authentik server from this namespace
apiVersion: v1
kind: Service
metadata:
  name: {app-name}-authentik
  namespace: arr-stack
spec:
  type: ExternalName
  externalName: authentik-server.authentik.svc.cluster.local
---
# Ingress for Authentik outpost paths (login flow)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {app-name}-outpost
  namespace: arr-stack
  labels:
    app.kubernetes.io/name: {app-name}
    app.kubernetes.io/managed-by: tower-fleet
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
    nginx.ingress.kubernetes.io/upstream-vhost: "authentik-server.authentik.svc.cluster.local"
spec:
  ingressClassName: nginx
  rules:
    - host: {app-name}.bogocat.com
      http:
        paths:
          - path: /outpost.goauthentik.io/
            pathType: Prefix
            backend:
              service:
                name: {app-name}-authentik
                port:
                  number: 80
---
# Main app ingress with forward auth
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {app-name}
  namespace: arr-stack
  labels:
    app.kubernetes.io/name: {app-name}
    app.kubernetes.io/managed-by: tower-fleet
  annotations:
    nginx.ingress.kubernetes.io/auth-url: "http://authentik-server.authentik.svc.cluster.local/outpost.goauthentik.io/auth/nginx"
    nginx.ingress.kubernetes.io/auth-signin: "http://{app-name}.bogocat.com/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri"
    nginx.ingress.kubernetes.io/auth-response-headers: "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-uid"
    nginx.ingress.kubernetes.io/auth-proxy-set-headers: "arr-stack/{app-name}-auth-headers"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
  ingressClassName: nginx
  rules:
    - host: {app-name}.bogocat.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: {app-name}-external
                port:
                  number: {PORT}

Replace: - {app-name} → lowercase app name (e.g., sonarr) - {App Name} → display name (e.g., Sonarr) - {PORT} → service port (see Services Reference table)

Step 5: Apply K8s Manifest

kubectl apply -f /root/tower-fleet/manifests/arr-stack/{app-name}.yaml

Step 6: Add DNS Entry

In OPNsense: 1. Services → Unbound DNS → Host Overrides 2. Add: {app-name}.bogocat.com10.89.97.220 3. Apply changes

Step 7: Test

  1. Open incognito browser
  2. Go to http://{app-name}.bogocat.com
  3. Should redirect to Authentik login
  4. Login with a user in the correct group
  5. Should redirect back to the app

Key Learnings / Gotchas

ExternalName services don't work with nginx-ingress for IPs

Use headless Service + Endpoints instead:

spec:
  type: ClusterIP
  clusterIP: None

Why this pattern exists: arr-stack apps run on VM 100 (10.89.97.50), not in K8s. Since Ingress backends require a Service name (not an IP), we create a headless Service with manually-defined Endpoints pointing to the VM. This is a workaround for routing K8s Ingress traffic to external IPs.

When arr-stack migrates to K8s: This pattern will be replaced with standard ClusterIP Services that auto-discover pods via label selectors. See arr-stack K8s Migration for details (currently deferred).

Forward auth needs X-Forwarded-Host header

The embedded outpost matches requests by host. Pass via ConfigMap:

nginx.ingress.kubernetes.io/auth-proxy-set-headers: "arr-stack/{app-name}-auth-headers"

Outpost paths must be routed via same hostname

The /outpost.goauthentik.io/start and /outpost.goauthentik.io/callback paths need their own ingress under the app's hostname, not auth.bogocat.com.

configuration-snippet is disabled

The nginx-ingress controller has snippets disabled. Use auth-proxy-set-headers with ConfigMap instead.

Forward auth ≠ SSO

Forward auth controls WHO can access the app. Users still need to log into the app itself separately. This is expected behavior.

Troubleshooting

404 on /outpost.goauthentik.io/auth/nginx

  • Check application is assigned to embedded outpost
  • Restart Authentik server: kubectl rollout restart deployment -n authentik authentik-server

503 Service Unavailable

  • Check Endpoints exist: kubectl get endpoints -n arr-stack
  • Verify VM is reachable: curl http://10.89.97.50:{PORT}

500 Internal Server Error

  • Check ingress controller logs: kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=50

Redirect loop

  • Clear browser cookies
  • Check auth-signin URL matches the app hostname

Files Reference

File Purpose
/root/tower-fleet/manifests/arr-stack/namespace.yaml Namespace definition
/root/tower-fleet/manifests/arr-stack/jellyseerr.yaml Jellyseerr forward auth config
/root/tower-fleet/manifests/arr-stack/overseerr.yaml Overseerr forward auth config
/root/tower-fleet/manifests/arr-stack/sonarr.yaml Sonarr forward auth config
/root/tower-fleet/manifests/arr-stack/radarr.yaml Radarr forward auth config
/root/tower-fleet/manifests/arr-stack/lidarr.yaml Lidarr forward auth config
/root/tower-fleet/manifests/arr-stack/prowlarr.yaml Prowlarr forward auth config
/root/tower-fleet/manifests/arr-stack/bazarr.yaml Bazarr forward auth config
/root/tower-fleet/manifests/arr-stack/sabnzbd.yaml SABnzbd forward auth config
/root/tower-fleet/manifests/arr-stack/deluge.yaml Deluge forward auth config
/root/tower-fleet/manifests/arr-stack/README.md Quick reference