Support IDP manager configuration with configure.sh (#843)

support IDP management configuration using configure.sh script

Add initial Zitadel configuration script
This commit is contained in:
Bethuel 2023-06-02 18:34:36 +03:00 committed by GitHub
parent 612ae253fe
commit 51502af218
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 231 additions and 63 deletions

View File

@ -6,6 +6,7 @@ on:
- main
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }}
cancel-in-progress: true
@ -48,6 +49,9 @@ jobs:
CI_NETBIRD_AUTH_AUDIENCE: testing.ci
CI_NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT: https://example.eu.auth0.com/.well-known/openid-configuration
CI_NETBIRD_USE_AUTH0: true
CI_NETBIRD_MGMT_IDP: "none"
CI_NETBIRD_IDP_MGMT_CLIENT_ID: testing.client.id
CI_NETBIRD_IDP_MGMT_CLIENT_SECRET: testing.client.secret
- name: check values
working-directory: infrastructure_files
@ -67,6 +71,9 @@ jobs:
CI_NETBIRD_AUTH_USER_ID_CLAIM: "email"
CI_NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE: "super"
CI_NETBIRD_AUTH_DEVICE_AUTH_SCOPE: "openid email"
CI_NETBIRD_MGMT_IDP: "none"
CI_NETBIRD_IDP_MGMT_CLIENT_ID: testing.client.id
CI_NETBIRD_IDP_MGMT_CLIENT_SECRET: testing.client.secret
run: |
grep AUTH_CLIENT_ID docker-compose.yml | grep $CI_NETBIRD_AUTH_CLIENT_ID
@ -83,6 +90,12 @@ jobs:
grep -A 1 ProviderConfig management.json | grep Audience | grep $CI_NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE
grep Scope management.json | grep "$CI_NETBIRD_AUTH_DEVICE_AUTH_SCOPE"
grep UseIDToken management.json | grep false
grep -A 1 IdpManagerConfig management.json | grep ManagerType | grep $CI_NETBIRD_MGMT_IDP
grep -A 3 IdpManagerConfig management.json | grep -A 1 ClientConfig | grep Issuer | grep $CI_NETBIRD_AUTH_AUTHORITY
grep -A 4 IdpManagerConfig management.json | grep -A 2 ClientConfig | grep TokenEndpoint | grep $CI_NETBIRD_AUTH_TOKEN_ENDPOINT
grep -A 5 IdpManagerConfig management.json | grep -A 3 ClientConfig | grep ClientID | grep $CI_NETBIRD_IDP_MGMT_CLIENT_ID
grep -A 6 IdpManagerConfig management.json | grep -A 4 ClientConfig | grep ClientSecret | grep $CI_NETBIRD_IDP_MGMT_CLIENT_SECRET
grep -A 7 IdpManagerConfig management.json | grep -A 5 ClientConfig | grep GrantType | grep client_credentials
- name: run docker compose up
working-directory: infrastructure_files

View File

