Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add keycloak and LDAP for SSO #28

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions hosts/goldberg/configuration.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
../../services/hedgedoc.nix
../../services/pretix.nix
../../services/pretalx.nix
../../services/keycloak
];

system.stateVersion = "23.05";
Expand Down
29 changes: 29 additions & 0 deletions packages/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,33 @@ final: prev:
})];

matrixjoinlink = final.callPackage ./matrixjoinlink {};
keycloak-registration-captcha = final.maven.buildMavenPackage rec {
pname = "keycloak-registration-captcha";
version = "1.1.0";
src = final.fetchFromGitHub {
owner = "chaos-jetzt";
repo = pname;
rev = "v${version}";
hash = "sha256-133cMOSHtDj1eTS01AuiNQa7aI0tNSCt1rg1mgCEinw=";
};

nativeBuildInputs = [ final.maven ];

mvnHash = "sha256-GTFDjQT7g1sMfIbH/wkxBS0yJDctW5l3QFsv2aggPN0=";

installPhase = ''
runHook preInstall
install -Dm444 -t "$out" target/registration-captcha.jar
runHook postInstall
'';
};

cj-keycloak-theme = final.fetchFromGitHub rec {
pname = "cj-keycloak-theme";
version = "2020-12-19-${builtins.substring 0 6 rev}";
owner = "chaos-jetzt";
repo = "cj-keycloak-theme";
rev = "3075080f828782cfae076c8f4f7866112f544d94";
hash = "sha256-uGUFPE1o0RaKxXh+Vv+OUxCSnyzARo9v2ucWHchW/wg=";
};
}
8 changes: 6 additions & 2 deletions secrets/goldberg/secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ vaultwarden:
hedgedoc_env: ENC[AES256_GCM,data:VHIzmq7P1pqS72HbRXRT3k7n6vyPkzkQFJdveseCAHnzdXlEF0lHr+Up7J6XhfhtQXO3ogV2jkGZpOMY0OuEvhLf2yGkBj3W0ZtG7Kx6Rdcbb5rG7Z6Vb1vpL/aT88QFd3VX23M+FPFyWeYKGOvGRuCela+mUX7jDs2W4jOrYOtEGe3+V08DcvtcCvE2L1NqeDQ=,iv:011/ZRdQlkFQ2TZpzQhfRf/OTawnHFQDockLGlOrkmc=,tag:Y66RIBtyjl5VSo23GU4sNg==,type:str]
pretix_env: ENC[AES256_GCM,data:Cu3S3j49P0IVZMKfzuUBdPVl4YTDUybmVKasGCaqrcyWFKbRrd1XK9NmZ+iYHemuJ7A6F+I1qrnn7GdwayOQr0MCAIpoIuDjiYex1wi3WPkx48Dxk9YInoD6JGzmYQE64Qe08rlH1gt3nBXGKkUQ5D4razNokO1F4pYQxthsTvP3s5+zOD5Z3H6/wy30e5Ihtp3KMiiJ5OJzBUelmA2YN5Q/l4TAR/pTk0R5557TdAmqUuMWzxovCl4cXY8xP6Nlnc9X3Hg7YdfTOTAVLak5aMOi2kZFB79CxF8QBjZzwS1EuyFImyWohP53Yb/SxdnsgDNQQajxfQy/8Z4Bg1T7k2hRZ5LBuITwu15wu5V3h+VPTgZMDi1PeQhN8InZF8nNenpdw+4FRNinR7qIVf31SsCbAOXs2CU3KEi8KfEc7MEsvSG2tNOoy5zX/2H6EKvHJZED+mHcnvffAjTIkvVLvGw=,iv:NdCtoXtL0JtmzrheW6tbYd6XwyfH/DVqL9sZBPCmnws=,tag:/7ts5E1Pc5mF5YpWSGgorw==,type:str]
pretalx_env: ENC[AES256_GCM,data:Fq37a73w5/m/2T/dFqgUx0EIESWLr2+CEYv869YBSnGLAVO5eqzrtXwiPq3g/vtEh/b1T+jbwi2y04PgM4IFOJ2UMYtIrxW0BAsRB26XBTAEF3NLMiHTYj/+4D+NVaSFM7vm4TGTLso//rkBtCJvWnIxbGCphAREgG0qCaacUBfv+HYtdA/REFfqyohxyLleSvvvVdSKbNK4gOpe3Pp1d03Jg3LY6dB8NqNSCZCdSEa65+xcniJjJXqAwhyG3VcefzaQXh+nOLP01ZVijDdRkWw=,iv:jkoxmrZr+vlM92UIGLOlFMC7UeJm7UjRL6eTzVOAcvo=,tag:gGEkRHYbJUWSwy2lTO5HCA==,type:str]
keycloak:
db_password: ENC[AES256_GCM,data:fRSCENb0II+obekeD82JtjSgKfMsfQHPn33jft7xCHqkEpAkBk5TZ30rYGJOQ+09hdKx4NTFS6iYMG1jEDYDLw==,iv:RhsPKrjj+IaRRUK5NELKPTS2vkO7GnTWRMySpzJlzvs=,tag:YOO9cx4nMJwXeiNHoAPsEw==,type:str]
ldap:
admin_password: ENC[AES256_GCM,data:Xj8DiRYGf6Kgk6nnhKfblbQ3u2hcJgl+m+piJpw1ivyJ8224laX9HZHZqYWtczOZi7oy2ddF5XcLVEh0rLa/4w==,iv:dJqusylgVsn0elF3yRuV+6bDB3KiKdxnVf0UL7DE+YQ=,tag:+7oP5sQliwSOF2OE4dO5BA==,type:str]
sops:
kms: []
gcp_kms: []
Expand All @@ -31,8 +35,8 @@ sops:
QjBmYlNYWlFoWHd0ZFJkWE0xMkpvZzQKJwKap35S2pWGNOtBHe931dRqAQAczbWv
/BUEtl900F8YLQCB1/myV0Dk5X9XDlww1yrzw/La3gXANY93Ndu3MA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-07-02T19:49:57Z"
mac: ENC[AES256_GCM,data:28L6nbZms7df9fvrcC5HdDl7fwHFlXDrW3JibwzlTARfi7p9goOUxpUUifXcrWU6dawWJS/b9CQyy9eUoT2XpqXFF3bkMK67to8IGJWTjkF2x2hEa+nl+OuXFCz5cqr/QsDtNPzEitDARA7+GNt8qtUoxiZ41oFmEx2rfQyEmj0=,iv:gUL8/7ZcKConZamz3kWTBZuYg+opn8LPueNfxPfzfi0=,tag:9hAPtZmZH+puf0o3WpwpDw==,type:str]
lastmodified: "2024-07-08T09:22:18Z"
mac: ENC[AES256_GCM,data:xtLzeje57woFwmI2vqNcb46utHNQqteQPmVZQartlL1l8E/AKmxPtMMCjG6x7//DOsbt5YliXJ/5Ik0VEkHzVmlK05RSy3CSA8UATaWExAEgyfQIzpvv14Fet0rjE7T48IcqfaGYpz5arzbFF2VJaSCuPLPqwKOaa2aCDdkEzaA=,iv:9o/OGN41XoSjk35Nd+hdgtk4+MuoLTtAeOxUVRGEm3w=,tag:4AK7whc85fjhBJ8mBm+nbA==,type:str]
pgp:
- created_at: "2023-07-23T14:01:56Z"
enc: |-
Expand Down
2 changes: 1 addition & 1 deletion services/dokuwiki.nix
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ in {
};
plugin.oauthkeycloak = {
key = get_secret "dokuwiki/keycloak_key";
openidurl = "https://sso.chaos.jetzt/auth/realms/${if isDev then "dev" else "chaos-jetzt"}/.well-known/openid-configuration";
openidurl = "https://sso${lib.optionalString isDev ".dev"}.chaos.jetzt/auth/realms/${if isDev then "dev" else "chaos-jetzt"}/.well-known/openid-configuration";
};
};

Expand Down
160 changes: 160 additions & 0 deletions services/keycloak/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
{ pkgs
, config
, lib
, baseDomain
, isDev
, ...
}:

let
sso_domain = "sso.${baseDomain}";

populate_content = pkgs.writeText "populate_content.ldif" ''
dn: dc=chaos, dc=jetzt
dc: chaos
o: chaos.jetzt
objectClass: top
objectclass: organization
objectclass: dcObject

dn: ou=People,dc=chaos,dc=jetzt
changetype: add
objectClass: organizationalUnit

dn: ou=Groups,dc=chaos,dc=jetzt
changetype: add
objectClass: organizationalUnit
'';
init_ldap = pkgs.writeShellScript "init-ldap" ''
export PATH=${config.services.openldap.package}/bin:$PATH
export LDAP_ALREADY_EXISTS=68
ldapadd -c -Y EXTERNAL -H ldapi:/// -f ${populate_content}
ret=$?
if [[ $ret -eq $LDAP_ALREADY_EXISTS ]]; then
echo "Everything already exists"
exit 0
fi
exit $ret
'';
in {
sops.secrets = {
"keycloak/db_password" = {};
"ldap/admin_password".owner = config.services.openldap.user;
};
services.keycloak = {
enable = true;
database = {
createLocally = true;
host = "localhost";
name = "keycloak";
passwordFile = config.sops.secrets."keycloak/db_password".path;
type = "postgresql";
};
settings = {
hostname = sso_domain;
http-host = "127.0.0.1";
# Since we're comming from 12.x
http-relative-path = "/auth";
http-port = 8081;
https-port = 8443;
proxy = "edge";
spi-theme-welcome-theme = "chaos-jetzt";
spi-connections-jpa-legacy-migration-strategy = "update";
};
plugins = [ pkgs.keycloak-registration-captcha ];
themes.cj-keycloak-theme = pkgs.cj-keycloak-theme;
};

services.openldap = {
enable = true;
urlList = [
"ldap:///"
"ldapi:///"
];
settings = {
attrs.olcLogLevel = [ "stats" ];
children = let
root_access = "dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth";
in{
"cn=schema".includes = [
"${pkgs.openldap}/etc/schema/core.ldif"
"${pkgs.openldap}/etc/schema/cosine.ldif"
"${pkgs.openldap}/etc/schema/nis.ldif"
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
];
"olcDatabase={-1}frontend".attrs = {
objectClass = [ "olcDatabaseConfig" "olcFrontendConfig" ];
olcDatabase = "{-1}frontend";
olcSizeLimit = "500";
# Allows the local root user to see the running config
# ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config
olcAccess = [
"{0}to * by ${root_access} manage by * break"
"{1}to dn.exact=\"\" by * read"
"{2}to dn.base=\"cn=Subschema\" by * read"
];
structuralObjectClass = "olcDatabaseConfig";
};
/* "olcBackend={0}mdb".attrs = {
objectClass = "olcBackendConfig";
olcBackend = "{0}config";
}; */
"olcDatabase={0}config".attrs = {
objectClass = "olcDatabaseConfig";
olcDatabase = "{0}config";
# Allows the local root user to see the running config
# ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config
olcAccess = [
"{0}to * by ${root_access} manage by * break"
];
};
"olcDatabase={1}mdb".attrs = {
objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];

olcDatabase = "{1}mdb";
olcDbDirectory = "/var/lib/openldap/data";

olcSuffix = "dc=chaos,dc=jetzt";

olcRootDN = "cn=admin,dc=chaos,dc=jetzt";
olcRootPW.path = config.sops.secrets."ldap/admin_password".path;

olcLastMod = "TRUE";
olcdbcheckpoint = "512 30";

olcDbIndex = [
"objectClass eq"
"cn,uid eq"
"uidNumber,gidNumber eq"
"member,memberUid eq"
];
olcAccess = [
''{0}to attrs=userPassword by self write by anonymous auth by * none''
''{1}to attrs=shadowLastChange by self write by * read''
];
};
};
};
};

systemd.services.openldap.serviceConfig.ExecStartPost = [
"!${init_ldap}"
];

services.nginx = {
enable = true;
virtualHosts."${sso_domain}" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://127.0.0.1:${toString config.services.keycloak.settings.http-port}";
locations."= /".return = "307 ${config.services.keycloak.settings.http-relative-path}/realms/${if !isDev then "chaos-jetzt" else "dev"}/account/";
};
};

/*
NOTE(@e1mo): Gripes with the keycloak module
- `database.createLocaly` doesn't respect username
- `initialAdminPassword` can't be a secret
- `pkgs.keycloak.plugins` can't be discovered via the search
*/
}