nixos/keycloak: Inherit library functions and builtins
Instead of referencing all library functions through `lib.` and builtins through `builtins.` at every invocation, inherit them into the appropriate scope.
This commit is contained in:
parent
5010f4fff9
commit
21b1de2bcd
@ -3,299 +3,312 @@
|
||||
let
|
||||
cfg = config.services.keycloak;
|
||||
opt = options.services.keycloak;
|
||||
|
||||
inherit (lib) types mkOption concatStringsSep mapAttrsToList
|
||||
escapeShellArg recursiveUpdate optionalAttrs boolToString mkOrder
|
||||
sort filterAttrs concatMapStringsSep concatStrings mkIf
|
||||
optionalString optionals mkDefault literalExpression hasSuffix
|
||||
foldl' isAttrs filter attrNames elem literalDocBook
|
||||
maintainers;
|
||||
|
||||
inherit (builtins) match typeOf;
|
||||
in
|
||||
{
|
||||
options.services.keycloak = {
|
||||
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to enable the Keycloak identity and access management
|
||||
server.
|
||||
'';
|
||||
};
|
||||
|
||||
bindAddress = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "\${jboss.bind.address:0.0.0.0}";
|
||||
example = "127.0.0.1";
|
||||
description = ''
|
||||
On which address Keycloak should accept new connections.
|
||||
|
||||
A special syntax can be used to allow command line Java system
|
||||
properties to override the value: ''${property.name:value}
|
||||
'';
|
||||
};
|
||||
|
||||
httpPort = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "\${jboss.http.port:80}";
|
||||
example = "8080";
|
||||
description = ''
|
||||
On which port Keycloak should listen for new HTTP connections.
|
||||
|
||||
A special syntax can be used to allow command line Java system
|
||||
properties to override the value: ''${property.name:value}
|
||||
'';
|
||||
};
|
||||
|
||||
httpsPort = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "\${jboss.https.port:443}";
|
||||
example = "8443";
|
||||
description = ''
|
||||
On which port Keycloak should listen for new HTTPS connections.
|
||||
|
||||
A special syntax can be used to allow command line Java system
|
||||
properties to override the value: ''${property.name:value}
|
||||
'';
|
||||
};
|
||||
|
||||
frontendUrl = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
apply = x:
|
||||
if x == "" || lib.hasSuffix "/" x then
|
||||
x
|
||||
else
|
||||
x + "/";
|
||||
example = "keycloak.example.com/auth";
|
||||
description = ''
|
||||
The public URL used as base for all frontend requests. Should
|
||||
normally include a trailing <literal>/auth</literal>.
|
||||
|
||||
See <link xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the
|
||||
Hostname section of the Keycloak server installation
|
||||
manual</link> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
forceBackendUrlToFrontendUrl = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether Keycloak should force all requests to go through the
|
||||
frontend URL configured in <xref
|
||||
linkend="opt-services.keycloak.frontendUrl" />. By default,
|
||||
Keycloak allows backend requests to instead use its local
|
||||
hostname or IP address and may also advertise it to clients
|
||||
through its OpenID Connect Discovery endpoint.
|
||||
|
||||
See <link
|
||||
xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the
|
||||
Hostname section of the Keycloak server installation
|
||||
manual</link> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
sslCertificate = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/run/keys/ssl_cert";
|
||||
description = ''
|
||||
The path to a PEM formatted certificate to use for TLS/SSL
|
||||
connections.
|
||||
|
||||
This should be a string, not a Nix path, since Nix paths are
|
||||
copied into the world-readable Nix store.
|
||||
'';
|
||||
};
|
||||
|
||||
sslCertificateKey = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/run/keys/ssl_key";
|
||||
description = ''
|
||||
The path to a PEM formatted private key to use for TLS/SSL
|
||||
connections.
|
||||
|
||||
This should be a string, not a Nix path, since Nix paths are
|
||||
copied into the world-readable Nix store.
|
||||
'';
|
||||
};
|
||||
|
||||
database = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "mysql" "postgresql" ];
|
||||
default = "postgresql";
|
||||
example = "mysql";
|
||||
options.services.keycloak =
|
||||
let
|
||||
inherit (types) bool str nullOr attrsOf path enum anything
|
||||
package port;
|
||||
in
|
||||
{
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
The type of database Keycloak should connect to.
|
||||
Whether to enable the Keycloak identity and access management
|
||||
server.
|
||||
'';
|
||||
};
|
||||
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "localhost";
|
||||
bindAddress = mkOption {
|
||||
type = str;
|
||||
default = "\${jboss.bind.address:0.0.0.0}";
|
||||
example = "127.0.0.1";
|
||||
description = ''
|
||||
Hostname of the database to connect to.
|
||||
On which address Keycloak should accept new connections.
|
||||
|
||||
A special syntax can be used to allow command line Java system
|
||||
properties to override the value: ''${property.name:value}
|
||||
'';
|
||||
};
|
||||
|
||||
port =
|
||||
let
|
||||
dbPorts = {
|
||||
postgresql = 5432;
|
||||
mysql = 3306;
|
||||
};
|
||||
in
|
||||
lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = dbPorts.${cfg.database.type};
|
||||
defaultText = lib.literalDocBook "default port of selected database";
|
||||
description = ''
|
||||
Port of the database to connect to.
|
||||
'';
|
||||
};
|
||||
|
||||
useSSL = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = cfg.database.host != "localhost";
|
||||
defaultText = lib.literalExpression ''config.${opt.database.host} != "localhost"'';
|
||||
httpPort = mkOption {
|
||||
type = str;
|
||||
default = "\${jboss.http.port:80}";
|
||||
example = "8080";
|
||||
description = ''
|
||||
Whether the database connection should be secured by SSL /
|
||||
TLS.
|
||||
On which port Keycloak should listen for new HTTP connections.
|
||||
|
||||
A special syntax can be used to allow command line Java system
|
||||
properties to override the value: ''${property.name:value}
|
||||
'';
|
||||
};
|
||||
|
||||
caCert = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
httpsPort = mkOption {
|
||||
type = str;
|
||||
default = "\${jboss.https.port:443}";
|
||||
example = "8443";
|
||||
description = ''
|
||||
On which port Keycloak should listen for new HTTPS connections.
|
||||
|
||||
A special syntax can be used to allow command line Java system
|
||||
properties to override the value: ''${property.name:value}
|
||||
'';
|
||||
};
|
||||
|
||||
frontendUrl = mkOption {
|
||||
type = str;
|
||||
apply = x:
|
||||
if x == "" || hasSuffix "/" x then
|
||||
x
|
||||
else
|
||||
x + "/";
|
||||
example = "keycloak.example.com/auth";
|
||||
description = ''
|
||||
The public URL used as base for all frontend requests. Should
|
||||
normally include a trailing <literal>/auth</literal>.
|
||||
|
||||
See <link xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the
|
||||
Hostname section of the Keycloak server installation
|
||||
manual</link> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
forceBackendUrlToFrontendUrl = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether Keycloak should force all requests to go through the
|
||||
frontend URL configured in <xref
|
||||
linkend="opt-services.keycloak.frontendUrl" />. By default,
|
||||
Keycloak allows backend requests to instead use its local
|
||||
hostname or IP address and may also advertise it to clients
|
||||
through its OpenID Connect Discovery endpoint.
|
||||
|
||||
See <link
|
||||
xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the
|
||||
Hostname section of the Keycloak server installation
|
||||
manual</link> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
sslCertificate = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
example = "/run/keys/ssl_cert";
|
||||
description = ''
|
||||
The SSL / TLS CA certificate that verifies the identity of the
|
||||
database server.
|
||||
|
||||
Required when PostgreSQL is used and SSL is turned on.
|
||||
|
||||
For MySQL, if left at <literal>null</literal>, the default
|
||||
Java keystore is used, which should suffice if the server
|
||||
certificate is issued by an official CA.
|
||||
'';
|
||||
};
|
||||
|
||||
createLocally = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether a database should be automatically created on the
|
||||
local host. Set this to false if you plan on provisioning a
|
||||
local database yourself. This has no effect if
|
||||
services.keycloak.database.host is customized.
|
||||
'';
|
||||
};
|
||||
|
||||
username = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "keycloak";
|
||||
description = ''
|
||||
Username to use when connecting to an external or manually
|
||||
provisioned database; has no effect when a local database is
|
||||
automatically provisioned.
|
||||
|
||||
To use this with a local database, set <xref
|
||||
linkend="opt-services.keycloak.database.createLocally" /> to
|
||||
<literal>false</literal> and create the database and user
|
||||
manually. The database should be called
|
||||
<literal>keycloak</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
example = "/run/keys/db_password";
|
||||
description = ''
|
||||
File containing the database password.
|
||||
The path to a PEM formatted certificate to use for TLS/SSL
|
||||
connections.
|
||||
|
||||
This should be a string, not a Nix path, since Nix paths are
|
||||
copied into the world-readable Nix store.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = pkgs.keycloak;
|
||||
defaultText = lib.literalExpression "pkgs.keycloak";
|
||||
description = ''
|
||||
Keycloak package to use.
|
||||
'';
|
||||
};
|
||||
sslCertificateKey = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
example = "/run/keys/ssl_key";
|
||||
description = ''
|
||||
The path to a PEM formatted private key to use for TLS/SSL
|
||||
connections.
|
||||
|
||||
initialAdminPassword = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "changeme";
|
||||
description = ''
|
||||
Initial password set for the <literal>admin</literal>
|
||||
user. The password is not stored safely and should be changed
|
||||
immediately in the admin panel.
|
||||
'';
|
||||
};
|
||||
This should be a string, not a Nix path, since Nix paths are
|
||||
copied into the world-readable Nix store.
|
||||
'';
|
||||
};
|
||||
|
||||
themes = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.package;
|
||||
default = {};
|
||||
description = ''
|
||||
Additional theme packages for Keycloak. Each theme is linked into
|
||||
subdirectory with a corresponding attribute name.
|
||||
database = {
|
||||
type = mkOption {
|
||||
type = enum [ "mysql" "postgresql" ];
|
||||
default = "postgresql";
|
||||
example = "mysql";
|
||||
description = ''
|
||||
The type of database Keycloak should connect to.
|
||||
'';
|
||||
};
|
||||
|
||||
Theme packages consist of several subdirectories which provide
|
||||
different theme types: for example, <literal>account</literal>,
|
||||
<literal>login</literal> etc. After adding a theme to this option you
|
||||
can select it by its name in Keycloak administration console.
|
||||
'';
|
||||
};
|
||||
host = mkOption {
|
||||
type = str;
|
||||
default = "localhost";
|
||||
description = ''
|
||||
Hostname of the database to connect to.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.anything;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"subsystem=keycloak-server" = {
|
||||
"spi=hostname" = {
|
||||
"provider=default" = null;
|
||||
"provider=fixed" = {
|
||||
enabled = true;
|
||||
properties.hostname = "keycloak.example.com";
|
||||
};
|
||||
default-provider = "fixed";
|
||||
port =
|
||||
let
|
||||
dbPorts = {
|
||||
postgresql = 5432;
|
||||
mysql = 3306;
|
||||
};
|
||||
in
|
||||
mkOption {
|
||||
type = port;
|
||||
default = dbPorts.${cfg.database.type};
|
||||
defaultText = literalDocBook "default port of selected database";
|
||||
description = ''
|
||||
Port of the database to connect to.
|
||||
'';
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Additional Keycloak configuration options to set in
|
||||
<literal>standalone.xml</literal>.
|
||||
|
||||
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>.
|
||||
useSSL = mkOption {
|
||||
type = bool;
|
||||
default = cfg.database.host != "localhost";
|
||||
defaultText = literalExpression ''config.${opt.database.host} != "localhost"'';
|
||||
description = ''
|
||||
Whether the database connection should be secured by SSL /
|
||||
TLS.
|
||||
'';
|
||||
};
|
||||
|
||||
The example configuration does the equivalent of the following
|
||||
script, which removes the hostname provider
|
||||
<literal>default</literal>, adds the deprecated hostname
|
||||
provider <literal>fixed</literal> and defines it the default:
|
||||
caCert = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
The SSL / TLS CA certificate that verifies the identity of the
|
||||
database server.
|
||||
|
||||
<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>
|
||||
Required when PostgreSQL is used and SSL is turned on.
|
||||
|
||||
For MySQL, if left at <literal>null</literal>, the default
|
||||
Java keystore is used, which should suffice if the server
|
||||
certificate is issued by an official CA.
|
||||
'';
|
||||
};
|
||||
|
||||
createLocally = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether a database should be automatically created on the
|
||||
local host. Set this to false if you plan on provisioning a
|
||||
local database yourself. This has no effect if
|
||||
services.keycloak.database.host is customized.
|
||||
'';
|
||||
};
|
||||
|
||||
username = mkOption {
|
||||
type = str;
|
||||
default = "keycloak";
|
||||
description = ''
|
||||
Username to use when connecting to an external or manually
|
||||
provisioned database; has no effect when a local database is
|
||||
automatically provisioned.
|
||||
|
||||
To use this with a local database, set <xref
|
||||
linkend="opt-services.keycloak.database.createLocally" /> to
|
||||
<literal>false</literal> and create the database and user
|
||||
manually. The database should be called
|
||||
<literal>keycloak</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = path;
|
||||
example = "/run/keys/db_password";
|
||||
description = ''
|
||||
File containing the database password.
|
||||
|
||||
This should be a string, not a Nix path, since Nix paths are
|
||||
copied into the world-readable Nix store.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = package;
|
||||
default = pkgs.keycloak;
|
||||
defaultText = literalExpression "pkgs.keycloak";
|
||||
description = ''
|
||||
Keycloak package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
initialAdminPassword = mkOption {
|
||||
type = str;
|
||||
default = "changeme";
|
||||
description = ''
|
||||
Initial password set for the <literal>admin</literal>
|
||||
user. The password is not stored safely and should be changed
|
||||
immediately in the admin panel.
|
||||
'';
|
||||
};
|
||||
|
||||
themes = mkOption {
|
||||
type = attrsOf package;
|
||||
default = { };
|
||||
description = ''
|
||||
Additional theme packages for Keycloak. Each theme is linked into
|
||||
subdirectory with a corresponding attribute name.
|
||||
|
||||
Theme packages consist of several subdirectories which provide
|
||||
different theme types: for example, <literal>account</literal>,
|
||||
<literal>login</literal> etc. After adding a theme to this option you
|
||||
can select it by its name in Keycloak administration console.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = attrsOf anything;
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
"subsystem=keycloak-server" = {
|
||||
"spi=hostname" = {
|
||||
"provider=default" = null;
|
||||
"provider=fixed" = {
|
||||
enabled = true;
|
||||
properties.hostname = "keycloak.example.com";
|
||||
};
|
||||
default-provider = "fixed";
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Additional Keycloak configuration options to set in
|
||||
<literal>standalone.xml</literal>.
|
||||
|
||||
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>.
|
||||
|
||||
The example configuration does the equivalent of 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>
|
||||
|
||||
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>.
|
||||
'';
|
||||
};
|
||||
|
||||
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>.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
# We only want to create a database if we're actually going to connect to it.
|
||||
@ -332,10 +345,10 @@ in
|
||||
fi
|
||||
done
|
||||
|
||||
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: theme: "linkTheme ${theme} ${lib.escapeShellArg name}") cfg.themes)}
|
||||
${concatStringsSep "\n" (mapAttrsToList (name: theme: "linkTheme ${theme} ${escapeShellArg name}") cfg.themes)}
|
||||
'';
|
||||
|
||||
keycloakConfig' = builtins.foldl' lib.recursiveUpdate {
|
||||
keycloakConfig' = foldl' recursiveUpdate {
|
||||
"interface=public".inet-address = cfg.bindAddress;
|
||||
"socket-binding-group=standard-sockets"."socket-binding=http".port = cfg.httpPort;
|
||||
"subsystem=keycloak-server" = {
|
||||
@ -353,7 +366,7 @@ in
|
||||
password = "@db-password@";
|
||||
};
|
||||
} [
|
||||
(lib.optionalAttrs (cfg.database.type == "postgresql") {
|
||||
(optionalAttrs (cfg.database.type == "postgresql") {
|
||||
"subsystem=datasources" = {
|
||||
"jdbc-driver=postgresql" = {
|
||||
driver-module-name = "org.postgresql";
|
||||
@ -361,16 +374,16 @@ in
|
||||
driver-xa-datasource-class-name = "org.postgresql.xa.PGXADataSource";
|
||||
};
|
||||
"data-source=KeycloakDS" = {
|
||||
connection-url = "jdbc:postgresql://${cfg.database.host}:${builtins.toString cfg.database.port}/keycloak";
|
||||
connection-url = "jdbc:postgresql://${cfg.database.host}:${toString cfg.database.port}/keycloak";
|
||||
driver-name = "postgresql";
|
||||
"connection-properties=ssl".value = lib.boolToString cfg.database.useSSL;
|
||||
} // (lib.optionalAttrs (cfg.database.caCert != null) {
|
||||
"connection-properties=ssl".value = boolToString cfg.database.useSSL;
|
||||
} // (optionalAttrs (cfg.database.caCert != null) {
|
||||
"connection-properties=sslrootcert".value = cfg.database.caCert;
|
||||
"connection-properties=sslmode".value = "verify-ca";
|
||||
});
|
||||
};
|
||||
})
|
||||
(lib.optionalAttrs (cfg.database.type == "mysql") {
|
||||
(optionalAttrs (cfg.database.type == "mysql") {
|
||||
"subsystem=datasources" = {
|
||||
"jdbc-driver=mysql" = {
|
||||
driver-module-name = "com.mysql";
|
||||
@ -378,38 +391,38 @@ in
|
||||
driver-class-name = "com.mysql.jdbc.Driver";
|
||||
};
|
||||
"data-source=KeycloakDS" = {
|
||||
connection-url = "jdbc:mysql://${cfg.database.host}:${builtins.toString cfg.database.port}/keycloak";
|
||||
connection-url = "jdbc:mysql://${cfg.database.host}:${toString cfg.database.port}/keycloak";
|
||||
driver-name = "mysql";
|
||||
"connection-properties=useSSL".value = lib.boolToString cfg.database.useSSL;
|
||||
"connection-properties=requireSSL".value = lib.boolToString cfg.database.useSSL;
|
||||
"connection-properties=verifyServerCertificate".value = lib.boolToString cfg.database.useSSL;
|
||||
"connection-properties=useSSL".value = boolToString cfg.database.useSSL;
|
||||
"connection-properties=requireSSL".value = boolToString cfg.database.useSSL;
|
||||
"connection-properties=verifyServerCertificate".value = boolToString cfg.database.useSSL;
|
||||
"connection-properties=characterEncoding".value = "UTF-8";
|
||||
valid-connection-checker-class-name = "org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker";
|
||||
validate-on-match = true;
|
||||
exception-sorter-class-name = "org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter";
|
||||
} // (lib.optionalAttrs (cfg.database.caCert != null) {
|
||||
} // (optionalAttrs (cfg.database.caCert != null) {
|
||||
"connection-properties=trustCertificateKeyStoreUrl".value = "file:${mySqlCaKeystore}";
|
||||
"connection-properties=trustCertificateKeyStorePassword".value = "notsosecretpassword";
|
||||
});
|
||||
};
|
||||
})
|
||||
(lib.optionalAttrs (cfg.sslCertificate != null && cfg.sslCertificateKey != null) {
|
||||
(optionalAttrs (cfg.sslCertificate != null && cfg.sslCertificateKey != null) {
|
||||
"socket-binding-group=standard-sockets"."socket-binding=https".port = cfg.httpsPort;
|
||||
"subsystem=elytron" = lib.mkOrder 900 {
|
||||
"key-store=httpsKS" = lib.mkOrder 900 {
|
||||
"subsystem=elytron" = mkOrder 900 {
|
||||
"key-store=httpsKS" = mkOrder 900 {
|
||||
path = "/run/keycloak/ssl/certificate_private_key_bundle.p12";
|
||||
credential-reference.clear-text = "notsosecretpassword";
|
||||
type = "JKS";
|
||||
};
|
||||
"key-manager=httpsKM" = lib.mkOrder 901 {
|
||||
"key-manager=httpsKM" = mkOrder 901 {
|
||||
key-store = "httpsKS";
|
||||
credential-reference.clear-text = "notsosecretpassword";
|
||||
};
|
||||
"server-ssl-context=httpsSSC" = lib.mkOrder 902 {
|
||||
"server-ssl-context=httpsSSC" = mkOrder 902 {
|
||||
key-manager = "httpsKM";
|
||||
};
|
||||
};
|
||||
"subsystem=undertow" = lib.mkOrder 901 {
|
||||
"subsystem=undertow" = mkOrder 901 {
|
||||
"server=default-server"."https-listener=https".ssl-context = "httpsSSC";
|
||||
};
|
||||
})
|
||||
@ -500,7 +513,7 @@ in
|
||||
# with `expression` to evaluate.
|
||||
prefixExpression = string:
|
||||
let
|
||||
matchResult = builtins.match ''"\$\{.*}"'' string;
|
||||
matchResult = match ''"\$\{.*}"'' string;
|
||||
in
|
||||
if matchResult != null then
|
||||
"expression " + string
|
||||
@ -509,21 +522,21 @@ in
|
||||
|
||||
writeAttribute = attribute: value:
|
||||
let
|
||||
type = builtins.typeOf value;
|
||||
type = typeOf value;
|
||||
in
|
||||
if type == "set" then
|
||||
let
|
||||
names = builtins.attrNames value;
|
||||
names = attrNames value;
|
||||
in
|
||||
builtins.foldl' (text: name: text + (writeAttribute "${attribute}.${name}" value.${name})) "" names
|
||||
foldl' (text: name: text + (writeAttribute "${attribute}.${name}" value.${name})) "" names
|
||||
else if value == null then ''
|
||||
if (outcome == success) of ${path}:read-attribute(name="${attribute}")
|
||||
${path}:undefine-attribute(name="${attribute}")
|
||||
end-if
|
||||
''
|
||||
else if builtins.elem type [ "string" "path" "bool" ] then
|
||||
else if elem type [ "string" "path" "bool" ] then
|
||||
let
|
||||
value' = if type == "bool" then lib.boolToString value else ''"${value}"'';
|
||||
value' = if type == "bool" then boolToString value else ''"${value}"'';
|
||||
in ''
|
||||
if (result != ${prefixExpression value'}) of ${path}:read-attribute(name="${attribute}")
|
||||
${path}:write-attribute(name=${attribute}, value=${value'})
|
||||
@ -531,8 +544,8 @@ in
|
||||
''
|
||||
else throw "Unsupported type '${type}' for path '${path}'!";
|
||||
in
|
||||
lib.concatStrings
|
||||
(lib.mapAttrsToList
|
||||
concatStrings
|
||||
(mapAttrsToList
|
||||
(attribute: value: (writeAttribute attribute value))
|
||||
set);
|
||||
|
||||
@ -557,19 +570,19 @@ in
|
||||
let
|
||||
makeArg = attribute: value:
|
||||
let
|
||||
type = builtins.typeOf value;
|
||||
type = typeOf value;
|
||||
in
|
||||
if type == "set" then
|
||||
"${attribute} = { " + (makeArgList value) + " }"
|
||||
else if builtins.elem type [ "string" "path" "bool" ] then
|
||||
"${attribute} = ${if type == "bool" then lib.boolToString value else ''"${value}"''}"
|
||||
else if elem type [ "string" "path" "bool" ] then
|
||||
"${attribute} = ${if type == "bool" then boolToString value else ''"${value}"''}"
|
||||
else if value == null then
|
||||
""
|
||||
else
|
||||
throw "Unsupported type '${type}' for attribute '${attribute}'!";
|
||||
|
||||
in
|
||||
lib.concatStringsSep ", " (lib.mapAttrsToList makeArg set);
|
||||
concatStringsSep ", " (mapAttrsToList makeArg set);
|
||||
|
||||
|
||||
/* Recurses into the `nodeValue` attrset. Only subattrsets that
|
||||
@ -579,7 +592,7 @@ in
|
||||
recurse = nodePath: nodeValue:
|
||||
let
|
||||
nodeContent =
|
||||
if builtins.isAttrs nodeValue && nodeValue._type or "" == "order" then
|
||||
if isAttrs nodeValue && nodeValue._type or "" == "order" then
|
||||
nodeValue.content
|
||||
else
|
||||
nodeValue;
|
||||
@ -587,21 +600,21 @@ in
|
||||
let
|
||||
value = nodeContent.${name};
|
||||
in
|
||||
if (builtins.match ".*([=]).*" name) == [ "=" ] then
|
||||
if builtins.isAttrs value || value == null then
|
||||
if (match ".*([=]).*" name) == [ "=" ] then
|
||||
if isAttrs value || value == null then
|
||||
true
|
||||
else
|
||||
throw "Parsing path '${lib.concatStringsSep "." (nodePath ++ [ name ])}' failed: JBoss attributes cannot contain '='!"
|
||||
throw "Parsing path '${concatStringsSep "." (nodePath ++ [ name ])}' failed: JBoss attributes cannot contain '='!"
|
||||
else
|
||||
false;
|
||||
jbossPath = "/" + lib.concatStringsSep "/" nodePath;
|
||||
children = if !builtins.isAttrs nodeContent then {} else nodeContent;
|
||||
subPaths = builtins.filter isPath (builtins.attrNames children);
|
||||
jbossPath = "/" + concatStringsSep "/" nodePath;
|
||||
children = if !isAttrs nodeContent then {} else nodeContent;
|
||||
subPaths = filter isPath (attrNames children);
|
||||
getPriority = name:
|
||||
let value = children.${name};
|
||||
in if value._type or "" == "order" then value.priority else 1000;
|
||||
orderedSubPaths = lib.sort (a: b: getPriority a < getPriority b) subPaths;
|
||||
jbossAttrs = lib.filterAttrs (name: _: !(isPath name)) children;
|
||||
orderedSubPaths = sort (a: b: getPriority a < getPriority b) subPaths;
|
||||
jbossAttrs = filterAttrs (name: _: !(isPath name)) children;
|
||||
text =
|
||||
if nodeContent != null then
|
||||
''
|
||||
@ -615,7 +628,7 @@ in
|
||||
${jbossPath}:remove()
|
||||
end-if
|
||||
'';
|
||||
in text + lib.concatMapStringsSep "\n" (name: recurse (nodePath ++ [name]) children.${name}) orderedSubPaths;
|
||||
in text + concatMapStringsSep "\n" (name: recurse (nodePath ++ [name]) children.${name}) orderedSubPaths;
|
||||
in
|
||||
recurse [] attrs;
|
||||
|
||||
@ -652,7 +665,7 @@ in
|
||||
cp configuration/standalone.xml $out
|
||||
'';
|
||||
in
|
||||
lib.mkIf cfg.enable {
|
||||
mkIf cfg.enable {
|
||||
|
||||
assertions = [
|
||||
{
|
||||
@ -663,7 +676,7 @@ in
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
systemd.services.keycloakPostgreSQLInit = lib.mkIf createLocalPostgreSQL {
|
||||
systemd.services.keycloakPostgreSQLInit = mkIf createLocalPostgreSQL {
|
||||
after = [ "postgresql.service" ];
|
||||
before = [ "keycloak.service" ];
|
||||
bindsTo = [ "postgresql.service" ];
|
||||
@ -687,7 +700,7 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.keycloakMySQLInit = lib.mkIf createLocalMySQL {
|
||||
systemd.services.keycloakMySQLInit = mkIf createLocalMySQL {
|
||||
after = [ "mysql.service" ];
|
||||
before = [ "keycloak.service" ];
|
||||
bindsTo = [ "mysql.service" ];
|
||||
@ -737,7 +750,7 @@ in
|
||||
serviceConfig = {
|
||||
LoadCredential = [
|
||||
"db_password:${cfg.database.passwordFile}"
|
||||
] ++ lib.optionals (cfg.sslCertificate != null && cfg.sslCertificateKey != null) [
|
||||
] ++ optionals (cfg.sslCertificate != null && cfg.sslCertificateKey != null) [
|
||||
"ssl_cert:${cfg.sslCertificate}"
|
||||
"ssl_key:${cfg.sslCertificateKey}"
|
||||
];
|
||||
@ -769,7 +782,7 @@ in
|
||||
|
||||
export JAVA_OPTS=-Djboss.server.config.user.dir=/run/keycloak/configuration
|
||||
add-user-keycloak.sh -u admin -p '${cfg.initialAdminPassword}'
|
||||
'' + lib.optionalString (cfg.sslCertificate != null && cfg.sslCertificateKey != null) ''
|
||||
'' + optionalString (cfg.sslCertificate != null && cfg.sslCertificateKey != null) ''
|
||||
pushd /run/keycloak/ssl/
|
||||
cat "$CREDENTIALS_DIRECTORY/ssl_cert" <(echo) \
|
||||
"$CREDENTIALS_DIRECTORY/ssl_key" <(echo) \
|
||||
@ -784,11 +797,11 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
services.postgresql.enable = lib.mkDefault createLocalPostgreSQL;
|
||||
services.mysql.enable = lib.mkDefault createLocalMySQL;
|
||||
services.mysql.package = lib.mkIf createLocalMySQL pkgs.mariadb;
|
||||
services.postgresql.enable = mkDefault createLocalPostgreSQL;
|
||||
services.mysql.enable = mkDefault createLocalMySQL;
|
||||
services.mysql.package = mkIf createLocalMySQL pkgs.mariadb;
|
||||
};
|
||||
|
||||
meta.doc = ./keycloak.xml;
|
||||
meta.maintainers = [ lib.maintainers.talyz ];
|
||||
meta.maintainers = [ maintainers.talyz ];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user