@ -1,15 +1,13 @@
#!/bin/bash
if ! which curl > /dev/null 2>&1
then
if ! which curl >/dev/null 2>&1; then
echo "This script uses curl fetch OpenID configuration from IDP."
echo "Please install curl and re-run the script https://curl.se/"
echo ""
exit 1
fi
if ! which jq > /dev/null 2>&1
then
if ! which jq >/dev/null 2>&1; then
echo "This script uses jq to load OpenID configuration from IDP."
echo "Please install jq and re-run the script https://stedolan.github.io/jq/"
echo ""
@ -19,16 +17,13 @@ fi
source setup.env
source base.setup.env
if ! which envsubst > /dev/null 2>&1
then
if ! which envsubst >/dev/null 2>&1; then
echo "envsubst is needed to run this script"
if [[ $(uname) == "Darwin" ]]
then
if [[ $(uname) == "Darwin" ]]; then
echo "you can install it with homebrew (https://brew.sh):"
echo "brew install gettext"
else
if which apt-get > /dev/null 2>&1
then
if which apt-get >/dev/null 2>&1; then
echo "you can install it by running"
echo "apt-get update && apt-get install gettext-base"
else
@ -38,8 +33,7 @@ then
exit 1
fi
if [[ "x-$NETBIRD_DOMAIN" == "x-" ]]
then
if [[ "x-$NETBIRD_DOMAIN" == "x-" ]]; then
echo NETBIRD_DOMAIN is not set, please update your setup.env file
echo If you are migrating from old versions, you migh need to update your variables prefixes from
echo WIRETRUSTEE_.. TO NETBIRD_
@ -47,8 +41,7 @@ then
fi
# local development or tests
if [[ $NETBIRD_DOMAIN == "localhost" || $NETBIRD_DOMAIN == "127.0.0.1" ]]
then
if [[ $NETBIRD_DOMAIN == "localhost" || $NETBIRD_DOMAIN == "127.0.0.1" ]]; then
export NETBIRD_MGMT_SINGLE_ACCOUNT_MODE_DOMAIN="netbird.selfhosted"
export NETBIRD_MGMT_API_ENDPOINT=http://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
unset NETBIRD_MGMT_API_CERT_FILE
@ -56,8 +49,7 @@ then
fi
# if not provided, we generate a turn password
if [[ "x-$TURN_PASSWORD" == "x-" ]]
then
if [[ "x-$TURN_PASSWORD" == "x-" ]]; then
export TURN_PASSWORD=$(openssl rand -base64 32 | sed 's/=//g')
fi
@ -109,8 +101,7 @@ export NETBIRD_AUTH_SUPPORTED_SCOPES=$( jq -r '.scopes_supported | join(" ")' op
export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' openid-configuration.json)
export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' openid-configuration.json)
if [ $NETBIRD_USE_AUTH0 == "true" ]
then
if [ "$NETBIRD_USE_AUTH0" == "true" ]; then
export NETBIRD_AUTH_SUPPORTED_SCOPES="openid profile email offline_access api email_verified"
else
export NETBIRD_AUTH_SUPPORTED_SCOPES="openid profile email offline_access api"
@ -122,8 +113,7 @@ if [[ ! -z "${NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID}" ]]; then
fi
# Check if letsencrypt was disabled
if [[ "$NETBIRD_DISABLE_LETSENCRYPT" == "true" ]]
then
if [[ "$NETBIRD_DISABLE_LETSENCRYPT" == "true" ]]; then
export NETBIRD_DASHBOARD_ENDPOINT="https://$NETBIRD_DOMAIN:443"
export NETBIRD_SIGNAL_ENDPOINT="https://$NETBIRD_DOMAIN:$NETBIRD_SIGNAL_PORT"
@ -145,6 +135,29 @@ then
unset NETBIRD_MGMT_API_CERT_KEY_FILE
fi
# Check if management identity provider is set
if [ -n "$NETBIRD_MGMT_IDP" ]; then
EXTRA_CONFIG={}
# extract extra config from all env prefixed with NETBIRD_IDP_MGMT_EXTRA_
for var in ${!NETBIRD_IDP_MGMT_EXTRA_*}; do
# convert key snake case to camel case
key=$(
echo "${var#NETBIRD_IDP_MGMT_EXTRA_}" | awk -F "_" \
'{for (i=1; i<=NF; i++) {output=output substr($i,1,1) tolower(substr($i,2))} print output}'
)
value="${!var}"
echo "$var"
EXTRA_CONFIG=$(jq --arg k "$key" --arg v "$value" '.[$k] = $v' <<<"$EXTRA_CONFIG")
done
export NETBIRD_MGMT_IDP
export NETBIRD_IDP_MGMT_CLIENT_ID
export NETBIRD_IDP_MGMT_CLIENT_SECRET
export NETBIRD_IDP_MGMT_EXTRA_CONFIG=$EXTRA_CONFIG
fi
env | grep NETBIRD
envsubst <docker-compose.yml.tmpl >docker-compose.yml

View File

@ -38,7 +38,15 @@
"OIDCConfigEndpoint":"$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT"
},
"IdpManagerConfig": {
"Manager": "none"
"ManagerType": "$NETBIRD_MGMT_IDP",
"ClientConfig": {
"Issuer": "$NETBIRD_AUTH_AUTHORITY",
"TokenEndpoint": "$NETBIRD_AUTH_TOKEN_ENDPOINT",
"ClientID": "$NETBIRD_IDP_MGMT_CLIENT_ID",
"ClientSecret": "$NETBIRD_IDP_MGMT_CLIENT_SECRET",
"GrantType": "client_credentials"
},
"ExtraConfig": $NETBIRD_IDP_MGMT_EXTRA_CONFIG
},
"DeviceAuthorizationFlow": {
"Provider": "$NETBIRD_AUTH_DEVICE_AUTH_PROVIDER",

View File

@ -22,6 +22,11 @@ NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID=""
NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE=$NETBIRD_AUTH_AUDIENCE
NETBIRD_AUTH_DEVICE_AUTH_SCOPE="openid"
NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN=false
eg. zitadel, auth0, azure, keycloak
NETBIRD_MGMT_IDP="none"
# Some IDPs requires different client id and client secret for management api
NETBIRD_IDP_MGMT_CLIENT_ID=$NETBIRD_AUTH_CLIENT_ID
NETBIRD_IDP_MGMT_CLIENT_SECRET=""
# if your IDP provider doesn't support fragmented URIs, configure custom
# redirect and silent redirect URIs, these will be concatenated into your NETBIRD_DOMAIN domain.

View File

@ -17,3 +17,6 @@ NETBIRD_TOKEN_SOURCE="idToken"
NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE="super"
NETBIRD_AUTH_USER_ID_CLAIM="email"
NETBIRD_AUTH_DEVICE_AUTH_SCOPE="openid email"
NETBIRD_MGMT_IDP=$CI_NETBIRD_MGMT_IDP
NETBIRD_IDP_MGMT_CLIENT_ID=$CI_NETBIRD_IDP_MGMT_CLIENT_ID
NETBIRD_IDP_MGMT_CLIENT_SECRET=$CI_NETBIRD_IDP_MGMT_CLIENT_SECRET

View File

@ -0,0 +1,122 @@
#!/bin/bash
set -e
request_jwt_token() {
INSTANCE_URL=$1
BODY="grant_type=client_credentials&scope=urn:zitadel:iam:org:project:id:zitadel:aud&client_id=$ZITADEL_CLIENT_ID&client_secret=$ZITADEL_CLIENT_SECRET"
RESPONSE=$(
curl -X POST "$INSTANCE_URL/oauth/v2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "$BODY"
)
echo "$RESPONSE" | jq -r '.access_token'
}
create_new_project() {
INSTANCE_URL=$1
ACCESS_TOKEN=$2
PROJECT_NAME="NETBIRD"
RESPONSE=$(
curl -X POST "$INSTANCE_URL/management/v1/projects" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "'"$PROJECT_NAME"'"}'
)
echo "$RESPONSE" | jq -r '.id'
}
create_new_application() {
INSTANCE_URL=$1
ACCESS_TOKEN=$2
APPLICATION_NAME="netbird"
RESPONSE=$(
curl -X POST "$INSTANCE_URL/management/v1/projects/$PROJECT_ID/apps/oidc" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "'"$APPLICATION_NAME"'",
"redirectUris": [
"'"$BASE_REDIRECT_URL"'/auth"
],
"RESPONSETypes": [
"OIDC_RESPONSE_TYPE_CODE"
],
"grantTypes": [
"OIDC_GRANT_TYPE_AUTHORIZATION_CODE",
"OIDC_GRANT_TYPE_REFRESH_TOKEN"
],
"appType": "OIDC_APP_TYPE_USER_AGENT",
"authMethodType": "OIDC_AUTH_METHOD_TYPE_NONE",
"postLogoutRedirectUris": [
"'"$BASE_REDIRECT_URL"'/silent-auth"
],
"version": "OIDC_VERSION_1_0",
"devMode": '"$ZITADEL_DEV_MODE"',
"accessTokenType": "OIDC_TOKEN_TYPE_JWT",
"accessTokenRoleAssertion": true,
"skipNativeAppSuccessPage": true
}'
)
echo "$RESPONSE" | jq -r '.clientId'
}
configure_zitadel_instance() {
# extract zitadel instance url
INSTANCE_URL=$(echo "$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT" | sed 's/\/\.well-known\/openid-configuration//')
DOC_URL="https://netbird.io/docs/integrations/identity-providers/self-hosted/using-netbird-with-zitadel#step-4-create-a-service-user"
echo ""
printf "configuring zitadel instance: $INSTANCE_URL \n \
before proceeding, please create a new service account for authorization by following the instructions (step 4 and 5
) in the documentation at %s\n" "$DOC_URL"
echo "Please ensure that the new service account has 'Org Owner' permission in order for this to work."
echo ""
read -n 1 -s -r -p "press any key to continue..."
echo ""
# prompt the user to enter service account clientID
echo ""
read -r -p "enter service account ClientId: " ZITADEL_CLIENT_ID
echo ""
# Prompt the user to enter service account clientSecret
read -r -p "enter service account ClientSecret: " ZITADEL_CLIENT_SECRET
echo ""
# get an access token from zitadel
echo "retrieving access token from zitadel"
ACCESS_TOKEN=$(request_jwt_token "$INSTANCE_URL")
if [ "$ACCESS_TOKEN" = "null" ]; then
echo "failed requesting access token"
exit 1
fi
# create the zitadel project
echo "creating new zitadel project"
PROJECT_ID=$(create_new_project "$INSTANCE_URL" "$ACCESS_TOKEN")
if [ "$PROJECT_ID" = "null" ]; then
echo "failed creating new zitadel project"
exit 1
fi
ZITADEL_DEV_MODE=false
if [[ $NETBIRD_DOMAIN == *"localhost"* ]]; then
BASE_REDIRECT_URL="http://$NETBIRD_DOMAIN"
ZITADEL_DEV_MODE=true
else
BASE_REDIRECT_URL="https://$NETBIRD_DOMAIN"
fi
# create zitadel spa application
echo "creating new zitadel spa application"
APPLICATION_CLIENT_ID=$(create_new_application "$INSTANCE_URL" "$ACCESS_TOKEN")
if [ "$APPLICATION_CLIENT_ID" = "null" ]; then
echo "failed creating new zitadel spa application"
exit 1
fi
}

