diff --git a/server/pbenchinacan/etc/pbench-server/pbench-server.cfg b/server/pbenchinacan/etc/pbench-server/pbench-server.cfg index 1aa325c397..37e3f71362 100644 --- a/server/pbenchinacan/etc/pbench-server/pbench-server.cfg +++ b/server/pbenchinacan/etc/pbench-server/pbench-server.cfg @@ -24,7 +24,9 @@ uri = postgresql://pbenchcontainer:pbench@localhost:5432/pbenchcontainer secret-key = "pbench-in-a-can secret shhh" [openid] -server_url = https://localhost:8090 +server_url = ##KEYCLOAK_SERVER_URL## +realm = ##KEYCLOAK_REALM## +client = ##KEYCLOAK_CLIENT## # Provide a CA cert for the pbenchinacan Keycloak server connection. tls_ca_file = /etc/pki/tls/certs/pbench_CA.crt diff --git a/server/pbenchinacan/load_keycloak.sh b/server/pbenchinacan/load_keycloak.sh index 5344bc5cb6..d1d0bbae76 100755 --- a/server/pbenchinacan/load_keycloak.sh +++ b/server/pbenchinacan/load_keycloak.sh @@ -13,12 +13,14 @@ # The script defaults to using master realm username/password as admin/admin # unless specified otherwise by 'ADMIN_USERNAME' and 'ADMIN_PASSWORD' env -# variables. The script also defaults the keycloak redirect URI as -# "https://localhost:8443/*" unless specified otherwise by 'KEYCLOAK_REDIRECT_URI' -# env variable. +# variables. The script constructs the Keycloak redirect URI list as +# "https://:8443/*" from the space-separated list of nodes in +# the 'KEYCLOAK_REDIRECT_HOSTS' env variable, defaulting to 'localhost' plus +# whatever we can glean from the 'hostname' command. It adds to that list the +# value of 'KEYCLOAK_DEV_REDIRECT' which defaults to "http://localhost:3000/*". KEYCLOAK_HOST_PORT=${KEYCLOAK_HOST_PORT:-"https://localhost:8090"} -KEYCLOAK_REDIRECT_URI=${KEYCLOAK_REDIRECT_URI:-"https://localhost:8443/*"} +KEYCLOAK_REDIRECT_HOSTS=${KEYCLOAK_REDIRECT_HOSTS:-"localhost $(hostname -A) $(hostname -f) 127.0.0.1 ::1 $(hostname -I)"} KEYCLOAK_DEV_REDIRECT=${KEYCLOAK_DEV_REDIRECT:-"http://localhost:3000/*"} ADMIN_USERNAME=${ADMIN_USERNAME:-"admin"} ADMIN_PASSWORD=${ADMIN_PASSWORD:-"admin"} @@ -34,6 +36,16 @@ export CURL_CA_BUNDLE=${CURL_CA_BUNDLE:-"${PWD}/server/pbenchinacan/etc/pki/tls/ end_in_epoch_secs=$(date --date "2 minutes" +%s) +keycloak_redirect_uris="\"${KEYCLOAK_DEV_REDIRECT}\"" +for n in ${KEYCLOAK_REDIRECT_HOSTS}; do + if [[ $n =~ ^[0-9a-f]{0,4}(:[0-9a-f]{0,4}){1,8}$ ]]; then + n="[$n]" # IPv6 addresses must be wrapped in square-brackets + fi + keycloak_redirect_uris="${keycloak_redirect_uris}, \"https://${n}:8443/*\"" +done + +echo "Keycloak redirect URI list is <${keycloak_redirect_uris}>." + # Run the custom configuration ADMIN_TOKEN="" @@ -64,7 +76,7 @@ status_code=$(curl -f -s -o /dev/null -w "%{http_code}" -X POST \ "${KEYCLOAK_HOST_PORT}/admin/realms" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ - -d '{"realm": "'${REALM}'", "enabled": true}') + -d '{"realm": "'"${REALM}"'", "enabled": true}') if [[ "${status_code}" != "201" ]]; then echo "Realm creation failed with ${status_code}" @@ -99,7 +111,7 @@ curl -si -f -X POST \ "protocolMapper": "oidc-audience-mapper", "consentRequired": false, "config": { - "included.client.audience": "'${CLIENT}'", + "included.client.audience": "'"${CLIENT}"'", "id.token.claim": "false", "access.token.claim": "true" } @@ -111,16 +123,16 @@ CLIENT_CONF=$(curl -si -f -X POST \ "${KEYCLOAK_HOST_PORT}/admin/realms/${REALM}/clients" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ - -d '{"clientId": "'${CLIENT}'", + -d '{"clientId": "'"${CLIENT}"'", "publicClient": true, "defaultClientScopes": ["pbench", "openid", "profile", "email"], "directAccessGrantsEnabled": true, "serviceAccountsEnabled": true, "enabled": true, "attributes": {"post.logout.redirect.uris": "+"}, - "redirectUris": ["'${KEYCLOAK_REDIRECT_URI}'", "'${KEYCLOAK_DEV_REDIRECT}'"]}') + "redirectUris": ['"${keycloak_redirect_uris}"']}') -CLIENT_ID=$(grep -o -e 'https://[^[:space:]]*' <<< ${CLIENT_CONF} | sed -e 's|.*/||') +CLIENT_ID=$(grep -o -e 'https://[^[:space:]]*' <<< "${CLIENT_CONF}" | sed -e 's|.*/||') if [[ -z "${CLIENT_ID}" ]]; then echo "${CLIENT} id is empty" exit 1 @@ -155,7 +167,7 @@ USER=$(curl -si -f -X POST \ -H "Content-Type: application/json" \ -d '{"username": "admin", "enabled": true, "credentials": [{"type": "password", "value": "123", "temporary": false}]}') -USER_ID=$(grep -o -e 'https://[^[:space:]]*' <<< ${USER} | sed -e 's|.*/||') +USER_ID=$(grep -o -e 'https://[^[:space:]]*' <<< "${USER}" | sed -e 's|.*/||') if [[ -z "${USER_ID}" ]]; then echo "User id is empty" @@ -168,7 +180,7 @@ status_code=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ "${KEYCLOAK_HOST_PORT}/admin/realms/${REALM}/users/${USER_ID}/role-mappings/clients/${CLIENT_ID}" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ - -d '[{"id":"'${ROLE_ID}'","name":"ADMIN"}]') + -d '[{"id":"'"${ROLE_ID}"'","name":"ADMIN"}]') if [[ "${status_code}" != "204" ]]; then echo "Assigning 'ADMIN' client role to the user 'admin' failed with ${status_code}" diff --git a/server/pbenchinacan/run-pbench-in-a-can b/server/pbenchinacan/run-pbench-in-a-can index 4461a5eb98..b0fe85ed9a 100755 --- a/server/pbenchinacan/run-pbench-in-a-can +++ b/server/pbenchinacan/run-pbench-in-a-can @@ -24,19 +24,41 @@ export PB_SERVER_IMAGE_PULL_POLICY="${PB_SERVER_IMAGE_PULL_POLICY:-${PB_COMMON_I # Directory to use for the fully built dashboard code. export PB_DASHBOARD_DIR="${PB_DASHBOARD_DIR:-${PWD}/dashboard/build/}" +# Keycloak realm and client IDs to be used by the load_keycloak.sh script and +# the pbench-server.cfg file. export KEYCLOAK_REALM=${KEYCLOAK_REALM:-"pbench-server"} export KEYCLOAK_CLIENT=${KEYCLOAK_CLIENT:-"pbench-client"} -# Note: the value of PB_HOST_IP will be used to generate the TLS certificate -# and so it (not `localhost`) must also be used to access the Pbench Server; -# otherwise, the TLS validation will fail due to a host mismatch. -if [[ -z "${PB_HOST_IP}" ]]; then - host_ip_list=$(hostname -I) - PB_HOST_IP=${host_ip_list%% *} - export PB_HOST_IP -fi +# Name or IP address to be used by the client to access the Pbench Server, to +# load the Dashboard, and to interface with the canned Keycloak server +host_name=${PB_HOST:-localhost} -host_name=${PB_HOST_NAME:-$(hostname --fqdn)} +# Set a value for the -addext "subjectAltName=..." option to the cert creation. +# Set the initial value "manually" and skip the "dummy" value to make the +# comma-separated concatenations work nicely. +# +# Notes about the use of `readarray`: in order for the output array to be +# visible to the rest of the commands, the `readarray` command must not be +# executed in a subprocess, and therefore it cannot be on the receiving end +# of a pipe. Instead we execute the `hostname` command in a "command +# expansion" inside a "here string". Unfortunately, this causes a newline +# to be appended to the output, so that if we divide the result on spaces +# we end up with an extra array entry containing just a newline. So, instead +# we translate the spaces into newlines ("squeezing" out any repeated +# delimiters) and use the `readarray` default delimiter which is the newline. +subj_alt_name="DNS.1:localhost" +readarray -t cert_hostnames <<< "$(echo "dummy $(hostname -A)" | tr -s ' ' '\n')" +for ((i=1; i < ${#cert_hostnames[*]}; i++)); do + subj_alt_name+=", DNS.$((i+1)):${cert_hostnames[i]}" +done +readarray -t cert_ipaddrs <<< "$(echo "127.0.0.1 ::1 $(hostname -I)" | tr -s ' ' '\n')" +for ((i=0; i < ${#cert_ipaddrs[*]}; i++)); do + subj_alt_name+=", IP.$((i+1)):${cert_ipaddrs[i]}" +done +echo "subjectAltName is <${subj_alt_name}>." + +grep -q ${host_name} <<< ${subj_alt_name} \ + || echo "Warning: requested host name/addr (${host_name}) is not covered by the TLS cert." >&2 # Set up TMP_DIR, if it's not already defined, to point to WORKSPACE_TMP, if it # is defined (e.g., by the CI), or to `/var/tmp/pbench` as a fallback. @@ -65,8 +87,9 @@ cp ${pbiac_etc}/pbench-server/pbench-server.cfg ${PB_DEPLOY_FILES}/ # Customize the Pbench Server config file for canned operation sed -Ei \ -e "/^ *realhost/ s/=.*/= $(hostname -f)/" \ - -e "s//${KEYCLOAK_REALM}/" \ - -e "s//${KEYCLOAK_CLIENT}/" \ + -e "s|##KEYCLOAK_SERVER_URL##|https://${host_name}:8090|" \ + -e "s/##KEYCLOAK_REALM##/${KEYCLOAK_REALM}/" \ + -e "s/##KEYCLOAK_CLIENT##/${KEYCLOAK_CLIENT}/" \ -e "s/##ADMIN_NAMES##/${PB_ADMIN_NAMES}/" \ ${PB_DEPLOY_FILES}/pbench-server.cfg @@ -132,7 +155,7 @@ podman run \ -addext "authorityKeyIdentifier = keyid,issuer" \ -addext "basicConstraints=CA:FALSE" \ -addext "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment" \ - -addext "subjectAltName = IP.2:${PB_HOST_IP}, DNS:localhost" \ + -addext "subjectAltName = ${subj_alt_name}" \ 2>&1 | sed -E -e '/^[.+*-]*$/ d' chmod 0640 ${PB_DEPLOY_FILES}/pbench-server.key