From 426a5dd70d094c2237b51d493906a05ca35ae2e0 Mon Sep 17 00:00:00 2001 From: Igor Loskutov Date: Fri, 5 Dec 2025 14:40:42 -0500 Subject: [PATCH] authentik script --- docs/docs/installation/auth-setup.md | 24 ++++++++++- scripts/setup-authentik-oauth.sh | 64 +++++++++++++++------------- 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/docs/docs/installation/auth-setup.md b/docs/docs/installation/auth-setup.md index 02037ed3..5a6e0e63 100644 --- a/docs/docs/installation/auth-setup.md +++ b/docs/docs/installation/auth-setup.md @@ -24,6 +24,8 @@ This setup runs Authentik on the same server as Reflector, with Caddy proxying t ### Step 1: Deploy Authentik +**Location: YOUR SERVER (via SSH)** + ```bash # Create directory for Authentik mkdir -p ~/authentik && cd ~/authentik @@ -48,6 +50,8 @@ Authentik takes ~2 minutes to run migrations and apply blueprints on first start ### Step 2: Connect Authentik to Reflector's Network +**Location: YOUR SERVER (via SSH)** + Since Authentik runs in a separate Docker Compose project, connect it to Reflector's network so Caddy can proxy to it: ```bash @@ -62,6 +66,8 @@ sudo docker network connect reflector_default authentik-server-1 ### Step 3: Add Authentik to Caddy +**Location: YOUR SERVER (via SSH)** + Uncomment the Authentik section in your `Caddyfile` and set your domain: ```bash @@ -84,13 +90,18 @@ docker compose -f docker-compose.prod.yml exec caddy caddy reload --config /etc/ **Option A: Automated Setup (Recommended)** +**Location: YOUR SERVER (via SSH)** + Run the setup script from the Reflector repository: ```bash +ssh user@your-server-ip cd ~/reflector ./scripts/setup-authentik-oauth.sh https://authentik.example.com YourSecurePassword123 https://app.example.com ``` +**Important:** The script must be run from the `~/reflector` directory on your server, as it creates files using relative paths. + The script will output the configuration values to add to your `.env` files. Skip to Step 6. **Option B: Manual Setup** @@ -129,9 +140,12 @@ The script will output the configuration values to add to your `.env` files. Ski ### Step 5: Get Public Key for JWT Verification +**Location: YOUR SERVER (via SSH)** + Extract the public key from Authentik's JWKS endpoint: ```bash +mkdir -p ~/reflector/server/reflector/auth/jwt/keys curl -s https://authentik.example.com/application/o/reflector/jwks/ | \ jq -r '.keys[0].x5c[0]' | base64 -d | openssl x509 -pubkey -noout \ > ~/reflector/server/reflector/auth/jwt/keys/authentik_public.pem @@ -139,7 +153,9 @@ curl -s https://authentik.example.com/application/o/reflector/jwks/ | \ ### Step 6: Update docker-compose.prod.yml -Add a volume mount for the JWT keys directory to the server and worker services: +**Location: YOUR SERVER (via SSH)** + +**Note:** This step is already done in the current `docker-compose.prod.yml`. Verify the volume mounts exist: ```yaml server: @@ -159,6 +175,8 @@ worker: ### Step 7: Configure Reflector Backend +**Location: YOUR SERVER (via SSH)** + Update `server/.env`: ```env # Authentication @@ -172,6 +190,8 @@ Replace `` with the Client ID from Step 4. ### Step 8: Configure Reflector Frontend +**Location: YOUR SERVER (via SSH)** + Update `www/.env`: ```env # Authentication @@ -189,6 +209,8 @@ NEXTAUTH_SECRET= ### Step 9: Restart Services +**Location: YOUR SERVER (via SSH)** + ```bash cd ~/reflector sudo docker compose -f docker-compose.prod.yml up -d --force-recreate server worker web diff --git a/scripts/setup-authentik-oauth.sh b/scripts/setup-authentik-oauth.sh index 0171e32a..71edc49d 100755 --- a/scripts/setup-authentik-oauth.sh +++ b/scripts/setup-authentik-oauth.sh @@ -2,6 +2,10 @@ set -e # Setup Authentik OAuth provider for Reflector +# +# IMPORTANT: Run this script from your Reflector repository directory (cd ~/reflector) +# The script creates files using relative paths: server/reflector/auth/jwt/keys/ +# # Usage: ./setup-authentik-oauth.sh # Example: ./setup-authentik-oauth.sh https://authentik.example.com MyPassword123 https://app.example.com @@ -27,29 +31,18 @@ echo "Authentik URL: $AUTHENTIK_URL" echo "Frontend URL: $FRONTEND_URL" echo "" -# Step 1: Create API token using basic auth +# Step 1: Create API token via docker exec echo "Creating API token..." -TOKEN_RESPONSE=$(curl -s -X POST "$AUTHENTIK_URL/api/v3/core/tokens/" \ - -u "akadmin:$ADMIN_PASSWORD" \ - -H "Content-Type: application/json" \ - -d '{ - "identifier": "reflector-setup-token", - "intent": "api", - "description": "Token for Reflector setup script" - }') +API_TOKEN=$(docker compose -f ~/authentik/docker-compose.yml exec -T server python manage.py shell -c " +from authentik.core.models import User, Token +user = User.objects.get(username='akadmin') +token, _ = Token.objects.get_or_create(user=user, identifier='reflector-setup', defaults={'intent': 'api'}) +print(f'TOKEN:{token.key}') +" 2>&1 | grep "TOKEN:" | cut -d: -f2) -# Check if token already exists, if so get it -if echo "$TOKEN_RESPONSE" | grep -q "already exists"; then - echo " -> Token exists, retrieving..." - API_TOKEN=$(curl -s "$AUTHENTIK_URL/api/v3/core/tokens/reflector-setup-token/view_key/" \ - -u "akadmin:$ADMIN_PASSWORD" | jq -r '.key') -else - API_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.key') -fi - -if [ -z "$API_TOKEN" ] || [ "$API_TOKEN" = "null" ]; then - echo "Error: Failed to get API token" - echo "Response: $TOKEN_RESPONSE" +if [ -z "$API_TOKEN" ]; then + echo "Error: Failed to create API token via docker exec" + echo "Make sure Authentik is fully started and akadmin user exists" exit 1 fi echo " -> Got API token" @@ -81,12 +74,12 @@ echo " -> Invalidation UUID: $INVALIDATION_UUID" # Step 4: Get scope mappings (email, openid, profile) echo "Getting scope mappings..." -SCOPE_RESPONSE=$(curl -s "$AUTHENTIK_URL/api/v3/propertymappings/scope/" \ +SCOPE_RESPONSE=$(curl -s "$AUTHENTIK_URL/api/v3/propertymappings/all/" \ -H "Authorization: Bearer $API_TOKEN") -EMAIL_SCOPE=$(echo "$SCOPE_RESPONSE" | jq -r '.results[] | select(.scope_name=="email") | .pk') -OPENID_SCOPE=$(echo "$SCOPE_RESPONSE" | jq -r '.results[] | select(.scope_name=="openid") | .pk') -PROFILE_SCOPE=$(echo "$SCOPE_RESPONSE" | jq -r '.results[] | select(.scope_name=="profile") | .pk') +EMAIL_SCOPE=$(echo "$SCOPE_RESPONSE" | jq -r '.results[] | select(.name == "authentik default OAuth Mapping: OpenID '\''email'\''") | .pk') +OPENID_SCOPE=$(echo "$SCOPE_RESPONSE" | jq -r '.results[] | select(.name == "authentik default OAuth Mapping: OpenID '\''openid'\''") | .pk') +PROFILE_SCOPE=$(echo "$SCOPE_RESPONSE" | jq -r '.results[] | select(.name == "authentik default OAuth Mapping: OpenID '\''profile'\''") | .pk') echo " -> email: $EMAIL_SCOPE" echo " -> openid: $OPENID_SCOPE" echo " -> profile: $PROFILE_SCOPE" @@ -173,10 +166,19 @@ else echo " -> Application created: $APP_SLUG" fi -# Step 9: Clean up setup token -echo "Cleaning up..." -curl -s -X DELETE "$AUTHENTIK_URL/api/v3/core/tokens/reflector-setup-token/" \ - -H "Authorization: Bearer $API_TOKEN" > /dev/null 2>&1 || true +# Step 9: Extract public key for JWT verification +echo "Extracting public key for JWT verification..." +mkdir -p server/reflector/auth/jwt/keys +curl -s "$AUTHENTIK_URL/application/o/reflector/jwks/" | \ + jq -r '.keys[0].x5c[0]' | \ + base64 -d | \ + openssl x509 -pubkey -noout > server/reflector/auth/jwt/keys/authentik_public.pem + +if [ ! -s server/reflector/auth/jwt/keys/authentik_public.pem ]; then + echo "Error: Failed to extract public key" + exit 1 +fi +echo " -> Saved to server/reflector/auth/jwt/keys/authentik_public.pem" # Output configuration echo "" @@ -198,4 +200,8 @@ echo "" echo "# --- JWT Authentication ---" echo "AUTH_BACKEND=jwt" echo "AUTH_JWT_AUDIENCE=$CLIENT_ID" +echo "AUTH_JWT_PUBLIC_KEY=authentik_public.pem" echo "# --- End JWT Configuration ---" +echo "" +echo "Note: Public key has been saved to server/reflector/auth/jwt/keys/authentik_public.pem" +echo " It will be mounted via docker-compose volume."