keycloak: Switch to the new Quarkus version of Keycloak

With version 17 of Keycloak, the Wildfly based distribution was
deprecated in favor of the one based on Quarkus. The difference in
configuration is massive and to accommodate it, both the package and
module had to be rewritten.
main
talyz 2 years ago
parent 920784e80a
commit ed30d3b02f
No known key found for this signature in database
GPG Key ID: 2DED2151F4671A2B
  1. 125
      nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
  2. 75
      nixos/doc/manual/release-notes/rl-2205.section.md
  3. 873
      nixos/modules/services/web-apps/keycloak.nix
  4. 142
      nixos/modules/services/web-apps/keycloak.xml
  5. 22
      nixos/tests/keycloak.nix
  6. 98
      pkgs/servers/keycloak/default.nix

@ -643,6 +643,131 @@
updated.
</para>
</listitem>
<listitem>
<para>
The Keycloak package (<literal>pkgs.keycloak</literal>) has
been switched from the Wildfly version, which will soon be
deprecated, to the Quarkus based version. The Keycloak service
(<literal>services.keycloak</literal>) has been updated to
accommodate the change and now differs from the previous
version in a few ways:
</para>
<itemizedlist>
<listitem>
<para>
<literal>services.keycloak.extraConfig</literal> has been
removed in favor of the new
<link xlink:href="https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md">settings-style</link>
<link linkend="opt-services.keycloak.settings"><literal>services.keycloak.settings</literal></link>
option. The available options correspond directly to
parameters in <literal>conf/keycloak.conf</literal>. Some
of the most important parameters are documented as
suboptions, the rest can be found in the
<link xlink:href="https://www.keycloak.org/server/all-config">All
configuration section of the Keycloak Server Installation
and Configuration Guide</link>. While the new
configuration is much simpler and cleaner than the old
JBoss CLI one, this unfortunately mean that there’s no
straightforward way to convert an old configuration to the
new format and some settings may not even be available
anymore.
</para>
</listitem>
<listitem>
<para>
<literal>services.keycloak.frontendUrl</literal> was
removed and the frontend URL is now configured through the
<literal>hostname</literal> family of settings in
<link linkend="opt-services.keycloak.settings"><literal>services.keycloak.settings</literal></link>
instead. See the
<link xlink:href="https://www.keycloak.org/server/hostname">Hostname
section of the Keycloak Server Installation and
Configuration Guide</link> for more details. Additionally,
<literal>/auth</literal> was removed from the default
context path and needs to be added back in
<link linkend="opt-services.keycloak.settings.http-relative-path"><literal>services.keycloak.settings.http-relative-path</literal></link>
if you want to keep compatibility with your current
clients.
</para>
</listitem>
<listitem>
<para>
<literal>services.keycloak.bindAddress</literal>,
<literal>services.keycloak.forceBackendUrlToFrontendUrl</literal>,
<literal>services.keycloak.httpPort</literal> and
<literal>services.keycloak.httpsPort</literal> have been
removed in favor of their equivalent options in
<link linkend="opt-services.keycloak.settings"><literal>services.keycloak.settings</literal></link>.
<literal>httpPort</literal> and
<literal>httpsPort</literal> have additionally had their
types changed from <literal>str</literal> to
<literal>port</literal>.
</para>
<para>
The new names are as follows:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<literal>bindAddress</literal>:
<link linkend="opt-services.keycloak.settings.http-host"><literal>services.keycloak.settings.http-host</literal></link>
</para>
</listitem>
<listitem>
<para>
<literal>forceBackendUrlToFrontendUrl</literal>:
<link linkend="opt-services.keycloak.settings.hostname-strict-backchannel"><literal>services.keycloak.settings.hostname-strict-backchannel</literal></link>
</para>
</listitem>
<listitem>
<para>
<literal>httpPort</literal>:
<link linkend="opt-services.keycloak.settings.http-port"><literal>services.keycloak.settings.http-port</literal></link>
</para>
</listitem>
<listitem>
<para>
<literal>httpsPort</literal>:
<link linkend="opt-services.keycloak.settings.https-port"><literal>services.keycloak.settings.https-port</literal></link>
</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>
For example, when using a reverse proxy the migration could
look like this:
</para>
<para>
Before:
</para>
<programlisting language="bash">
services.keycloak = {
enable = true;
httpPort = &quot;8080&quot;;
frontendUrl = &quot;https://keycloak.example.com/auth&quot;;
database.passwordFile = &quot;/run/keys/db_password&quot;;
extraConfig = {
&quot;subsystem=undertow&quot;.&quot;server=default-server&quot;.&quot;http-listener=default&quot;.proxy-address-forwarding = true;
};
};
</programlisting>
<para>
After:
</para>
<programlisting language="bash">
services.keycloak = {
enable = true;
settings = {
http-port = 8080;
hostname = &quot;keycloak.example.com&quot;;
http-relative-path = &quot;/auth&quot;;
proxy = &quot;edge&quot;;
};
database.passwordFile = &quot;/run/keys/db_password&quot;;
};
</programlisting>
</listitem>
<listitem>
<para>
The MoinMoin wiki engine

