diff --git a/services/keycloak/startup-scripts/00-configure-lagoon.sh b/services/keycloak/startup-scripts/00-configure-lagoon.sh index 6652a26aca..518770419c 100755 --- a/services/keycloak/startup-scripts/00-configure-lagoon.sh +++ b/services/keycloak/startup-scripts/00-configure-lagoon.sh @@ -35,18 +35,6 @@ function sync_client_secrets { fi } -############## -# Migrations # -############## - -# This script runs on every keycloak startup and needs to be idempotent. It also -# has to handle both use cases of installing a fresh keycloak (new cluster, CI, -# etc) and updating existing ones (e.g, prod). For those reasons, every -# migration must be designed to run __only once__ per keycloak install. Once a -# function is released, it should be considered "final." -# -# The "standard" update mechanism is to first check if some data exists that -# would've been created by the function, and halting execution if found. function import_lagoon_realm { # handle importing a realm from a snapshot of a raw install of 2.16.0 @@ -136,2220 +124,61 @@ function configure_realm_settings { } -function configure_opendistro_security_client { - - # delete old SearchGuard Clients - searchguard_client_id=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=searchguard --config $CONFIG_PATH) - if [ "$searchguard_client_id" != "[ ]" ]; then - echo "Client searchguard is exising, will delete" - SEARCHGUARD_CLIENT_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=searchguard --config $CONFIG_PATH | jq -r '.[0]["id"]') - /opt/keycloak/bin/kcadm.sh delete clients/${SEARCHGUARD_CLIENT_ID} --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} - fi - lagoon_searchguard_client_id=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=lagoon-searchguard --config $CONFIG_PATH) - if [ "$lagoon_searchguard_client_id" != "[ ]" ]; then - echo "Client lagoon-searchguard is exising, will delete" - LAGOON_SEARCHGUARD_CLIENT_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=lagoon-searchguard --config $CONFIG_PATH | jq -r '.[0]["id"]') - /opt/keycloak/bin/kcadm.sh delete clients/${LAGOON_SEARCHGUARD_CLIENT_ID} --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} - fi - - - opendistro_security_client_id=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=lagoon-opendistro-security --config $CONFIG_PATH) - if [ "$opendistro_security_client_id" != "[ ]" ]; then - echo "Client lagoon-opendistro-security is already created, skipping setup" - return 0 - fi - - # Configure keycloak for lagoon-opendistro-security - echo Creating client lagoon-opendistro-security - local SECRET=$(openssl rand -hex 16) - echo '{"clientId": "lagoon-opendistro-security", "webOrigins": ["*"], "redirectUris": ["*"], "secret": "'$SECRET'"}' | /opt/keycloak/bin/kcadm.sh create clients --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating mapper for lagoon-opendistro-security "groups" - CLIENT_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=lagoon-opendistro-security --config $CONFIG_PATH | jq -r '.[0]["id"]') - echo '{"name":"groups","protocolMapper":"script-mappers/groups-and-roles.js","protocol":"openid-connect","config":{"id.token.claim":"true","access.token.claim":"true","userinfo.token.claim":"true","multivalued":"true","claim.name":"groups","jsonType.label":"String"}}' | /opt/keycloak/bin/kcadm.sh create -r ${KEYCLOAK_REALM:-master} clients/$CLIENT_ID/protocol-mappers/models --config $CONFIG_PATH -f - - -} - -function configure_api_client { - api_client_id=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=api --config $CONFIG_PATH) - if [ "$api_client_id" != "[ ]" ]; then - echo "Client api is already created, skipping basic setup" - return 0 - fi - - # Enable username edit - /opt/keycloak/bin/kcadm.sh update realms/${KEYCLOAK_REALM:-master} --config $CONFIG_PATH -s editUsernameAllowed=true - - echo Creating client auth-server - echo '{"clientId": "auth-server", "publicClient": false, "standardFlowEnabled": false, "serviceAccountsEnabled": true, "secret": "'$KEYCLOAK_AUTH_SERVER_CLIENT_SECRET'"}' | /opt/keycloak/bin/kcadm.sh create clients --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - AUTH_SERVER_CLIENT_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=auth-server --config $CONFIG_PATH | jq -r '.[0]["id"]') - REALM_MANAGEMENT_CLIENT_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=realm-management --config $CONFIG_PATH | jq -r '.[0]["id"]') - echo Enable auth-server token exchange - # 1 Enable fine grained admin permissions for users - /opt/keycloak/bin/kcadm.sh update users-management-permissions --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -s enabled=true - # 2 Enable fine grained admin perions for client - /opt/keycloak/bin/kcadm.sh update clients/$AUTH_SERVER_CLIENT_ID/management/permissions --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -s enabled=true - # 3 Create policy for auth-server client - echo '{"type":"client","logic":"POSITIVE","decisionStrategy":"UNANIMOUS","name":"Client auth-server Policy","clients":["'$AUTH_SERVER_CLIENT_ID'"]}' | /opt/keycloak/bin/kcadm.sh create clients/$REALM_MANAGEMENT_CLIENT_ID/authz/resource-server/policy/client --config $CONFIG_PATH -r lagoon -f - - AUTH_SERVER_CLIENT_POLICY_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients/$REALM_MANAGEMENT_CLIENT_ID/authz/resource-server/policy?name=Client+auth-server+Policy --config $CONFIG_PATH | jq -r '.[0]["id"]') - # 4 Update user impersonate permission to add client policy (PUT) - IMPERSONATE_PERMISSION_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients/$REALM_MANAGEMENT_CLIENT_ID/authz/resource-server/permission?name=admin-impersonating.permission.users --config $CONFIG_PATH | jq -r '.[0]["id"]') - /opt/keycloak/bin/kcadm.sh update clients/$REALM_MANAGEMENT_CLIENT_ID/authz/resource-server/permission/scope/$IMPERSONATE_PERMISSION_ID --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -s 'policies=["'$AUTH_SERVER_CLIENT_POLICY_ID'"]' - - - - # Setup composite roles. Each role will include the roles to the left of it - composite_role_names=(guest reporter developer maintainer owner) - composites_add=() - for crn_key in ${!composite_role_names[@]}; do - echo Creating role ${composite_role_names[$crn_key]} - /opt/keycloak/bin/kcadm.sh create roles --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -s composite=true -s name=${composite_role_names[$crn_key]} - - for ca_key in ${!composites_add[@]}; do - /opt/keycloak/bin/kcadm.sh add-roles --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} --rname ${composite_role_names[$crn_key]} --rolename ${composites_add[$ca_key]} - done - - composites_add+=(${composite_role_names[$crn_key]}) - done - - # Setup platform wide roles. - /opt/keycloak/bin/kcadm.sh create roles --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -s name=platform-owner - /opt/keycloak/bin/kcadm.sh add-roles --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} --rname admin --rolename platform-owner - - # Configure keycloak for api - echo Creating client api - echo '{"clientId": "api", "publicClient": false, "standardFlowEnabled": false, "serviceAccountsEnabled": true, "authorizationServicesEnabled": true, "secret": "'$KEYCLOAK_API_CLIENT_SECRET'"}' | /opt/keycloak/bin/kcadm.sh create clients --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - CLIENT_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients?clientId=api --config $CONFIG_PATH | jq -r '.[0]["id"]') - ADMIN_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/admin --config $CONFIG_PATH | jq -r '.["id"]') - GUEST_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/guest --config $CONFIG_PATH | jq -r '.["id"]') - REPORTER_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/reporter --config $CONFIG_PATH | jq -r '.["id"]') - DEVELOPER_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/developer --config $CONFIG_PATH | jq -r '.["id"]') - MAINTAINER_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/maintainer --config $CONFIG_PATH | jq -r '.["id"]') - OWNER_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/owner --config $CONFIG_PATH | jq -r '.["id"]') - PLATFORM_OWNER_ROLE_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon roles/platform-owner --config $CONFIG_PATH | jq -r '.["id"]') - - # Resource Scopes - resource_scope_names=(add add:development add:production addGroup addNoExec addNotification addOrUpdate:development addOrUpdate:production addUser delete delete:development delete:production deleteAll deleteNoExec deploy:development deploy:production drushArchiveDump:development drushArchiveDump:production drushCacheClear:development drushCacheClear:production drushRsync:destination:development drushRsync:destination:production drushRsync:source:development drushRsync:source:production drushSqlDump:development drushSqlDump:production drushSqlSync:destination:development drushSqlSync:destination:production drushSqlSync:source:development drushSqlSync:source:production environment:add:development environment:add:production environment:view:development environment:view:production getBySshKey invoke:guest invoke:developer invoke:maintainer create:advanced delete:advanced project:add project:view removeAll removeGroup removeNotification removeUser ssh:development ssh:production storage update update:development update:production view view:token view:user viewAll viewPrivateKey) - for rsn_key in ${!resource_scope_names[@]}; do - echo Creating resource scope ${resource_scope_names[$rsn_key]} - /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/scope --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -s name=${resource_scope_names[$rsn_key]} - done - - # Resources with scopes - echo Creating resource backup - echo '{"name":"backup","displayName":"backup","scopes":[{"name":"view"},{"name":"add"},{"name":"delete"},{"name":"deleteAll"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource restore - echo '{"name":"restore","displayName":"restore","scopes":[{"name":"add"},{"name":"addNoExec"},{"name":"update"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource deployment - echo '{"name":"deployment","displayName":"deployment","scopes":[{"name":"view"},{"name":"update"},{"name":"delete"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource env_var - echo '{"name":"env_var","displayName":"env_var","scopes":[{"name":"project:view"},{"name":"project:add"},{"name":"environment:view:production"},{"name":"environment:view:development"},{"name":"environment:add:production"},{"name":"environment:add:development"},{"name":"delete"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource task - echo '{"name":"task","displayName":"task","scopes":[{"name":"view"},{"name":"update"},{"name":"delete"},{"name":"add:production"},{"name":"add:development"},{"name":"addNoExec"},{"name":"drushArchiveDump:development"},{"name":"drushArchiveDump:production"},{"name":"drushSqlDump:development"},{"name":"drushSqlDump:production"},{"name":"drushCacheClear:development"},{"name":"drushCacheClear:production"},{"name":"drushSqlSync:source:development"},{"name":"drushSqlSync:source:production"},{"name":"drushSqlSync:destination:development"},{"name":"drushSqlSync:destination:production"},{"name":"drushRsync:source:development"},{"name":"drushRsync:source:production"},{"name":"drushRsync:destination:development"},{"name":"drushRsync:destination:production"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource openshift - echo '{"name":"openshift","displayName":"openshift","scopes":[{"name":"add"},{"name":"delete"},{"name":"update"},{"name":"deleteAll"},{"name":"view"},{"name":"viewAll"},{"name":"view:token"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource user - echo '{"name":"user","displayName":"user","scopes":[{"name":"add"},{"name":"getBySshKey"},{"name":"update"},{"name":"delete"},{"name":"deleteAll"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource environment - echo '{"name":"environment","displayName":"environment","scopes":[{"name":"ssh:production"},{"name":"ssh:development"},{"name":"view"},{"name":"deploy:production"},{"name":"deploy:development"},{"name":"addOrUpdate:production"},{"name":"addOrUpdate:development"},{"name":"storage"},{"name":"delete:production"},{"name":"delete:development"},{"name":"deleteNoExec"},{"name":"update:production"},{"name":"update:development"},{"name":"viewAll"},{"name":"deleteAll"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource project - echo '{"name":"project","displayName":"project","scopes":[{"name":"update"},{"name":"add"},{"name":"addGroup"},{"name":"removeGroup"},{"name":"addNotification"},{"name":"removeNotification"},{"name":"view"},{"name":"delete"},{"name":"deleteAll"},{"name":"viewAll"},{"name":"viewPrivateKey"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource group - echo '{"name":"group","displayName":"group","scopes":[{"name":"add"},{"name":"update"},{"name":"delete"},{"name":"deleteAll"},{"name":"addUser"},{"name":"removeUser"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource notification - echo '{"name":"notification","displayName":"notification","scopes":[{"name":"add"},{"name":"delete"},{"name":"view"},{"name":"deleteAll"},{"name":"removeAll"},{"name":"update"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - echo Creating resource ssh_key - echo '{"name":"ssh_key","displayName":"ssh_key","scopes":[{"name":"view:user"},{"name":"view:project"},{"name":"add"},{"name":"deleteAll"},{"name":"removeAll"},{"name":"update"},{"name":"delete"}],"attributes":{},"uris":[],"ownerManagedAccess":""}' | /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/resource --config $CONFIG_PATH -r ${KEYCLOAK_REALM:-master} -f - - - # Authorization policies - echo Creating api authz js policies - - # List of all policies that need migrating - local policies='User has access to own data;User has access to project;Users role for group is Owner;Users role for group is Maintainer;Users role for group is Developer;Users role for group is Reporter;Users role for group is Guest;Users role for project is Owner;Users role for project is Maintainer;Users role for project is Developer;Users role for project is Reporter;Users role for project is Guest;Users role for realm is Admin;Users role for realm is Platform Owner' - - OLDIFS=$IFS;IFS=";"; - local p_name - for p_name in $policies - do - echo "Creating '$p_name' policy" - # Add the new script based policy to the api client - local script_name="$p_name" - local script_type="script-policies/$(echo $p_name | sed -e 's/.*/\L&/' -e 's/ /-/g').js" - echo '{"name":"'$script_name'","type":"'$script_type'"}' | /opt/keycloak/bin/kcadm.sh create -r lagoon clients/$CLIENT_ID/authz/resource-server/policy/$(echo $script_type | sed -e 's/\//%2F/') --config $CONFIG_PATH -f - - done - IFS=$OLDIFS - - #Authorization permissions - echo Creating api authz permissions - DEFAULT_PERMISSION_ID=$(/opt/keycloak/bin/kcadm.sh get -r lagoon clients/$CLIENT_ID/authz/resource-server/permission?name=Default+Permission --config $CONFIG_PATH | jq -r '.[0]["id"]') - /opt/keycloak/bin/kcadm.sh delete -r lagoon clients/$CLIENT_ID/authz/resource-server/permission/$DEFAULT_PERMISSION_ID --config $CONFIG_PATH - - - /opt/keycloak/bin/kcadm.sh create clients/$CLIENT_ID/authz/resource-server/permission/scope --config $CONFIG_PATH -r lagoon -f - <