Last active
January 10, 2025 21:48
-
-
Save profound-killah/16759e27640aab773bbbb28c5c496291 to your computer and use it in GitHub Desktop.
Authentik - Initial setup of embedded outpost instance and its associated Docker service connection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # This script configures an authentik embedded outpost instance and its associated Docker service connection. | |
| # It performs the following actions: | |
| # 1. Retrieves the UUID of the embedded outpost instance. | |
| # 2. Checks for an existing Docker service connection and updates it if necessary. | |
| # 3. Creates a new Docker service connection if none exists. | |
| # 4. Verifies and updates the authentik host configuration for the outpost instance. | |
| # Usage: | |
| # Run this script with the `setup` argument to execute the configuration process. | |
| # Example: ./1.configure_authentik_host.sh setup | |
| # Requirements: | |
| # - jq installed on the system (for JSON parsing) | |
| # - Valid API token with sufficient permissions to perform the operations. | |
| # API Documentation Links: | |
| # - Outpost Instances: | |
| # - https://docs.goauthentik.io/docs/developer-docs/api/reference/outposts-instances-list | |
| # - Docker Service Connections: | |
| # - https://docs.goauthentik.io/docs/developer-docs/api/reference/outposts-service-connections-docker-list | |
| # - https://docs.goauthentik.io/docs/developer-docs/api/reference/outposts-service-connections-docker-retrieve | |
| # - https://docs.goauthentik.io/docs/developer-docs/api/reference/outposts-service-connections-docker-create | |
| # - Embedded Outpost Update: | |
| # - https://docs.goauthentik.io/docs/developer-docs/api/reference/outposts-instances-retrieve | |
| # - https://docs.goauthentik.io/docs/developer-docs/api/reference/outposts-instances-update | |
| # API authentication | |
| api_base="http://localhost:9000/api/v3" | |
| token='<token>' | |
| auth_header="Authorization: Bearer $token" | |
| # Outpost instance configuration | |
| name='authentik Embedded Outpost' | |
| managed='goauthentik.io/outposts/embedded' | |
| authentik_host="https://auth.<example.com>" | |
| # Service connection configuration | |
| docker_service_name="Local Docker connection" | |
| docker_url="//var/run/docker.sock" | |
| # Help function | |
| function show_help() { | |
| echo "Usage: $0 setup" | |
| echo | |
| echo "Options:" | |
| echo " setup Run the setup process to configure the outpost and Docker service connection." | |
| echo " help Show this help message." | |
| echo | |
| exit 0 | |
| } | |
| # Check for parameters | |
| [[ $# -eq 0 ]] && show_help | |
| [[ "$1" != "setup" ]] && { echo "Error: Invalid parameter '$1'. Use '$0 help' for usage information."; exit 1; } | |
| # Retrieve outpost instance UUID | |
| outpost_instance_uuid=$(curl -s -L "${api_base}/outposts/instances/" \ | |
| -H "accept: application/json" \ | |
| -H "$auth_header" | jq -r '.results[0].pk // empty') | |
| if [[ -z "$outpost_instance_uuid" ]]; then | |
| echo "Failed to retrieve outpost instance UUID." | |
| exit 1 | |
| fi | |
| echo "Outpost instance UUID: $outpost_instance_uuid" | |
| # Check for existing Docker service connections | |
| response=$(curl -s -L "${api_base}/outposts/service_connections/docker/" \ | |
| -H "accept: application/json" \ | |
| -H "$auth_header") | |
| outpost_service_connection_pk=$(echo "$response" | jq -r '.results[0].pk // empty') | |
| existing_url=$(echo "$response" | jq -r '.results[0].url // empty') | |
| if [[ -n "$outpost_service_connection_pk" ]]; then | |
| echo "Found existing Docker service connection PK: $outpost_service_connection_pk" | |
| # Check if the existing URL matches the desired URL | |
| if [[ "$existing_url" != "$docker_url" ]]; then | |
| echo "Existing Docker service connection URL ('$existing_url') does not match the desired URL ('$docker_url'). Updating..." | |
| update_response=$(curl -s -X PUT "${api_base}/outposts/service_connections/docker/${outpost_service_connection_pk}/" \ | |
| -H "accept: application/json" \ | |
| -H "content-type: application/json" \ | |
| -H "$auth_header" \ | |
| -d "{ | |
| \"name\": \"$docker_service_name\", | |
| \"local\": true, | |
| \"url\": \"$docker_url\", | |
| \"tls_verification\": null, | |
| \"tls_authentication\": null | |
| }") | |
| success=$(echo "$update_response" | jq -r '.pk // empty') | |
| if [[ -n "$success" ]]; then | |
| echo "Docker service connection updated successfully. PK: $success" | |
| else | |
| echo "Failed to update Docker service connection. Response: $update_response" | |
| exit 1 | |
| fi | |
| else | |
| echo "Existing Docker service connection URL matches the desired URL. No update needed." | |
| fi | |
| else | |
| echo "No Docker service connections found. Creating a new one..." | |
| response=$(curl -s -X POST "${api_base}/outposts/service_connections/docker/" \ | |
| -H "accept: application/json" \ | |
| -H "content-type: application/json" \ | |
| -H "$auth_header" \ | |
| -d "{ | |
| \"name\": \"$docker_service_name\", | |
| \"local\": true, | |
| \"url\": \"$docker_url\", | |
| \"tls_verification\": null, | |
| \"tls_authentication\": null | |
| }") | |
| outpost_service_connection_pk=$(echo "$response" | jq -r '.pk // empty') | |
| if [[ -z "$outpost_service_connection_pk" ]]; then | |
| echo "Failed to create Docker service connection. Response: $response" | |
| exit 1 | |
| fi | |
| echo "Created new Docker service connection PK: $outpost_service_connection_pk" | |
| fi | |
| # Confirm whether authentik_host matches | |
| current_authentik_host=$(curl -s -L "${api_base}/outposts/instances/${outpost_instance_uuid}/" \ | |
| -H "accept: application/json" \ | |
| -H "$auth_header" | jq -r '.config.authentik_host // empty') | |
| if [[ "$current_authentik_host" == "$authentik_host" ]]; then | |
| echo "✅ No update required. authentik_host matches the desired value." | |
| else | |
| echo "⚠️ authentik_host does not match. Updating embedded outpost..." | |
| # Full update with detailed configuration | |
| update_outpost_instance_response=$(curl -s -L -X PUT "${api_base}/outposts/instances/${outpost_instance_uuid}/" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Accept: application/json" \ | |
| -H "$auth_header" \ | |
| -d "{ | |
| \"name\": \"${name}\", | |
| \"type\": \"proxy\", | |
| \"providers\": [0], | |
| \"service_connection\": \"${outpost_service_connection_pk}\", | |
| \"config\": { | |
| \"log_level\": \"info\", | |
| \"authentik_host\": \"${authentik_host}\", | |
| \"docker_map_ports\": true, | |
| \"refresh_interval\": \"minutes=5\", | |
| \"kubernetes_replicas\": 1, | |
| \"authentik_host_insecure\": false, | |
| \"kubernetes_namespace\": \"default\" | |
| }, | |
| \"managed\": \"${managed}\" | |
| }") | |
| # Check for a successful update | |
| updated_pk=$(echo "$update_outpost_instance_response" | jq -r '.pk // empty') | |
| if [[ -n "$updated_pk" ]]; then | |
| echo "✅ Successfully updated embedded outpost. PK: $updated_pk" | |
| else | |
| echo "❌ Failed to update embedded outpost. Response:" | |
| echo "$update_outpost_instance_response" | jq . | |
| exit 1 | |
| fi | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # what script do: | |
| # - provision providers | |
| # - set name: Treafik Provider | |
| # - set authorization flow - implicit - done | |
| # - set forward auth - done | |
| # - external host: https://traefik.example.com - done | |
| # - set invalidation flow - done | |
| # - provision applications | |
| # - set name: Traefik App - done per app with custom mapping for group and icon | |
| # - set slug: traefik-app - done | |
| # - set group (preferably from docker label) - quick and dirty done | |
| # - set provider - done | |
| # - ui settings | |
| # - set open in new tab - done | |
| # - set icon - may not be doable because api calls look like they only accept local files to upload instead of updating the meta_icon value. | |
| # - activate/select applications in embedded outpost instance | |
| # | |
| token='<token>' | |
| api_base="http://localhost:9000/api/v3" | |
| auth_header="Authorization: Bearer $token" | |
| domain="<example.com>" | |
| # array of applications | |
| applications=( | |
| "traefik" | |
| "plex" | |
| "ombi" | |
| "not porn" | |
| ) | |
| # setup providers | |
| default_provider_authorization_flow="default-provider-authorization-implicit-consent" | |
| default_provider_invalidation_flow="default-provider-invalidation-flow" | |
| provider_authorization_flow_uuid=$(curl -s -L "${api_base}/flows/instances/${default_provider_authorization_flow}/" \ | |
| -H 'Accept: application/json' \ | |
| -H "$auth_header" | jq .pk) | |
| provider_invalidation_flow_uuid=$(curl -s -L "${api_base}/flows/instances/${default_provider_invalidation_flow}/" \ | |
| -H 'Accept: application/json' \ | |
| -H "$auth_header" | jq .pk) | |
| # Property mappings names to search | |
| property_mappings=( | |
| "authentik%20default%20OAuth%20Mapping%3A%20Proxy%20outpost" | |
| "authentik%20default%20OAuth%20Mapping%3A%20OpenID%20%27openid%27" | |
| "authentik%20default%20OAuth%20Mapping%3A%20OpenID%20%27email%27" | |
| "authentik%20default%20OAuth%20Mapping%3A%20OpenID%20%27profile%27" | |
| "authentik%20default%20OAuth%20Mapping%3A%20Application%20Entitlements" | |
| ) | |
| # Initialize property mappings PK array | |
| property_mapping_pks=() | |
| # Fetch PK for each property mapping | |
| for mapping_name in "${property_mappings[@]}"; do | |
| pk=$(curl -s -L "${api_base}/propertymappings/all/?name=${mapping_name}" \ | |
| -H "Accept: application/json" \ | |
| -H "$auth_header" | jq -r '.pk // empty') | |
| if [[ -n "$pk" ]]; then | |
| property_mapping_pks+=("$pk") | |
| echo "✅ Found PK for ${mapping_name}: $pk" | |
| else | |
| echo "❌ Failed to fetch PK for ${mapping_name}" | |
| fi | |
| done | |
| # Validate we have all PKs | |
| if [[ ${#property_mapping_pks[@]} -ne ${#property_mappings[@]} ]]; then | |
| echo "❌ Not all property mappings were resolved. Exiting." | |
| # could build out some fuzzy logic to retry the failed mappings, maybe future enhancement | |
| exit 1 | |
| fi | |
| # Prepare the final API call data | |
| property_mapping_json=$(printf '"%s",' "${property_mapping_pks[@]}" | sed 's/,$//') | |
| for application in "${applications[@]}"; do | |
| # set provider vars | |
| provider_name="${application} Provider" | |
| provider_internal_host="" | |
| if $application == "ombi"; then | |
| provider_external_host="https://${domain}" | |
| else | |
| provider_external_host="https://${application}.${domain}" | |
| fi | |
| provider_basic_auth="false" | |
| provider_mode="forward_single" | |
| provider_access_token_validity="hours=24" | |
| provider_refresh_token_validity="days=30" | |
| # create provider | |
| echo "Provisioning provider: $provider_name" | |
| create_provider_response=$(curl -s -L "${api_base}/providers/proxy/" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Accept: application/json" \ | |
| -H "$auth_header" \ | |
| -d "{ | |
| \"name\": \"${provider_authorization_flow_uuid}\", | |
| \"authentication_flow\": null, | |
| \"authorization_flow\": \"${provider_authorization_flow_uuid}\", | |
| \"invalidation_flow\": \"${provider_invalidation_flow_uuid}\", | |
| \"property_mappings\": [$property_mapping_json], | |
| \"internal_host\": \"${provider_mode}\", | |
| \"external_host\": \"${provider_authorization_flow_uuid}\", | |
| \"internal_host_ssl_validation\": true, | |
| \"certificate\": null, | |
| \"skip_path_regex\": \"\", | |
| \"basic_auth_enabled\": ${provider_basic_auth}, | |
| \"basic_auth_password_attribute\": \"\", | |
| \"basic_auth_user_attribute\": \"\", | |
| \"mode\": \"${provider_mode}\", | |
| \"intercept_header_auth\": true, | |
| \"cookie_domain\": \"\", | |
| \"jwt_federation_sources\": [ | |
| 0 | |
| ], | |
| \"jwt_federation_providers\": [ | |
| 0 | |
| ], | |
| \"access_token_validity\": \"${provider_access_token_validity}\", | |
| \"refresh_token_validity\": \"${provider_refresh_token_validity}\" | |
| }") | |
| # Check for successful response | |
| updated_pk=$(echo "$create_provider_response" | jq -r '.pk // empty') | |
| if [[ -n "$updated_pk" ]]; then | |
| echo "✅ Successfully updated provider. PK: $updated_pk" | |
| else | |
| echo "❌ Failed to update provider. Response:" | |
| echo "$create_provider_response" | jq . | |
| exit 1 | |
| fi | |
| ## we're done with the provider, now let's move on to the application | |
| # application group & icon svg filename mappings | |
| ## The default syntax for icon svg is ${application}.svg | |
| ## if no icon svg name is listed below, the default will be used | |
| # admin | |
| # - traefik - traefik-gopher.svg | |
| # - portainer | |
| # - pgadmin - null | |
| # - adminer - adminerevo.svg | |
| # media | |
| # - plex - plex-white.svg | |
| # - ombi | |
| # arr | |
| # - sonarr | |
| # - radarr | |
| # - prowlarr | |
| # - bazarr | |
| # downloads | |
| # - nzbget - sabnzbd.svg | |
| # - qbit-tv - qbittorrent.svg | |
| # - qbit-mv - qbittorrent.svg | |
| # - qbit-misc - qbittorrent.svg | |
| # monitoring | |
| # - grafana | |
| # - prometheus | |
| # - alertmanager - prometheus.svg | |
| # - tautulli | |
| # - apcupsd - apc.svg | |
| # tools | |
| # - kiwix | |
| # - mediawiki - mediawiki-large.svg | |
| # - ittools | |
| # games | |
| # - factorio - null | |
| # - palworld - null | |
| # set application vars | |
| application_group="" | |
| application_name="${application} App" | |
| application_slug="${application}-app" | |
| application_provider_pk="$updated_pk" | |
| application_new_tab="true" | |
| application_icon_path="${application}.svg" | |
| # select case for application icon - if svg reference is null, default will be used | |
| case "$application" in | |
| "traefik") | |
| application_group="admin" | |
| application_icon_path="traefik-gopher.svg" | |
| ;; | |
| "plex") | |
| application_group="media" | |
| application_icon_path="plex-white.svg" | |
| ;; | |
| "ombi") | |
| application_group="media" | |
| application_icon_path="cacti.svg" | |
| ;; | |
| "sonarr") | |
| application_group="arr" | |
| ;; | |
| "radarr") | |
| application_group="arr" | |
| ;; | |
| "prowlarr") | |
| application_group="arr" | |
| ;; | |
| "bazarr") | |
| application_group="arr" | |
| ;; | |
| "nzbget") | |
| application_group="downloads" | |
| application_icon_path="sabnzbd.svg" | |
| ;; | |
| "qbit-tv") | |
| application_group="downloads" | |
| application_icon_path="qbittorrent.svg" | |
| ;; | |
| "qbit-mv") | |
| application_group="downloads" | |
| application_icon_path="qbittorrent.svg" | |
| ;; | |
| "qbit-misc") | |
| application_group="downloads" | |
| application_icon_path="qbittorrent.svg" | |
| ;; | |
| "grafana") | |
| application_group="monitoring" | |
| ;; | |
| "prometheus") | |
| application_group="monitoring" | |
| ;; | |
| "alertmanager") | |
| application_group="monitoring" | |
| application_icon_path="prometheus.svg" | |
| ;; | |
| "tautulli") | |
| application_group="monitoring" | |
| ;; | |
| "apcupsd") | |
| application_group="monitoring" | |
| application_icon_path="apc.svg" | |
| ;; | |
| "kiwix") | |
| application_group="tools" | |
| ;; | |
| "mediawiki") | |
| application_group="tools" | |
| application_icon_path="mediawiki-large.svg" | |
| ;; | |
| "ittools") | |
| application_group="tools" | |
| application_icon_path="cacti.svg" | |
| ;; | |
| "factorio") | |
| application_group="games" | |
| application_icon_path="cacti.svg" | |
| ;; | |
| "palworld") | |
| application_group="games" | |
| application_icon_path="cacti.svg" | |
| ;; | |
| *) | |
| application_group="default" | |
| application_icon_path="${application}.svg" | |
| ;; | |
| esac | |
| # create application | |
| echo "Provisioning provider: $application_name" | |
| curl -s -L "${api_base}/core/applications/" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Accept: application/json" \ | |
| -H "$auth_header" \ | |
| -d "{ | |
| \"name\": \"${application_name}\", | |
| \"slug\": \"${application_slug}\", | |
| \"provider\": ${application_provider_pk}, | |
| \"backchannel_providers\": [ | |
| 0 | |
| ], | |
| \"open_in_new_tab\": ${application_new_tab}, | |
| \"meta_launch_url\": \"\", | |
| \"meta_description\": \"\", | |
| \"meta_publisher\": \"\", | |
| \"policy_engine_mode\": \"all\", | |
| \"group\": \"${application_group}\" | |
| }" | jq . | |
| # set icon for application | |
| # when setting icon url, begin path from /media/public | |
| # i'm opting not to use application-icons in the path | |
| curl -L "${api_base}/core/applications/${application_slug}/set_icon_url/" \ | |
| -H 'Content-Type: application/json' \ | |
| -H "$auth_header" \ | |
| -d "{ \"url\": \"/${application_icon_path}\"}" | |
| # # set icon for source | |
| # # when setting icon url, begin path from /media/public | |
| # # i'm opting not to use source-icons in the path | |
| # curl -L "${api_base}/sources/all/${source_slug}/set_icon_url/" \ | |
| # -H 'Content-Type: application/json' \ | |
| # -H "$auth_header" \ | |
| # -d "{ \"url\": \"/${source_icon_path}\"}" | |
| done | |
| # ###### MISC Troubleshooting calls ###### | |
| # # list applications | |
| # curl -L "${api_base}/core/applications/" \ | |
| # -H 'Accept: application/json' \ | |
| # -H "$auth_header" | jq . | |
| # # list providers | |
| # curl -L "${api_base}/providers/proxy/" \ | |
| # -H 'Accept: application/json' \ | |
| # -H "$auth_header" | |
| # # search flows | |
| # curl -L "${api_base}/flows/instances/?search=implicit" \ | |
| # -H 'Accept: application/json' \ | |
| # -H "$auth_header" | jq . | |
| # # capture list of property mappings | |
| # curl -L "${api_base}/propertymappings/all/?name=${array_of_property_mappings}" \ | |
| # -H 'Accept: application/json' \ | |
| # -H "$auth_header" | jq .pk | |
| # # "48cff5e8-e785-4446-a6b1-0e0b3c08951f", | |
| # # "50d4c363-2c6d-4198-851c-cf8325fe9b38", | |
| # # "74cc6522-a0c9-43ea-8151-cfeaba71da18", | |
| # # "6dd3cbd6-4fce-4f7c-8023-7d1290fd5a25", | |
| # # "ab07b851-2c57-4aea-81b6-176dae1cdc31" | |
| # curl -L "${api_base}/propertymappings/all/ab07b851-2c57-4aea-81b6-176dae1cdc31/" \ | |
| # -H 'Accept: application/json' \ | |
| # -H "$auth_header" | jq .name | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment