Merge pull request #198820 from talyz/keycloak-admin-password

This commit is contained in:
Martin Weinelt 2022-11-19 15:03:03 +01:00 committed by GitHub
commit 2714a22521
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 9 deletions

View file

@ -482,6 +482,10 @@ in
assertion = (cfg.database.useSSL && cfg.database.type == "postgresql") -> (cfg.database.caCert != null); assertion = (cfg.database.useSSL && cfg.database.type == "postgresql") -> (cfg.database.caCert != null);
message = "A CA certificate must be specified (in 'services.keycloak.database.caCert') when PostgreSQL is used with SSL"; message = "A CA certificate must be specified (in 'services.keycloak.database.caCert') when PostgreSQL is used with SSL";
} }
{
assertion = createLocalPostgreSQL -> config.services.postgresql.settings.standard_conforming_strings or true;
message = "Setting up a local PostgreSQL db for Keycloak requires `standard_conforming_strings` turned on to work reliably";
}
]; ];
environment.systemPackages = [ keycloakBuild ]; environment.systemPackages = [ keycloakBuild ];
@ -544,7 +548,13 @@ in
create_role="$(mktemp)" create_role="$(mktemp)"
trap 'rm -f "$create_role"' EXIT trap 'rm -f "$create_role"' EXIT
# Read the password from the credentials directory and
# escape any single quotes by adding additional single
# quotes after them, following the rules laid out here:
# https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS
db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")" db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")"
db_password="''${db_password//\'/\'\'}"
echo "CREATE ROLE keycloak WITH LOGIN PASSWORD '$db_password' CREATEDB" > "$create_role" echo "CREATE ROLE keycloak WITH LOGIN PASSWORD '$db_password' CREATEDB" > "$create_role"
psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='keycloak'" | grep -q 1 || psql -tA --file="$create_role" psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='keycloak'" | grep -q 1 || psql -tA --file="$create_role"
psql -tAc "SELECT 1 FROM pg_database WHERE datname = 'keycloak'" | grep -q 1 || psql -tAc 'CREATE DATABASE "keycloak" OWNER "keycloak"' psql -tAc "SELECT 1 FROM pg_database WHERE datname = 'keycloak'" | grep -q 1 || psql -tAc 'CREATE DATABASE "keycloak" OWNER "keycloak"'
@ -566,8 +576,16 @@ in
script = '' script = ''
set -o errexit -o pipefail -o nounset -o errtrace set -o errexit -o pipefail -o nounset -o errtrace
shopt -s inherit_errexit shopt -s inherit_errexit
# Read the password from the credentials directory and
# escape any single quotes by adding additional single
# quotes after them, following the rules laid out here:
# https://dev.mysql.com/doc/refman/8.0/en/string-literals.html
db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")" db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")"
( echo "CREATE USER IF NOT EXISTS 'keycloak'@'localhost' IDENTIFIED BY '$db_password';" db_password="''${db_password//\'/\'\'}"
( echo "SET sql_mode = 'NO_BACKSLASH_ESCAPES';"
echo "CREATE USER IF NOT EXISTS 'keycloak'@'localhost' IDENTIFIED BY '$db_password';"
echo "CREATE DATABASE IF NOT EXISTS keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;" echo "CREATE DATABASE IF NOT EXISTS keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;"
echo "GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';" echo "GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';"
) | mysql -N ) | mysql -N
@ -632,12 +650,17 @@ in
${secretReplacements} ${secretReplacements}
# Escape any backslashes in the db parameters, since
# they're otherwise unexpectedly read as escape
# sequences.
sed -i '/db-/ s|\\|\\\\|g' /run/keycloak/conf/keycloak.conf
'' + optionalString (cfg.sslCertificate != null && cfg.sslCertificateKey != null) '' '' + optionalString (cfg.sslCertificate != null && cfg.sslCertificateKey != null) ''
mkdir -p /run/keycloak/ssl mkdir -p /run/keycloak/ssl
cp $CREDENTIALS_DIRECTORY/ssl_{cert,key} /run/keycloak/ssl/ cp $CREDENTIALS_DIRECTORY/ssl_{cert,key} /run/keycloak/ssl/
'' + '' '' + ''
export KEYCLOAK_ADMIN=admin export KEYCLOAK_ADMIN=admin
export KEYCLOAK_ADMIN_PASSWORD=${cfg.initialAdminPassword} export KEYCLOAK_ADMIN_PASSWORD=${escapeShellArg cfg.initialAdminPassword}
kc.sh start --optimized kc.sh start --optimized
''; '';
}; };