@ -267,6 +267,81 @@ In addition to numerous new and upgraded packages, this release has the followin
`media_store_path` was changed from `${dataDir}/media` to `${dataDir}/media_store` if `system.stateVersion` is at least `22.05`. Files will need to be manually moved to the new
location if the `stateVersion` is updated.
- The Keycloak package (`pkgs.keycloak`) has been switched from the
Wildfly version, which will soon be deprecated, to the Quarkus based
version. The Keycloak service (`services.keycloak`) has been updated
to accommodate the change and now differs from the previous version
in a few ways:
- `services.keycloak.extraConfig` has been removed in favor of the
new [settings-style](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md)
[`services.keycloak.settings`](#opt-services.keycloak.settings)
option. The available options correspond directly to parameters in
`conf/keycloak.conf`. Some of the most important parameters are
documented as suboptions, the rest can be found in the [All
configuration section of the Keycloak Server Installation and
Configuration
Guide](https://www.keycloak.org/server/all-config). While the new
configuration is much simpler and cleaner than the old JBoss CLI
one, this unfortunately mean that there's no straightforward way
to convert an old configuration to the new format and some
settings may not even be available anymore.
- `services.keycloak.frontendUrl` was removed and the frontend URL
is now configured through the `hostname` family of settings in
[`services.keycloak.settings`](#opt-services.keycloak.settings)
instead. See the [Hostname section of the Keycloak Server
Installation and Configuration
Guide](https://www.keycloak.org/server/hostname) for more
details. Additionally, `/auth` was removed from the default
context path and needs to be added back in
[`services.keycloak.settings.http-relative-path`](#opt-services.keycloak.settings.http-relative-path)
if you want to keep compatibility with your current clients.
- `services.keycloak.bindAddress`,
`services.keycloak.forceBackendUrlToFrontendUrl`,
`services.keycloak.httpPort` and `services.keycloak.httpsPort`
have been removed in favor of their equivalent options in
[`services.keycloak.settings`](#opt-services.keycloak.settings). `httpPort`
and `httpsPort` have additionally had their types changed from
`str` to `port`.
The new names are as follows:
- `bindAddress`: [`services.keycloak.settings.http-host`](#opt-services.keycloak.settings.http-host)
- `forceBackendUrlToFrontendUrl`: [`services.keycloak.settings.hostname-strict-backchannel`](#opt-services.keycloak.settings.hostname-strict-backchannel)
- `httpPort`: [`services.keycloak.settings.http-port`](#opt-services.keycloak.settings.http-port)
- `httpsPort`: [`services.keycloak.settings.https-port`](#opt-services.keycloak.settings.https-port)
For example, when using a reverse proxy the migration could look
like this:
Before:
```nix
services.keycloak = {
enable = true;
httpPort = "8080";
frontendUrl = "https://keycloak.example.com/auth";
database.passwordFile = "/run/keys/db_password";
extraConfig = {
"subsystem=undertow"."server=default-server"."http-listener=default".proxy-address-forwarding = true;
};
};
```
After:
```nix
services.keycloak = {
enable = true;
settings = {
http-port = 8080;
hostname = "keycloak.example.com";
http-relative-path = "/auth";
proxy = "edge";
};
database.passwordFile = "/run/keys/db_password";
};
```
- The MoinMoin wiki engine (`services.moinmoin`) has been removed, because Python 2 is being retired from nixpkgs.
- Services in the `hadoop` module previously set `openFirewall` to true by default.

File diff suppressed because it is too large Load Diff

@ -27,10 +27,10 @@
<para>
Refer to the <link
xlink:href="https://www.keycloak.org/docs/latest/server_admin/index.html#admin-console">Admin
Console section of the Keycloak Server Administration Guide</link> for
information on how to administer your
<productname>Keycloak</productname> instance.
xlink:href="https://www.keycloak.org/docs/latest/server_admin/index.html">
Keycloak Server Administration Guide</link> for information on
how to administer your <productname>Keycloak</productname>
instance.
</para>
</section>
@ -38,27 +38,28 @@
<title>Database access</title>
<para>
<productname>Keycloak</productname> can be used with either
<productname>PostgreSQL</productname> or
<productname>PostgreSQL</productname>,
<productname>MariaDB</productname> or
<productname>MySQL</productname>. Which one is used can be
configured in <xref
linkend="opt-services.keycloak.database.type" />. The selected
database will automatically be enabled and a database and role
created unless <xref
linkend="opt-services.keycloak.database.host" /> is changed from
its default of <literal>localhost</literal> or <xref
linkend="opt-services.keycloak.database.createLocally" /> is set
to <literal>false</literal>.
linkend="opt-services.keycloak.database.host" /> is changed
from its default of <literal>localhost</literal> or <xref
linkend="opt-services.keycloak.database.createLocally" /> is
set to <literal>false</literal>.
</para>
<para>
External database access can also be configured by setting
<xref linkend="opt-services.keycloak.database.host" />, <xref
linkend="opt-services.keycloak.database.name" />, <xref
linkend="opt-services.keycloak.database.username" />, <xref
linkend="opt-services.keycloak.database.useSSL" /> and <xref
linkend="opt-services.keycloak.database.caCert" /> as
appropriate. Note that you need to manually create a database
called <literal>keycloak</literal> and allow the configured
database user full access to it.
appropriate. Note that you need to manually create the database
and allow the configured database user full access to it.
</para>
<para>
@ -79,22 +80,27 @@
</warning>
</section>
<section xml:id="module-services-keycloak-frontendurl">
<title>Frontend URL</title>
<section xml:id="module-services-keycloak-hostname">
<title>Hostname</title>
<para>
The frontend URL is used as base for all frontend requests and
must be configured through <xref linkend="opt-services.keycloak.frontendUrl" />.
It should normally include a trailing <literal>/auth</literal>
(the default web context). If you use a reverse proxy, you need
to set this option to <literal>""</literal>, so that frontend URL
is derived from HTTP headers. <literal>X-Forwarded-*</literal> headers
support also should be enabled, using <link
xlink:href="https://www.keycloak.org/docs/latest/server_installation/index.html#identifying-client-ip-addresses">
respective guidelines</link>.
The hostname is used to build the public URL used as base for
all frontend requests and must be configured through <xref
linkend="opt-services.keycloak.settings.hostname" />.
</para>
<note>
<para>
If you're migrating an old Wildfly based Keycloak instance
and want to keep compatibility with your current clients,
you'll likely want to set <xref
linkend="opt-services.keycloak.settings.http-relative-path"
/> to <literal>/auth</literal>. See the option description
for more details.
</para>
</note>
<para>
<xref linkend="opt-services.keycloak.forceBackendUrlToFrontendUrl" />
<xref linkend="opt-services.keycloak.settings.hostname-strict-backchannel" />
determines whether Keycloak should force all requests to go
through the frontend URL. By default,
<productname>Keycloak</productname> allows backend requests to
@ -104,10 +110,10 @@
</para>
<para>
See the <link
xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">Hostname
section of the Keycloak Server Installation and Configuration
Guide</link> for more information.
For more information on hostname configuration, see the <link
xlink:href="https://www.keycloak.org/server/hostname">Hostname
section of the Keycloak Server Installation and Configuration
Guide</link>.
</para>
</section>
@ -139,68 +145,40 @@
<section xml:id="module-services-keycloak-themes">
<title>Themes</title>
<para>
You can package custom themes and make them visible to Keycloak via
<xref linkend="opt-services.keycloak.themes" />
option. See the <link xlink:href="https://www.keycloak.org/docs/latest/server_development/#_themes">
You can package custom themes and make them visible to
Keycloak through <xref linkend="opt-services.keycloak.themes"
/>. See the <link
xlink:href="https://www.keycloak.org/docs/latest/server_development/#_themes">
Themes section of the Keycloak Server Development Guide</link>
and respective NixOS option description for more information.
and the description of the aforementioned NixOS option for
more information.
</para>
</section>
<section xml:id="module-services-keycloak-extra-config">
<title>Additional configuration</title>
<section xml:id="module-services-keycloak-settings">
<title>Configuration file settings</title>
<para>
Additional Keycloak configuration options, for which no
explicit <productname>NixOS</productname> options are provided,
can be set in <xref linkend="opt-services.keycloak.extraConfig" />.
Keycloak server configuration parameters can be set in <xref
linkend="opt-services.keycloak.settings" />. These correspond
directly to options in
<filename>conf/keycloak.conf</filename>. Some of the most
important parameters are documented as suboptions, the rest can
be found in the <link
xlink:href="https://www.keycloak.org/server/all-config">All
configuration section of the Keycloak Server Installation and
Configuration Guide</link>.
</para>
<para>
Options are expressed as a Nix attribute set which matches the
structure of the jboss-cli configuration. The configuration is
effectively overlayed on top of the default configuration
shipped with Keycloak. To remove existing nodes and undefine
attributes from the default configuration, set them to
<literal>null</literal>.
</para>
<para>
For example, the following script, which removes the hostname
provider <literal>default</literal>, adds the deprecated
hostname provider <literal>fixed</literal> and defines it the
default:
<programlisting>
/subsystem=keycloak-server/spi=hostname/provider=default:remove()
/subsystem=keycloak-server/spi=hostname/provider=fixed:add(enabled = true, properties = { hostname = "keycloak.example.com" })
/subsystem=keycloak-server/spi=hostname:write-attribute(name=default-provider, value="fixed")
</programlisting>
would be expressed as
<programlisting>
services.keycloak.extraConfig = {
"subsystem=keycloak-server" = {
"spi=hostname" = {
"provider=default" = null;
"provider=fixed" = {
enabled = true;
properties.hostname = "keycloak.example.com";
};
default-provider = "fixed";
};
};
};
</programlisting>
</para>
<para>
You can discover available options by using the <link
xlink:href="http://docs.wildfly.org/21/Admin_Guide.html#Command_Line_Interface">jboss-cli.sh</link>
program and by referring to the <link
xlink:href="https://www.keycloak.org/docs/latest/server_installation/index.html">Keycloak
Server Installation and Configuration Guide</link>.
Options containing secret data should be set to an attribute
set containing the attribute <literal>_secret</literal> - a
string pointing to a file containing the value the option
should be set to. See the description of <xref
linkend="opt-services.keycloak.settings" /> for an example.
</para>
</section>
<section xml:id="module-services-keycloak-example-config">
<title>Example configuration</title>
<para>
@ -208,9 +186,11 @@ services.keycloak.extraConfig = {
<programlisting>
services.keycloak = {
<link linkend="opt-services.keycloak.enable">enable</link> = true;
settings = {
<link linkend="opt-services.keycloak.settings.hostname">hostname</link> = "keycloak.example.com";
<link linkend="opt-services.keycloak.settings.hostname-strict-backchannel">hostname-strict-backchannel</link> = true;
};
<link linkend="opt-services.keycloak.initialAdminPassword">initialAdminPassword</link> = "e6Wcm0RrtegMEHl"; # change on first login
<link linkend="opt-services.keycloak.frontendUrl">frontendUrl</link> = "https://keycloak.example.com/auth";
<link linkend="opt-services.keycloak.forceBackendUrlToFrontendUrl">forceBackendUrlToFrontendUrl</link> = true;
<link linkend="opt-services.keycloak.sslCertificate">sslCertificate</link> = "/run/keys/ssl_cert";
<link linkend="opt-services.keycloak.sslCertificateKey">sslCertificateKey</link> = "/run/keys/ssl_key";
<link linkend="opt-services.keycloak.database.passwordFile">database.passwordFile</link> = "/run/keys/db_password";

@ -4,7 +4,7 @@
let
certs = import ./common/acme/server/snakeoil-certs.nix;
frontendUrl = "https://${certs.domain}/auth";
frontendUrl = "https://${certs.domain}";
initialAdminPassword = "h4IhoJFnt2iQIR9";
keycloakTest = import ./make-test-python.nix (
@ -27,20 +27,23 @@ let
services.keycloak = {
enable = true;
inherit frontendUrl initialAdminPassword;
sslCertificate = certs.${certs.domain}.cert;
sslCertificateKey = certs.${certs.domain}.key;
settings = {
hostname = certs.domain;
};
inherit initialAdminPassword;
sslCertificate = "${certs.${certs.domain}.cert}";
sslCertificateKey = "${certs.${certs.domain}.key}";
database = {
type = databaseType;
username = "bogus";
passwordFile = pkgs.writeText "dbPassword" "wzf6vOCbPp6cqTH";
name = "also bogus";
passwordFile = "${pkgs.writeText "dbPassword" "wzf6vOCbPp6cqTH"}";
};
plugins = with config.services.keycloak.package.plugins; [
keycloak-discord
keycloak-metrics-spi
];
};
environment.systemPackages = with pkgs; [
xmlstarlet
html-tidy
@ -99,9 +102,9 @@ let
in ''
keycloak.start()
keycloak.wait_for_unit("keycloak.service")
keycloak.wait_for_open_port(443)
keycloak.wait_until_succeeds("curl -sSf ${frontendUrl}")
### Realm Setup ###
# Get an admin interface access token
@ -117,8 +120,8 @@ let
# Register the metrics SPI
keycloak.succeed(
"${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' ${pkgs.keycloak}/bin/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' ${pkgs.keycloak}/bin/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 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 update events/config -s 'eventsEnabled=true' -s 'adminEventsEnabled=true' -s 'eventsListeners+=metrics-listener'",
"curl -sSf '${frontendUrl}/realms/master/metrics' | grep '^keycloak_admin_event_UPDATE'"
)
@ -172,5 +175,6 @@ let
in
{
postgres = keycloakTest { databaseType = "postgresql"; };
mariadb = keycloakTest { databaseType = "mariadb"; };
mysql = keycloakTest { databaseType = "mysql"; };
}

@ -1,73 +1,81 @@
{ stdenv, lib, fetchzip, makeWrapper, jre, writeText, nixosTests
, postgresql_jdbc ? null, mysql_jdbc ? null
{ stdenv
, lib
, fetchzip
, makeWrapper
, jre
, writeText
, nixosTests
, callPackage
, confFile ? null
, plugins ? [ ]
}:
let
mkModuleXml = name: jarFile: writeText "module.xml" ''
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.3" name="${name}">
<resources>
<resource-root path="${jarFile}"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
'';
in
stdenv.mkDerivation rec {
pname = "keycloak";
pname = "keycloak";
version = "17.0.1";
src = fetchzip {
url = "https://github.com/keycloak/keycloak/releases/download/${version}/keycloak-legacy-${version}.zip";
sha256 = "sha256-oqANNk7T6+CAS818v3I1QNsuxetL/JFZMqxouRn+kdE=";
url = "https://github.com/keycloak/keycloak/releases/download/${version}/keycloak-${version}.zip";
sha256 = "sha256-z1LfTUoK+v4oQxdyIQruFhl5O333zirSrkPoTFgVfmI=";
};
nativeBuildInputs = [ makeWrapper ];
nativeBuildInputs = [ makeWrapper jre ];
buildPhase = ''
runHook preBuild
'' + lib.optionalString (confFile != null) ''
install -m 0600 ${confFile} conf/keycloak.conf
'' + ''
install_plugin() {
if [ -d "$1" ]; then
find "$1" -type f \( -iname \*.ear -o -iname \*.jar \) -exec install -m 0500 "{}" "providers/" \;
else
install -m 0500 "$1" "providers/"
fi
}
${lib.concatMapStringsSep "\n" (pl: "install_plugin ${lib.escapeShellArg pl}") plugins}
'' + ''
export KC_HOME_DIR=$out
export KC_CONF_DIR=$out/conf
patchShebangs bin/kc.sh
bin/kc.sh build
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir $out
cp -r * $out
rm -rf $out/bin/*.{ps1,bat}
rm $out/bin/*.{ps1,bat}
module_path=$out/modules/system/layers/keycloak
if ! [[ -d $module_path ]]; then
echo "The module path $module_path not found!"
exit 1
fi
runHook postInstall
'';
postFixup = ''
substituteInPlace $out/bin/kc.sh --replace '-Dkc.home.dir=$DIRNAME/../' '-Dkc.home.dir=$KC_HOME_DIR'
substituteInPlace $out/bin/kc.sh --replace '-Djboss.server.config.dir=$DIRNAME/../conf' '-Djboss.server.config.dir=$KC_CONF_DIR'
${lib.optionalString (postgresql_jdbc != null) ''
mkdir -p $module_path/org/postgresql/main
ln -s ${postgresql_jdbc}/share/java/postgresql-jdbc.jar $module_path/org/postgresql/main/
ln -s ${mkModuleXml "org.postgresql" "postgresql-jdbc.jar"} $module_path/org/postgresql/main/module.xml
''}
${lib.optionalString (mysql_jdbc != null) ''
mkdir -p $module_path/com/mysql/main
ln -s ${mysql_jdbc}/share/java/mysql-connector-java.jar $module_path/com/mysql/main/
ln -s ${mkModuleXml "com.mysql" "mysql-connector-java.jar"} $module_path/com/mysql/main/module.xml
''}
for script in add-user-keycloak.sh add-user.sh domain.sh elytron-tool.sh jboss-cli.sh jconsole.sh jdr.sh standalone.sh wsconsume.sh wsprovide.sh; do
wrapProgram $out/bin/$script --set JAVA_HOME ${jre}
for script in $(find $out/bin -type f -executable); do
wrapProgram "$script" --set JAVA_HOME ${jre} --prefix PATH : ${jre}/bin
done
wrapProgram $out/bin/kcadm.sh --prefix PATH : ${jre}/bin
wrapProgram $out/bin/kcreg.sh --prefix PATH : ${jre}/bin
'';
passthru = {
tests = nixosTests.keycloak;
plugins = callPackage ./all-plugins.nix {};
plugins = callPackage ./all-plugins.nix { };
enabledPlugins = plugins;
};
meta = with lib; {
homepage = "https://www.keycloak.org/";
homepage = "https://www.keycloak.org/";
description = "Identity and access management for modern applications and services";
license = licenses.asl20;
platforms = jre.meta.platforms;
license = licenses.asl20;
platforms = jre.meta.platforms;
maintainers = with maintainers; [ ngerstle talyz ];
};

Loading…
Cancel
Save