155 lines
5 KiB
Bash
Executable file
155 lines
5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
project_id="${GOOGLE_CLOUD_PROJECT:-${BURROW_GOOGLE_PROJECT_ID:-project-88c23ce9-918a-470a-b33}}"
|
|
project_number="${BURROW_GOOGLE_PROJECT_NUMBER:-416198671487}"
|
|
pool_id="${BURROW_GOOGLE_WIF_POOL_ID:-burrow-authentik}"
|
|
provider_id="${BURROW_GOOGLE_WIF_PROVIDER_ID:-forgejo-runners}"
|
|
service_account="${BURROW_GOOGLE_WIF_SERVICE_ACCOUNT:-burrow-forgejo-runner@project-88c23ce9-918a-470a-b33.iam.gserviceaccount.com}"
|
|
authentik_issuer="${BURROW_AUTHENTIK_WIF_ISSUER:-https://auth.burrow.net/application/o/google-cloud/}"
|
|
authentik_token_endpoint="${BURROW_AUTHENTIK_WIF_TOKEN_ENDPOINT:-}"
|
|
authentik_audience="${BURROW_AUTHENTIK_WIF_AUDIENCE:-google-wif.burrow.net}"
|
|
authentik_client_id="${BURROW_AUTHENTIK_WIF_CLIENT_ID:-${AUTHENTIK_GOOGLE_WIF_CLIENT_ID:-google-wif.burrow.net}}"
|
|
authentik_client_secret="${BURROW_AUTHENTIK_WIF_CLIENT_SECRET:-${AUTHENTIK_GOOGLE_WIF_CLIENT_SECRET:-}}"
|
|
authentik_token_file="${BURROW_AUTHENTIK_WIF_TOKEN_FILE:-}"
|
|
authentik_token="${BURROW_AUTHENTIK_WIF_TOKEN:-}"
|
|
work_dir="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/burrow-google-wif"
|
|
emit_env=1
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: Scripts/ci/google-wif-auth.sh [--no-emit-env]
|
|
|
|
Authenticates gcloud to the Burrow Google project through Authentik-issued OIDC
|
|
and Google Workload Identity Federation. No Google service-account JSON key is
|
|
used or written.
|
|
|
|
Inputs:
|
|
GOOGLE_CLOUD_PROJECT / BURROW_GOOGLE_PROJECT_ID
|
|
BURROW_GOOGLE_PROJECT_NUMBER
|
|
BURROW_GOOGLE_WIF_POOL_ID
|
|
BURROW_GOOGLE_WIF_PROVIDER_ID
|
|
BURROW_GOOGLE_WIF_SERVICE_ACCOUNT
|
|
BURROW_AUTHENTIK_WIF_ISSUER
|
|
BURROW_AUTHENTIK_WIF_TOKEN_ENDPOINT
|
|
BURROW_AUTHENTIK_WIF_AUDIENCE
|
|
BURROW_AUTHENTIK_WIF_TOKEN or BURROW_AUTHENTIK_WIF_TOKEN_FILE
|
|
|
|
If no token is supplied, the script requests one from Authentik using
|
|
BURROW_AUTHENTIK_WIF_CLIENT_ID and BURROW_AUTHENTIK_WIF_CLIENT_SECRET.
|
|
EOF
|
|
}
|
|
|
|
while [[ "$#" -gt 0 ]]; do
|
|
case "$1" in
|
|
--no-emit-env)
|
|
emit_env=0
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "unknown argument: $1" >&2
|
|
exit 64
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
require_command() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "$1 is required for Google WIF authentication" >&2
|
|
exit 127
|
|
fi
|
|
}
|
|
|
|
require_command gcloud
|
|
require_command curl
|
|
require_command jq
|
|
|
|
resolve_token_endpoint() {
|
|
if [[ -n "$authentik_token_endpoint" ]]; then
|
|
printf '%s\n' "$authentik_token_endpoint"
|
|
return
|
|
fi
|
|
|
|
local issuer_no_slash="${authentik_issuer%/}"
|
|
local discovered=""
|
|
if discovered="$(
|
|
curl -fsS "${issuer_no_slash}/.well-known/openid-configuration" 2>/dev/null \
|
|
| jq -r '.token_endpoint // empty' 2>/dev/null
|
|
)" && [[ -n "$discovered" ]]; then
|
|
printf '%s\n' "$discovered"
|
|
return
|
|
fi
|
|
|
|
case "$issuer_no_slash" in
|
|
*/application/o/*)
|
|
printf '%s/application/o/token/\n' "${issuer_no_slash%%/application/o/*}"
|
|
;;
|
|
*)
|
|
printf '%s/token/\n' "$issuer_no_slash"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
mkdir -p "$work_dir"
|
|
chmod 0700 "$work_dir"
|
|
|
|
token_path="$work_dir/authentik-oidc-token.jwt"
|
|
credential_config="$work_dir/google-wif-credentials.json"
|
|
|
|
if [[ -n "$authentik_token_file" ]]; then
|
|
if [[ ! -s "$authentik_token_file" ]]; then
|
|
echo "Authentik WIF token file is empty or missing: $authentik_token_file" >&2
|
|
exit 1
|
|
fi
|
|
cp "$authentik_token_file" "$token_path"
|
|
elif [[ -n "$authentik_token" ]]; then
|
|
printf '%s' "$authentik_token" > "$token_path"
|
|
else
|
|
if [[ -z "$authentik_client_secret" ]]; then
|
|
echo "missing Authentik WIF token. Set BURROW_AUTHENTIK_WIF_TOKEN, BURROW_AUTHENTIK_WIF_TOKEN_FILE, or BURROW_AUTHENTIK_WIF_CLIENT_SECRET." >&2
|
|
exit 1
|
|
fi
|
|
token_endpoint="$(resolve_token_endpoint)"
|
|
curl -fsS \
|
|
-d grant_type=client_credentials \
|
|
-d client_id="$authentik_client_id" \
|
|
-d client_secret="$authentik_client_secret" \
|
|
-d scope="openid profile email groups" \
|
|
-d audience="$authentik_audience" \
|
|
"$token_endpoint" \
|
|
| jq -r '.id_token // .access_token // empty' > "$token_path"
|
|
fi
|
|
|
|
chmod 0600 "$token_path"
|
|
if [[ ! -s "$token_path" ]]; then
|
|
echo "Authentik did not return an OIDC token for Google WIF" >&2
|
|
exit 1
|
|
fi
|
|
|
|
provider_resource="projects/${project_number}/locations/global/workloadIdentityPools/${pool_id}/providers/${provider_id}"
|
|
gcloud iam workload-identity-pools create-cred-config "$provider_resource" \
|
|
--service-account "$service_account" \
|
|
--subject-token-type="urn:ietf:params:oauth:token-type:jwt" \
|
|
--credential-source-file "$token_path" \
|
|
--output-file "$credential_config"
|
|
|
|
chmod 0600 "$credential_config"
|
|
gcloud auth login --cred-file="$credential_config" --brief
|
|
gcloud config set project "$project_id" >/dev/null
|
|
|
|
{
|
|
echo "GOOGLE_APPLICATION_CREDENTIALS=$credential_config"
|
|
echo "CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE=$credential_config"
|
|
echo "CLOUDSDK_CORE_PROJECT=$project_id"
|
|
echo "GOOGLE_CLOUD_PROJECT=$project_id"
|
|
} > "$work_dir/google-wif.env"
|
|
|
|
if [[ "$emit_env" == "1" && -n "${GITHUB_ENV:-}" ]]; then
|
|
cat "$work_dir/google-wif.env" >> "$GITHUB_ENV"
|
|
fi
|
|
|
|
echo "Authenticated gcloud through Authentik WIF as ${service_account} in ${project_id}."
|