View File

@ -84,6 +84,10 @@ type JWTToken struct {
// NewManager returns a new idp manager based on the configuration that it receives
func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) {
if config.ClientConfig != nil {
config.ClientConfig.Issuer = strings.TrimSuffix(config.ClientConfig.Issuer, "/")
}
switch strings.ToLower(config.ManagerType) {
case "none", "":
return nil, nil
@ -108,8 +112,8 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error)
ClientSecret: config.ClientConfig.ClientSecret,
GrantType: config.ClientConfig.GrantType,
TokenEndpoint: config.ClientConfig.TokenEndpoint,
ObjectID: config.ExtraConfig["ObjectID"],
GraphAPIEndpoint: config.ExtraConfig["GraphAPIEndpoint"],
ObjectID: config.ExtraConfig["ObjectId"],
GraphAPIEndpoint: config.ExtraConfig["GraphApiEndpoint"],
}
}
@ -155,7 +159,7 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error)
Issuer: config.ClientConfig.Issuer,
TokenEndpoint: config.ClientConfig.TokenEndpoint,
GrantType: config.ClientConfig.GrantType,
APIToken: config.ExtraConfig["APIToken"],
APIToken: config.ExtraConfig["ApiToken"],
}
return NewOktaManager(oktaClientConfig, appMetrics)