Enable Google Authentik login on forge
This commit is contained in:
parent
20964e8ed7
commit
be5b7d90db
8 changed files with 389 additions and 3 deletions
284
Scripts/authentik-sync-google-source.sh
Executable file
284
Scripts/authentik-sync-google-source.sh
Executable file
|
|
@ -0,0 +1,284 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
authentik_url="${AUTHENTIK_URL:-https://auth.burrow.net}"
|
||||||
|
bootstrap_token="${AUTHENTIK_BOOTSTRAP_TOKEN:-}"
|
||||||
|
google_client_id="${AUTHENTIK_GOOGLE_CLIENT_ID:-}"
|
||||||
|
google_client_secret="${AUTHENTIK_GOOGLE_CLIENT_SECRET:-}"
|
||||||
|
source_slug="${AUTHENTIK_GOOGLE_SOURCE_SLUG:-google}"
|
||||||
|
source_name="${AUTHENTIK_GOOGLE_SOURCE_NAME:-Google}"
|
||||||
|
identification_stage_name="${AUTHENTIK_GOOGLE_IDENTIFICATION_STAGE_NAME:-default-authentication-identification}"
|
||||||
|
authentication_flow_slug="${AUTHENTIK_GOOGLE_AUTHENTICATION_FLOW_SLUG:-default-source-authentication}"
|
||||||
|
enrollment_flow_slug="${AUTHENTIK_GOOGLE_ENROLLMENT_FLOW_SLUG:-default-source-enrollment}"
|
||||||
|
login_mode="${AUTHENTIK_GOOGLE_LOGIN_MODE:-redirect}"
|
||||||
|
user_matching_mode="${AUTHENTIK_GOOGLE_USER_MATCHING_MODE:-email_link}"
|
||||||
|
policy_engine_mode="${AUTHENTIK_GOOGLE_POLICY_ENGINE_MODE:-any}"
|
||||||
|
google_account_map_json="${AUTHENTIK_GOOGLE_ACCOUNT_MAP_JSON:-[]}"
|
||||||
|
property_mapping_name="${AUTHENTIK_GOOGLE_PROPERTY_MAPPING_NAME:-Burrow Google Account Map}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: Scripts/authentik-sync-google-source.sh
|
||||||
|
|
||||||
|
Required environment:
|
||||||
|
AUTHENTIK_BOOTSTRAP_TOKEN
|
||||||
|
AUTHENTIK_GOOGLE_CLIENT_ID
|
||||||
|
AUTHENTIK_GOOGLE_CLIENT_SECRET
|
||||||
|
|
||||||
|
Optional environment:
|
||||||
|
AUTHENTIK_URL
|
||||||
|
AUTHENTIK_GOOGLE_SOURCE_SLUG
|
||||||
|
AUTHENTIK_GOOGLE_SOURCE_NAME
|
||||||
|
AUTHENTIK_GOOGLE_IDENTIFICATION_STAGE_NAME
|
||||||
|
AUTHENTIK_GOOGLE_AUTHENTICATION_FLOW_SLUG
|
||||||
|
AUTHENTIK_GOOGLE_ENROLLMENT_FLOW_SLUG
|
||||||
|
AUTHENTIK_GOOGLE_LOGIN_MODE promoted|redirect
|
||||||
|
AUTHENTIK_GOOGLE_USER_MATCHING_MODE identifier|email_link|email_deny|username_link|username_deny
|
||||||
|
AUTHENTIK_GOOGLE_POLICY_ENGINE_MODE all|any
|
||||||
|
AUTHENTIK_GOOGLE_ACCOUNT_MAP_JSON JSON array of alias mappings
|
||||||
|
AUTHENTIK_GOOGLE_PROPERTY_MAPPING_NAME
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$bootstrap_token" ]]; then
|
||||||
|
echo "error: AUTHENTIK_BOOTSTRAP_TOKEN is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$google_client_id" || -z "$google_client_secret" || "$google_client_id" == PENDING* || "$google_client_secret" == PENDING* ]]; then
|
||||||
|
echo "Google OAuth credentials are not configured; skipping Authentik Google source sync." >&2
|
||||||
|
echo "Set Authorized redirect URI in Google to ${authentik_url}/source/oauth/callback/${source_slug}/" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! printf '%s' "$google_account_map_json" | jq -e 'type == "array"' >/dev/null; then
|
||||||
|
echo "error: AUTHENTIK_GOOGLE_ACCOUNT_MAP_JSON must be a JSON array" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$login_mode" in
|
||||||
|
promoted|redirect) ;;
|
||||||
|
*)
|
||||||
|
echo "warning: unsupported AUTHENTIK_GOOGLE_LOGIN_MODE=$login_mode; falling back to redirect" >&2
|
||||||
|
login_mode="redirect"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
api() {
|
||||||
|
local method="$1"
|
||||||
|
local path="$2"
|
||||||
|
local data="${3:-}"
|
||||||
|
|
||||||
|
if [[ -n "$data" ]]; then
|
||||||
|
curl -fsS \
|
||||||
|
-X "$method" \
|
||||||
|
-H "Authorization: Bearer ${bootstrap_token}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$data" \
|
||||||
|
"${authentik_url}${path}"
|
||||||
|
else
|
||||||
|
curl -fsS \
|
||||||
|
-X "$method" \
|
||||||
|
-H "Authorization: Bearer ${bootstrap_token}" \
|
||||||
|
"${authentik_url}${path}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_authentik() {
|
||||||
|
for _ in $(seq 1 90); do
|
||||||
|
if curl -fsS "${authentik_url}/-/health/ready/" >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "error: Authentik did not become ready at ${authentik_url}" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup_single_result() {
|
||||||
|
local path="$1"
|
||||||
|
local jq_filter="$2"
|
||||||
|
|
||||||
|
api GET "$path" | jq -r "$jq_filter" | head -n1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_authentik
|
||||||
|
|
||||||
|
flow_pk="$(
|
||||||
|
lookup_single_result \
|
||||||
|
"/api/v3/flows/instances/?slug=${authentication_flow_slug}" \
|
||||||
|
'.results[] | select(.slug != null) | .pk // empty'
|
||||||
|
)"
|
||||||
|
if [[ -z "$flow_pk" ]]; then
|
||||||
|
echo "error: could not resolve Authentik authentication flow slug ${authentication_flow_slug}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
enrollment_flow_pk="$(
|
||||||
|
lookup_single_result \
|
||||||
|
"/api/v3/flows/instances/?slug=${enrollment_flow_slug}" \
|
||||||
|
'.results[] | select(.slug != null) | .pk // empty'
|
||||||
|
)"
|
||||||
|
if [[ -z "$enrollment_flow_pk" ]]; then
|
||||||
|
echo "error: could not resolve Authentik enrollment flow slug ${enrollment_flow_slug}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
identification_stage="$(
|
||||||
|
api GET "/api/v3/stages/identification/" \
|
||||||
|
| jq -c --arg name "$identification_stage_name" '.results[] | select(.name == $name)'
|
||||||
|
)"
|
||||||
|
if [[ -z "$identification_stage" ]]; then
|
||||||
|
echo "error: could not resolve Authentik identification stage ${identification_stage_name}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
stage_pk="$(printf '%s\n' "$identification_stage" | jq -r '.pk')"
|
||||||
|
|
||||||
|
property_mapping_payload='[]'
|
||||||
|
if [[ "$(printf '%s' "$google_account_map_json" | jq 'length')" -gt 0 ]]; then
|
||||||
|
alias_map_python="$(
|
||||||
|
printf '%s' "$google_account_map_json" \
|
||||||
|
| jq -c '
|
||||||
|
map({
|
||||||
|
key: (.source_email | ascii_downcase),
|
||||||
|
value: {
|
||||||
|
username: .username,
|
||||||
|
email: .email,
|
||||||
|
name: .name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
| from_entries
|
||||||
|
'
|
||||||
|
)"
|
||||||
|
|
||||||
|
oauth_property_mapping_expression="$(
|
||||||
|
cat <<EOF
|
||||||
|
email = (info.get("email") or "").strip().lower()
|
||||||
|
alias_map = ${alias_map_python}
|
||||||
|
mapped = alias_map.get(email)
|
||||||
|
if not mapped:
|
||||||
|
return {}
|
||||||
|
result = {}
|
||||||
|
for key in ("username", "email", "name"):
|
||||||
|
value = mapped.get(key)
|
||||||
|
if value:
|
||||||
|
result[key] = value
|
||||||
|
return result
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
|
||||||
|
oauth_property_mapping_payload="$(
|
||||||
|
jq -n \
|
||||||
|
--arg name "$property_mapping_name" \
|
||||||
|
--arg expression "$oauth_property_mapping_expression" \
|
||||||
|
'{
|
||||||
|
name: $name,
|
||||||
|
expression: $expression
|
||||||
|
}'
|
||||||
|
)"
|
||||||
|
|
||||||
|
existing_property_mapping="$(
|
||||||
|
api GET "/api/v3/propertymappings/source/oauth/?page_size=200" \
|
||||||
|
| jq -c --arg name "$property_mapping_name" '.results[]? | select(.name == $name)'
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -n "$existing_property_mapping" ]]; then
|
||||||
|
property_mapping_pk="$(printf '%s\n' "$existing_property_mapping" | jq -r '.pk')"
|
||||||
|
api PATCH "/api/v3/propertymappings/source/oauth/${property_mapping_pk}/" "$oauth_property_mapping_payload" >/dev/null
|
||||||
|
else
|
||||||
|
property_mapping_pk="$(
|
||||||
|
api POST "/api/v3/propertymappings/source/oauth/" "$oauth_property_mapping_payload" \
|
||||||
|
| jq -r '.pk // empty'
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${property_mapping_pk:-}" ]]; then
|
||||||
|
echo "error: Google OAuth property mapping did not return a primary key" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
property_mapping_payload="$(jq -cn --arg property_mapping_pk "$property_mapping_pk" '[$property_mapping_pk]')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
oauth_source_payload="$(
|
||||||
|
jq -n \
|
||||||
|
--arg name "$source_name" \
|
||||||
|
--arg slug "$source_slug" \
|
||||||
|
--arg authentication_flow "$flow_pk" \
|
||||||
|
--arg enrollment_flow "$enrollment_flow_pk" \
|
||||||
|
--arg user_matching_mode "$user_matching_mode" \
|
||||||
|
--arg policy_engine_mode "$policy_engine_mode" \
|
||||||
|
--argjson user_property_mappings "$property_mapping_payload" \
|
||||||
|
--arg consumer_key "$google_client_id" \
|
||||||
|
--arg consumer_secret "$google_client_secret" \
|
||||||
|
'{
|
||||||
|
name: $name,
|
||||||
|
slug: $slug,
|
||||||
|
enabled: true,
|
||||||
|
promoted: true,
|
||||||
|
authentication_flow: $authentication_flow,
|
||||||
|
enrollment_flow: $enrollment_flow,
|
||||||
|
user_property_mappings: $user_property_mappings,
|
||||||
|
group_property_mappings: [],
|
||||||
|
policy_engine_mode: $policy_engine_mode,
|
||||||
|
user_matching_mode: $user_matching_mode,
|
||||||
|
provider_type: "google",
|
||||||
|
consumer_key: $consumer_key,
|
||||||
|
consumer_secret: $consumer_secret
|
||||||
|
}'
|
||||||
|
)"
|
||||||
|
|
||||||
|
existing_source="$(
|
||||||
|
api GET "/api/v3/sources/oauth/?slug=${source_slug}" \
|
||||||
|
| jq -c '.results[]?'
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -n "$existing_source" ]]; then
|
||||||
|
source_pk="$(printf '%s\n' "$existing_source" | jq -r '.pk')"
|
||||||
|
api PATCH "/api/v3/sources/oauth/${source_slug}/" "$oauth_source_payload" >/dev/null
|
||||||
|
else
|
||||||
|
source_pk="$(
|
||||||
|
api POST "/api/v3/sources/oauth/" "$oauth_source_payload" \
|
||||||
|
| jq -r '.pk // empty'
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$source_pk" ]]; then
|
||||||
|
echo "error: Google OAuth source did not return a primary key" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
stage_patch="$(
|
||||||
|
printf '%s\n' "$identification_stage" \
|
||||||
|
| jq -c \
|
||||||
|
--arg source_pk "$source_pk" \
|
||||||
|
--arg login_mode "$login_mode" '
|
||||||
|
.sources = (
|
||||||
|
if $login_mode == "redirect" then
|
||||||
|
[$source_pk]
|
||||||
|
else
|
||||||
|
([ $source_pk ] + ((.sources // []) | map(select(. != $source_pk))))
|
||||||
|
end
|
||||||
|
)
|
||||||
|
| .show_source_labels = true
|
||||||
|
| if $login_mode == "redirect" then
|
||||||
|
.user_fields = []
|
||||||
|
else
|
||||||
|
.
|
||||||
|
end
|
||||||
|
| {
|
||||||
|
sources,
|
||||||
|
show_source_labels,
|
||||||
|
user_fields
|
||||||
|
}'
|
||||||
|
)"
|
||||||
|
|
||||||
|
api PATCH "/api/v3/stages/identification/${stage_pk}/" "$stage_patch" >/dev/null
|
||||||
|
|
||||||
|
echo "Synced Authentik Google source ${source_slug} (${source_pk}) in ${login_mode} mode."
|
||||||
4
flake.lock
generated
4
flake.lock
generated
|
|
@ -52,8 +52,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773506317,
|
"lastModified": 1773889306,
|
||||||
"narHash": "sha256-qWKbLUJpavIpvOdX1fhHYm0WGerytFHRoh9lVck6Bh0=",
|
"narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://codeload.github.com/nix-community/disko/tar.gz/master"
|
"url": "https://codeload.github.com/nix-community/disko/tar.gz/master"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ Mail hosting is intentionally not part of this NixOS host in the current plan. B
|
||||||
4. Let `burrow-forgejo-bootstrap.service` create or rotate the initial Forgejo admin account.
|
4. Let `burrow-forgejo-bootstrap.service` create or rotate the initial Forgejo admin account.
|
||||||
5. Let `burrow-forgejo-runner-bootstrap.service` register the self-hosted Forgejo runner and seed Git identity as `agent <agent@burrow.net>`.
|
5. Let `burrow-forgejo-runner-bootstrap.service` register the self-hosted Forgejo runner and seed Git identity as `agent <agent@burrow.net>`.
|
||||||
6. Run `Scripts/provision-forgejo-nsc.sh` locally, then `Scripts/sync-forgejo-nsc-config.sh` to place the Namespace dispatcher/autoscaler runtime inputs under `/var/lib/burrow/intake/`.
|
6. Run `Scripts/provision-forgejo-nsc.sh` locally, then `Scripts/sync-forgejo-nsc-config.sh` to place the Namespace dispatcher/autoscaler runtime inputs under `/var/lib/burrow/intake/`.
|
||||||
7. Ensure `/var/lib/agenix/agenix.key` exists on the host, encrypt `secrets/infra/authentik.env.age` and `secrets/infra/headscale-oidc-client-secret.age`, and let agenix materialize them under `/run/agenix/`.
|
7. Ensure `/var/lib/agenix/agenix.key` exists on the host, encrypt `secrets/infra/authentik.env.age`, `secrets/infra/authentik-google-client-id.age`, `secrets/infra/authentik-google-client-secret.age`, and `secrets/infra/headscale-oidc-client-secret.age`, and let agenix materialize them under `/run/agenix/`.
|
||||||
8. Use `Scripts/cloudflare-upsert-a-record.sh` to point `git.burrow.net`, `burrow.net`, `auth.burrow.net`, `ts.burrow.net`, and `nsc-autoscaler.burrow.net` at the host with Cloudflare proxying disabled for ACME.
|
8. Use `Scripts/cloudflare-upsert-a-record.sh` to point `git.burrow.net`, `burrow.net`, `auth.burrow.net`, `ts.burrow.net`, and `nsc-autoscaler.burrow.net` at the host with Cloudflare proxying disabled for ACME.
|
||||||
9. Use `Scripts/forge-deploy.sh --allow-dirty` for subsequent remote `nixos-rebuild` runs from the live workspace.
|
9. Use `Scripts/forge-deploy.sh --allow-dirty` for subsequent remote `nixos-rebuild` runs from the live workspace.
|
||||||
10. Configure Forward Email custom S3 backups for `burrow.net` and `burrow.rs` out-of-band with `Tools/forwardemail-custom-s3.sh`.
|
10. Configure Forward Email custom S3 backups for `burrow.net` and `burrow.rs` out-of-band with `Tools/forwardemail-custom-s3.sh`.
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,18 @@
|
||||||
group = "root";
|
group = "root";
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
};
|
};
|
||||||
|
age.secrets.burrowAuthentikGoogleClientId = {
|
||||||
|
file = ../../../secrets/infra/authentik-google-client-id.age;
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
age.secrets.burrowAuthentikGoogleClientSecret = {
|
||||||
|
file = ../../../secrets/infra/authentik-google-client-secret.age;
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
|
||||||
networking.extraHosts = ''
|
networking.extraHosts = ''
|
||||||
127.0.0.1 burrow.net git.burrow.net auth.burrow.net ts.burrow.net nsc-autoscaler.burrow.net
|
127.0.0.1 burrow.net git.burrow.net auth.burrow.net ts.burrow.net nsc-autoscaler.burrow.net
|
||||||
|
|
@ -69,6 +81,8 @@
|
||||||
enable = true;
|
enable = true;
|
||||||
envFile = config.age.secrets.burrowAuthentikEnv.path;
|
envFile = config.age.secrets.burrowAuthentikEnv.path;
|
||||||
headscaleClientSecretFile = config.age.secrets.burrowHeadscaleOidcClientSecret.path;
|
headscaleClientSecretFile = config.age.secrets.burrowHeadscaleOidcClientSecret.path;
|
||||||
|
googleClientIDFile = config.age.secrets.burrowAuthentikGoogleClientId.path;
|
||||||
|
googleClientSecretFile = config.age.secrets.burrowAuthentikGoogleClientSecret.path;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.burrow.headscale = {
|
services.burrow.headscale = {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ let
|
||||||
blueprintFile = "${blueprintDir}/burrow-authentik.yaml";
|
blueprintFile = "${blueprintDir}/burrow-authentik.yaml";
|
||||||
postgresVolume = "burrow-authentik-postgresql:/var/lib/postgresql/data";
|
postgresVolume = "burrow-authentik-postgresql:/var/lib/postgresql/data";
|
||||||
dataVolume = "burrow-authentik-data:/data";
|
dataVolume = "burrow-authentik-data:/data";
|
||||||
|
googleSourceSyncScript = ../../Scripts/authentik-sync-google-source.sh;
|
||||||
authentikBlueprint = pkgs.writeText "burrow-authentik-blueprint.yaml" ''
|
authentikBlueprint = pkgs.writeText "burrow-authentik-blueprint.yaml" ''
|
||||||
version: 1
|
version: 1
|
||||||
metadata:
|
metadata:
|
||||||
|
|
@ -106,6 +107,33 @@ in
|
||||||
default = "/var/lib/burrow/intake/authentik_headscale_client_secret.txt";
|
default = "/var/lib/burrow/intake/authentik_headscale_client_secret.txt";
|
||||||
description = "Host-local file containing the Authentik Headscale OIDC client secret.";
|
description = "Host-local file containing the Authentik Headscale OIDC client secret.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
googleClientIDFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Host-local file containing the Google OAuth client ID for the Authentik source.";
|
||||||
|
};
|
||||||
|
|
||||||
|
googleClientSecretFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Host-local file containing the Google OAuth client secret for the Authentik source.";
|
||||||
|
};
|
||||||
|
|
||||||
|
googleSourceSlug = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "google";
|
||||||
|
description = "Authentik OAuth source slug used for Google login.";
|
||||||
|
};
|
||||||
|
|
||||||
|
googleLoginMode = lib.mkOption {
|
||||||
|
type = lib.types.enum [
|
||||||
|
"promoted"
|
||||||
|
"redirect"
|
||||||
|
];
|
||||||
|
default = "redirect";
|
||||||
|
description = "Identification-stage behavior for the Google Authentik source.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
@ -263,6 +291,55 @@ EOF
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.services.burrow-authentik-google-source = lib.mkIf (
|
||||||
|
cfg.googleClientIDFile != null && cfg.googleClientSecretFile != null
|
||||||
|
) {
|
||||||
|
description = "Reconcile the Burrow Authentik Google OAuth source";
|
||||||
|
after = [
|
||||||
|
"burrow-authentik-ready.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
|
wants = [
|
||||||
|
"burrow-authentik-ready.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
restartTriggers = [
|
||||||
|
googleSourceSyncScript
|
||||||
|
cfg.envFile
|
||||||
|
cfg.googleClientIDFile
|
||||||
|
cfg.googleClientSecretFile
|
||||||
|
];
|
||||||
|
path = [
|
||||||
|
pkgs.bash
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.jq
|
||||||
|
];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "root";
|
||||||
|
Group = "root";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
set -euo pipefail
|
||||||
|
set -a
|
||||||
|
source ${lib.escapeShellArg cfg.envFile}
|
||||||
|
set +a
|
||||||
|
|
||||||
|
export AUTHENTIK_URL=https://${cfg.domain}
|
||||||
|
export AUTHENTIK_GOOGLE_SOURCE_SLUG=${lib.escapeShellArg cfg.googleSourceSlug}
|
||||||
|
export AUTHENTIK_GOOGLE_LOGIN_MODE=${lib.escapeShellArg cfg.googleLoginMode}
|
||||||
|
export AUTHENTIK_GOOGLE_USER_MATCHING_MODE=email_link
|
||||||
|
export AUTHENTIK_GOOGLE_CLIENT_ID="$(tr -d '\r\n' < ${lib.escapeShellArg cfg.googleClientIDFile})"
|
||||||
|
export AUTHENTIK_GOOGLE_CLIENT_SECRET="$(tr -d '\r\n' < ${lib.escapeShellArg cfg.googleClientSecretFile})"
|
||||||
|
|
||||||
|
${pkgs.bash}/bin/bash ${googleSourceSyncScript}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."${cfg.domain}".extraConfig = ''
|
services.caddy.virtualHosts."${cfg.domain}".extraConfig = ''
|
||||||
encode gzip zstd
|
encode gzip zstd
|
||||||
reverse_proxy 127.0.0.1:${toString cfg.port}
|
reverse_proxy 127.0.0.1:${toString cfg.port}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,7 @@ let
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
"secrets/infra/authentik.env.age".publicKeys = burrowForgeRecipients;
|
"secrets/infra/authentik.env.age".publicKeys = burrowForgeRecipients;
|
||||||
|
"secrets/infra/authentik-google-client-id.age".publicKeys = burrowForgeRecipients;
|
||||||
|
"secrets/infra/authentik-google-client-secret.age".publicKeys = burrowForgeRecipients;
|
||||||
"secrets/infra/headscale-oidc-client-secret.age".publicKeys = burrowForgeRecipients;
|
"secrets/infra/headscale-oidc-client-secret.age".publicKeys = burrowForgeRecipients;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
secrets/infra/authentik-google-client-id.age
Normal file
BIN
secrets/infra/authentik-google-client-id.age
Normal file
Binary file not shown.
9
secrets/infra/authentik-google-client-secret.age
Normal file
9
secrets/infra/authentik-google-client-secret.age
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 ux4N8Q 4uq5z93mRUUgcMOxP4+Yfe2Jq4tGYErwtzvtMHUvgi0
|
||||||
|
J9DkDeSPkQbOjFM3QoV+1Kz3ZVLfR4PUxCT8Zxz+Wvk
|
||||||
|
-> ssh-ed25519 IrZmAg uLEVmJ+e9ZiLas5YooR4GfgyspWTsFdMB2WPvluU/VI
|
||||||
|
7vqqQ/BIDQaOp6VDVLa5ugoRxVZZsMj116cTHY6+8KM
|
||||||
|
-> X25519 9spF9eLz63UOaBfuG9vTIr6bCKwzFsWMjnaIj1PIR3Y
|
||||||
|
iGFELg2RQUT9rEal7pblQhfxtwYhxsZdXYxEhvjtHpw
|
||||||
|
--- 3TDrUnIN826N/n5gc+YY8ilMMc/6K8zGTh6FxzKC/JM
|
||||||
|
ÊÉXÍHºéÓ#IJG§uíÃâeÒüÖ¹f&1€a2ƒB„JÔŽõg¯ºÁ=Ì¿Šä”.ÅÕ÷ë*7™F<E284A2>·<EFBFBD>´‰–bÖ
|
||||||
Loading…
Add table
Add a link
Reference in a new issue