Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions doc/keycloak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Keycloak

[Keycloak](https://www.keycloak.org/) is an open-source identity and access management solution providing single sign-on (SSO), user federation, and support for OpenID Connect, OAuth 2.0 and SAML.

> [!NOTE]
>
> This module runs Keycloak in development mode (`start --optimized` with an embedded database). It is intended for local development and testing, not production.

{#start}

## Getting Started

```nix
# In `perSystem.process-compose.<name>`
{
services.keycloak."kc" = {
enable = true;
settings.http-port = 8091;

database.type = "dev-file";

realms = {
master = {
export = {
enable = true; # Export to data folder.
};
};
test = {
# Set that once exported.
# import = "./test.json"

export = {
enable = true;
path = "./test.json";
};
};
};
};
}
```

Keycloak becomes available at [http://localhost:8091](http://localhost:8091).
The temporary admin user is `admin` with the password set by [`initialAdminPassword`](#admin-password) (`admin` by default).

{#tips}

## Tips & Tricks

{#import-realms}

### Import Realms

A realm listed under `realms` with `import` set is imported on start up, provided the realm does not already exist.
The `import` path may be relative to the `process-compose` working directory or a Nix store path.

```nix
{
services.keycloak."kc" = {
enable = true;

realms.test = {
import = ./test.json; # Nix store path. Quote to make it a relative path.
};
};
}
```

{#export-realms}

### Export Settings

To export realms when you made changes in the UI, make sure to have set `export` on the realms you care about:

```nix
{
services.keycloak."kc" = {
enable = true;

realms.test = {
export = {
enable = true;
path = "./test.json"; # Optional.
};
};
};
}
```

This creates two process-compose processes, both **disabled by default** (they are not run automatically, since exporting requires Keycloak to be stopped):

- `«name»-realm-export-all` — exports every realm with `export.enable = true`.

Run it manually once Keycloak has stopped, e.g. from the process-compose TUI, or:

```bash
# Stop keycloak first then run the export:
process-compose process stop «name»
process-compose process start «name»-realm-export-all
```

Each realm is exported to its `path` when that path is a relative (non-store) location, otherwise to `${config.services.keycloak.«name».dataDir}/realm-export/<realm>.json`. Exports are pretty-printed with `jq` for easy diffing.

You can disable the export processes/scripts globally with `exportRealms = false;`.
1 change: 1 addition & 0 deletions doc/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ short-title: Services
- [[tempo]]
- [[loki]]
- [[pyroscope]]
- [[keycloak]]#
- [[memcached]]#
- [[minio]]#
- [[mongodb]]#
Expand Down
4 changes: 3 additions & 1 deletion nix/services/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ in
./qdrant.nix
./chromadb.nix
./neo4j.nix
]) ++ [
./keycloak.nix
])
++ [
./devshell.nix
];

Expand Down
78 changes: 78 additions & 0 deletions nix/services/keycloak-certs_test.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{ pkgs, config, ... }:
let
name = "k1-certs";
inherit (config.services.keycloak.${name}) dataDir;
realmSrc = ./keycloak/test-realms/test.json;

sslCertificate = "./keycloak/test-certs/ssl-cert.crt";
sslCertificateKey = "./keycloak/test-certs/ssl-cert.key";
in
{
services.keycloak.${name} = {
enable = true;
settings.http-port = 8090;

database.type = "dev-file";

# They must not end up in the Nix store.
inherit sslCertificate sslCertificateKey;

realms = {
master = {
export = {
enable = true;
};
};

test = {
import = realmSrc;
export = {
enable = true;
};
};
};
};

# Copy certificates from the Nix store to correct location (only for tests).
settings.processes.copy-certs =
let
cert = ./keycloak/test-certs/ssl-cert.crt;
certKey = ./keycloak/test-certs/ssl-cert.key;
in
{
command = pkgs.writeShellApplication {
name = "copy-certs";
text =
# Bash
''
echo "Copying certificates (pwd: $(pwd))..."
mkdir -p "keycloak/test-certs"
cp "${cert}" "keycloak/test-certs/ssl-cert.crt"
cp "${certKey}" "keycloak/test-certs/ssl-cert.key"
'';
};
};

settings.processes.${name} = {
depends_on.copy-certs.condition = "process_completed_successfully";
};

settings.processes.test =
let
test-export = pkgs.callPackage ./keycloak/test-realms/export.nix {
process-compose = config.package;
realmDstDir = "${dataDir}/realm-export";
pcSocketPath = config.cli.options.unix-socket;
keycloak-name = name;
};
in
{
command = pkgs.writeShellApplication {
runtimeInputs = [ test-export ];
text = "test-export";
name = "${name}-test";
};

depends_on.${name}.condition = "process_healthy";
};
}
10 changes: 10 additions & 0 deletions nix/services/keycloak.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Based on Devenv's keycloak module:
# Ref: https://github.com/cachix/devenv/commit/32f6747aabbd5aeb7413bae53d7e01e224ec77bc
{ ...
}:
{
imports = [
./keycloak/service.nix
./keycloak/options.nix
];
}
Loading