Files
portainer-core/docs/sessions/2025-11-23-admin-sso-setup.md
T

6.0 KiB

Admin-Level SSO Setup Guide

Date: 2025-11-23 Objective: Create separate user-level and admin-level SSO providers for proper access control

Overview

This guide sets up a two-tier SSO architecture:

  • User Services Proxy - For general authenticated access (Organizr)
  • Admin Services Proxy - For administrative interfaces (Core API, future admin tools)

Prerequisites

  • Authentik accessible at https://auth.schweitz.net
  • Admin credentials: akadmin / yzXAhiBAggPB5cz
  • Standalone outpost running on port 9445

Step 1: Create Admin Group

  1. Navigate to https://auth.schweitz.net
  2. Log in as akadmin
  3. Go to DirectoryGroups
  4. Click Create
  5. Fill in:
    • Name: homelab-admins
    • Parent: (none)
    • Click Create
  6. Click on the new homelab-admins group
  7. Go to Users tab
  8. Click Add existing user
  9. Select your user (jpmschweitzer@gmail.com)
  10. Click Add

Step 2: Create Admin Authorization Policy

  1. Go to CustomizationPolicies
  2. Click CreateGroup Membership Policy
  3. Fill in:
    • Name: Admin Group Required
    • Groups: Select homelab-admins
    • Click Create

Step 3: Create Admin Proxy Provider

  1. Go to ApplicationsProviders
  2. Click CreateProxy Provider
  3. Fill in:
    • Name: Admin Services Proxy
    • Authorization flow: default-provider-authorization-implicit-consent
    • Mode: Forward auth (single application)
    • External host: https://api.schweitz.net
    • Cookie domain: .schweitz.net
    • Token validity: hours=8
    • Click Next
  4. On Policy Bindings page:
    • Click Bind existing policy
    • Select Admin Group Required
    • Order: 0
    • Click Create

Step 4: Create Core API Application

  1. Go to ApplicationsApplications
  2. Click Create
  3. Fill in:
    • Name: Core API
    • Slug: core-api
    • Provider: Select Admin Services Proxy
    • Launch URL: https://api.schweitz.net
    • Policy engine mode: all (require all policies to pass)
    • Click Create

Step 5: Assign Provider to Standalone Outpost

  1. Go to ApplicationsOutposts
  2. Click on Outpost Standalone Proxy Outpost
  3. In the Applications field, you should see Organizr
  4. Add Core API to the applications list
  5. Click Update
  6. Wait 10-20 seconds for the outpost to reconnect
  7. Check logs: docker logs authentik-proxy --tail 50
    • Should see: "WebSocket connected" and no errors

Step 6: Verify NPM Configuration

The NPM config for api.schweitz.net should already be correct:

# Forward auth to standalone outpost
auth_request /outpost.goauthentik.io/auth/nginx;

# Outpost proxy location
location /outpost.goauthentik.io {
    proxy_pass https://localhost:9445/outpost.goauthentik.io;
    # ... rest of config
}

No changes needed to NPM - The outpost automatically handles routing to the correct provider based on the external host.

Step 7: Test Admin Access

  1. Test in incognito window:

    # Open incognito window
    https://api.schweitz.net/docs
    
  2. Expected flow:

    • Redirects to https://auth.schweitz.net
    • Shows Google OAuth login
    • After authentication, checks group membership
    • If in homelab-admins group → allows access
    • If NOT in group → shows "Access Denied" or "Insufficient Permissions"
  3. Verify headers are passed:

    # After logging in, check developer tools → Network → Headers
    # Should see X-authentik-groups containing "homelab-admins"
    

Step 8: Rename Organizr Provider (Optional)

For consistency, rename the existing provider:

  1. Go to ApplicationsProviders
  2. Click on Organizr Proxy
  3. Change Name to User Services Proxy
  4. Click Update

Architecture Diagram

User → https://api.schweitz.net
  ↓
NPM: Forward auth check
  ↓
Standalone Outpost (port 9445)
  ↓
Authentik: Check which provider matches external host
  ↓
Provider: "Admin Services Proxy" (for api.schweitz.net)
  ↓
Policy: "Admin Group Required"
  ↓
✅ User in homelab-admins → Allow
❌ User NOT in group → Deny (403)

Verification Checklist

  • Admin group homelab-admins created
  • Your user added to homelab-admins group
  • Policy Admin Group Required created
  • Provider Admin Services Proxy created with policy binding
  • Application Core API created and linked to provider
  • Outpost has both Organizr and Core API applications assigned
  • Outpost logs show successful WebSocket connection
  • Test access to https://api.schweitz.net/docs requires auth
  • After auth, access is granted (user is in admin group)
  • X-authentik-groups header contains homelab-admins

Troubleshooting

Issue: "Access Denied" even though user is in admin group

Check:

# Verify policy is bound to provider
curl -s -H "Authorization: Bearer 9blMGz71CFMJszs7AedQefgydpTnwvybjmMn0AlYilIKBV5LIq7snqnCodwX" \
  https://auth.schweitz.net/api/v3/providers/proxy/ | \
  python3 -m json.tool | grep -A 20 "Admin Services"

Issue: Outpost not picking up new provider

Fix:

# Restart outpost
docker restart authentik-proxy

# Check logs
docker logs authentik-proxy --tail 100

Issue: Still using old provider

Check:

# Verify external host is EXACTLY "https://api.schweitz.net" (no trailing slash)
# Authentik matches providers by exact external host match

Next Steps

After admin SSO is working:

  1. Mark Milestone 4 as complete in STATUS.md
  2. Continue to Milestone 5: Protect remaining services
    • git.schweitz.net (Gitea) → Admin provider
    • amp.schweitz.net (AMP) → User provider
    • tatlock.schweitz.net → User provider
  3. Update CHANGELOG.md with 0.8.3-admin-sso version

Reference