View file

@ -5,10 +5,13 @@
let let
certs = import ./common/acme/server/snakeoil-certs.nix; certs = import ./common/acme/server/snakeoil-certs.nix;
frontendUrl = "https://${certs.domain}"; frontendUrl = "https://${certs.domain}";
initialAdminPassword = "h4IhoJFnt2iQIR9";
keycloakTest = import ./make-test-python.nix ( keycloakTest = import ./make-test-python.nix (
{ pkgs, databaseType, ... }: { pkgs, databaseType, ... }:
let
initialAdminPassword = "h4Iho\"JFn't2>iQIR9";
adminPasswordFile = pkgs.writeText "admin-password" "${initialAdminPassword}";
in
{ {
name = "keycloak"; name = "keycloak";
meta = with pkgs.lib.maintainers; { meta = with pkgs.lib.maintainers; {
@ -37,7 +40,7 @@ let
type = databaseType; type = databaseType;
username = "bogus"; username = "bogus";
name = "also bogus"; name = "also bogus";
passwordFile = "${pkgs.writeText "dbPassword" "wzf6vOCbPp6cqTH"}"; passwordFile = "${pkgs.writeText "dbPassword" ''wzf6\"vO"Cb\nP>p#6;c&o?eu=q'THE'''H''''E''}";
}; };
plugins = with config.services.keycloak.package.plugins; [ plugins = with config.services.keycloak.package.plugins; [
keycloak-discord keycloak-discord
@ -111,7 +114,7 @@ let
keycloak.succeed(""" keycloak.succeed("""
curl -sSf -d 'client_id=admin-cli' \ curl -sSf -d 'client_id=admin-cli' \
-d 'username=admin' \ -d 'username=admin' \
-d 'password=${initialAdminPassword}' \ -d "password=$(<${adminPasswordFile})" \
-d 'grant_type=password' \ -d 'grant_type=password' \
'${frontendUrl}/realms/master/protocol/openid-connect/token' \ '${frontendUrl}/realms/master/protocol/openid-connect/token' \
| jq -r '"Authorization: bearer " + .access_token' >admin_auth_header | jq -r '"Authorization: bearer " + .access_token' >admin_auth_header
@ -119,10 +122,10 @@ let
# Register the metrics SPI # Register the metrics SPI
keycloak.succeed( keycloak.succeed(
"${pkgs.jre}/bin/keytool -import -alias snakeoil -file ${certs.ca.cert} -storepass aaaaaa -keystore cacert.jks -noprompt", """${pkgs.jre}/bin/keytool -import -alias snakeoil -file ${certs.ca.cert} -storepass aaaaaa -keystore cacert.jks -noprompt""",
"KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' kcadm.sh config credentials --server '${frontendUrl}' --realm master --user admin --password '${initialAdminPassword}'", """KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' kcadm.sh config credentials --server '${frontendUrl}' --realm master --user admin --password "$(<${adminPasswordFile})" """,
"KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' kcadm.sh update events/config -s 'eventsEnabled=true' -s 'adminEventsEnabled=true' -s 'eventsListeners+=metrics-listener'", """KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' kcadm.sh update events/config -s 'eventsEnabled=true' -s 'adminEventsEnabled=true' -s 'eventsListeners+=metrics-listener'""",
"curl -sSf '${frontendUrl}/realms/master/metrics' | grep '^keycloak_admin_event_UPDATE'" """curl -sSf '${frontendUrl}/realms/master/metrics' | grep '^keycloak_admin_event_UPDATE'"""
) )
# Publish the realm, including a test OIDC client and user # Publish the realm, including a test OIDC client and user