From 3b3e2c9b57c8fe62c5f81da9ff376616cbec666d Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 23 Dec 2025 20:49:14 +0100 Subject: [PATCH 01/10] feat(self_host/monitoring): adding the reproductible dashboard config - Using assets for more simplicities --- services/self_host/monitor.nix | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/services/self_host/monitor.nix b/services/self_host/monitor.nix index 360a9eb..2cf4905 100644 --- a/services/self_host/monitor.nix +++ b/services/self_host/monitor.nix @@ -7,6 +7,7 @@ let cfg = config.service.selfhost.monitor; + dashboardsDir = ../../assets/grafana_dashboards; monitored = [ "nginx" "grafana" @@ -18,7 +19,36 @@ in enable = true; package = pkgs.grafana; dataDir = "/var/lib/grafana"; + provision = { + dashboards.settings.providers = [ + { + name = "nixos-dashboards"; + type = "file"; + updateIntervalSeconds = 30; + editable = false; + options = { + path = "/etc/grafana/dashboards"; + foldersFromFilesStructure = false; + }; + } + ]; + datasources.settings.datasources = [ + { + name = "Prometheus"; + type = "prometheus"; + uid = "prometheus"; + access = "proxy"; + url = "http://127.0.0.1:9090"; + isDefault = true; + editable = false; + jsonData = { + httpMethod = "POST"; + timeInterval = "15s"; + }; + } + ]; + }; settings = { server = { root_url = "https://monitor.enium.eu"; @@ -37,6 +67,8 @@ in }; security = { + cookie_secure = true; + cookie_samesite = "none"; allow_embedding = true; }; }; @@ -157,6 +189,8 @@ in ruleFiles = lib.mkForce [ "/etc/prometheus/services.rules" ]; }; + environment.etc."grafana/dashboards".source = dashboardsDir; + environment.etc."prometheus/services.rules".text = '' groups: - name: services From beafc15d79a181f39985db60e673bb331c5b6c57 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 23 Dec 2025 20:49:29 +0100 Subject: [PATCH 02/10] feat(self_host/monitoring): adding SSO to grafana --- services/self_host/monitor.nix | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/services/self_host/monitor.nix b/services/self_host/monitor.nix index 2cf4905..bbc25a7 100644 --- a/services/self_host/monitor.nix +++ b/services/self_host/monitor.nix @@ -56,16 +56,33 @@ in serve_from_sub_path = false; }; - users = { - auto_assign_org = true; - auto_assign_org_role = "Viewer"; + "auth.generic_oauth" = { + enabled = true; + name = "Enium"; + allow_sign_up = true; + client_id = "grafana"; + client_secret = "$__file{${config.age.secrets.grafana-oidc-secret.path}}"; + scopes = "openid profile email groups"; + auth_url = "https://auth.enium.eu/ui/oauth2"; + token_url = "https://auth.enium.eu/oauth2/token"; + api_url = "https://auth.enium.eu/oauth2/openid/grafana/userinfo"; + redirect_uri = "https://monitor.enium.eu/login/generic_oauth"; + use_pkce = true; + use_refresh_token = true; + login_attribute_path = "preferred_username"; + name_attribute_path = "name"; + email_attribute_path = "email"; + groups_attribute_path = "groups"; + role_attribute_path = "contains(groups, 'grafana_superadmins@enium.eu') && 'GrafanaAdmin' || contains(groups, 'grafana_admins@enium.eu') && 'Admin' || contains(groups, 'grafana_editors@enium.eu') && 'Editor' || 'Viewer'"; + allow_assign_grafana_admin = true; + role_attribute_strict = false; + skip_org_role_sync = false; }; - + log.level = "debug"; auth = { disable_login_form = true; disable_signout_menu = false; }; - security = { cookie_secure = true; cookie_samesite = "none"; From 94025116d054b12d2c70d6c598ba33d7010817b5 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 23 Dec 2025 20:49:58 +0100 Subject: [PATCH 03/10] feat(self_host/sso): adding the reproductible sso for grafana --- services/self_host/sso.nix | 73 +++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/services/self_host/sso.nix b/services/self_host/sso.nix index d43f1c8..0de69b7 100644 --- a/services/self_host/sso.nix +++ b/services/self_host/sso.nix @@ -26,7 +26,6 @@ in package = pkgs.kanidmWithSecretProvisioning_1_8; enableServer = true; serverSettings = { - role = "WriteReplica"; domain = "enium.eu"; origin = "https://auth.enium.eu"; bindaddress = "127.0.0.1:9000"; @@ -47,14 +46,86 @@ in mailAddresses = [ "raphael@enium.eu" ]; + groups = [ + "grafana_superadmins" + "nextcloud_user" + ]; }; }; groups = { + grafana_superadmins = { + present = true; + }; + grafana_admins = { + present = true; + }; + grafana_editors = { + present = true; + }; + grafana_user = { + present = true; + }; nextcloud_user = { present = true; }; }; systems.oauth2 = { + grafana = { + present = true; + displayName = "Grafana"; + originUrl = "https://monitor.enium.eu"; + originLanding = "https://monitor.enium.eu/login/generic_oauth"; + basicSecretFile = config.age.secrets.grafana-oidc-secret.path; + public = false; + enableLocalhostRedirects = false; + allowInsecureClientDisablePkce = false; + preferShortUsername = true; + scopeMaps = { + grafana_superadmins = [ + "email" + "openid" + "profile" + "groups" + ]; + grafana_admins = [ + "email" + "openid" + "profile" + "groups" + ]; + grafana_editors = [ + "email" + "openid" + "profile" + "groups" + ]; + grafana_user = [ + "email" + "openid" + "profile" + "groups" + ]; + }; + claimMaps = { + groups = { + joinType = "array"; + valuesByGroup = { + grafana_superadmins = [ + "grafana_superadmins" + ]; + grafana_admins = [ + "grafana_admins" + ]; + grafana_editors = [ + "grafana_editors" + ]; + grafana_user = [ + "grafana_user" + ]; + }; + }; + }; + }; nextcloud = { present = true; displayName = "Nextcloud"; From 655235c6baf96c328eced036afe4d26981b918da Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 25 Dec 2025 01:23:58 +0100 Subject: [PATCH 04/10] feat(sso/git): adding the kanidm connection to forgejo --- services/self_host/sso.nix | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/services/self_host/sso.nix b/services/self_host/sso.nix index 0de69b7..70b9955 100644 --- a/services/self_host/sso.nix +++ b/services/self_host/sso.nix @@ -70,6 +70,45 @@ in }; }; systems.oauth2 = { + forgejo = { + present = true; + displayName = "Forjego"; + originUrl = "https://git.enium.eu"; + imageFile = kanidmLogo; + originLanding = "https://git.enium.eu/user/oauth2/Enium/callback"; + basicSecretFile = config.age.secrets.forgejo-oidc-secret.path; + public = false; + enableLocalhostRedirects = false; + allowInsecureClientDisablePkce = true; + preferShortUsername = true; + scopeMaps = { + forgejo_admins = [ + "email" + "openid" + "profile" + "groups" + ]; + forgejo_users = [ + "email" + "openid" + "profile" + "groups" + ]; + }; + claimMaps = { + groups = { + joinType = "array"; + valuesByGroup = { + forgejo_admins = [ + "forgejo_admins" + ]; + forgejo_users = [ + "forgejo_users" + ]; + }; + }; + }; + }; grafana = { present = true; displayName = "Grafana"; From 2ca39ee7c9167698a75bd2f87fceb9a9a6691a2e Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 25 Dec 2025 01:24:35 +0100 Subject: [PATCH 05/10] feat(self_host/sso): adding the images to the kanidm --- services/self_host/sso.nix | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/services/self_host/sso.nix b/services/self_host/sso.nix index 70b9955..e83b5e3 100644 --- a/services/self_host/sso.nix +++ b/services/self_host/sso.nix @@ -9,6 +9,22 @@ let cfg = config.service.selfhost.sso; kanidm-admin = config.age.secrets."kanidm-admin".path; kanidm-idmAdmin = config.age.secrets."kanidm-idmAdmin".path; + imagesDir = "/user/share/kanidm/assets"; + kanidmLogo = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/doc-sheet/forgejo/refs/heads/forgejo/assets/logo.svg"; + name = "kanidm.svg"; + sha256 = "sha256-rP7aZURtHBfF2OYuGLcKZhbvIN+B596T/3kaOxHUvig="; + }; + grafanaLogo = pkgs.fetchurl { + url = "https://upload.wikimedia.org/wikipedia/commons/a/a1/Grafana_logo.svg"; + name = "grafana.svg"; + sha256 = "sha256-UjE6ArLCa52o3XGUmpqPoakbEOeFi+zfsnATi1FtWmQ="; + }; + nextcloudLogo = pkgs.fetchurl { + url = "https://upload.wikimedia.org/wikipedia/commons/6/60/Nextcloud_Logo.svg"; + name = "nextcloud.svg"; + sha256 = "sha256-hL51zJkFxUys1CoM8yUxiH8BDw111wh3Qv7eTLm+XYo="; + }; in { config = lib.mkIf cfg { @@ -48,6 +64,7 @@ in ]; groups = [ "grafana_superadmins" + "forgejo_admins" "nextcloud_user" ]; }; @@ -62,7 +79,13 @@ in grafana_editors = { present = true; }; - grafana_user = { + grafana_users = { + present = true; + }; + forgejo_admins = { + present = true; + }; + forgejo_users = { present = true; }; nextcloud_user = { @@ -112,6 +135,7 @@ in grafana = { present = true; displayName = "Grafana"; + imageFile = grafanaLogo; originUrl = "https://monitor.enium.eu"; originLanding = "https://monitor.enium.eu/login/generic_oauth"; basicSecretFile = config.age.secrets.grafana-oidc-secret.path; @@ -138,7 +162,7 @@ in "profile" "groups" ]; - grafana_user = [ + grafana_users = [ "email" "openid" "profile" @@ -158,8 +182,8 @@ in grafana_editors = [ "grafana_editors" ]; - grafana_user = [ - "grafana_user" + grafana_users = [ + "grafana_users" ]; }; }; @@ -168,6 +192,7 @@ in nextcloud = { present = true; displayName = "Nextcloud"; + imageFile = nextcloudLogo; originUrl = "https://nextcloud.enium.eu"; originLanding = "https://nextcloud.enium.eu/login"; basicSecretFile = config.age.secrets.nextcloud-oidc-secret.path; From cc166f8794adc0ae676b68156d8b1c20f232f59b Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 25 Dec 2025 01:25:29 +0100 Subject: [PATCH 06/10] feat(hosts/server): adding the sshkey for connection --- hosts/server/configuration.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hosts/server/configuration.nix b/hosts/server/configuration.nix index 7e122f8..f2ea58b 100644 --- a/hosts/server/configuration.nix +++ b/hosts/server/configuration.nix @@ -6,6 +6,9 @@ ... }: +let + sshKeyMac = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKbHk7YasSMK5FBCArKLeqIoaGXsN+WlgVquObyC5Zec raphael@MacBook-Pro-de-raphael.local"; +in { imports = [ ../global.nix @@ -122,6 +125,9 @@ efi.canTouchEfiVariables = true; }; + users.users.raphael.openssh.authorizedKeys.keys = [ + sshKeyMac + ]; services = { seatd.enable = true; xserver = { From 9d9236cd534d95936f846ad643af314906236d0a Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 25 Dec 2025 01:25:52 +0100 Subject: [PATCH 07/10] feat(host/server): adding the forgejo secrets --- hosts/server/secrets.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hosts/server/secrets.nix b/hosts/server/secrets.nix index b97de16..cc754ff 100644 --- a/hosts/server/secrets.nix +++ b/hosts/server/secrets.nix @@ -39,6 +39,13 @@ mode = "0440"; }; + age.secrets."forgejo-oidc-secret" = { + file = ../../secrets/forgejo-oidc-secret.age; + owner = "kanidm"; + group = "forgejo"; + mode = "0440"; + }; + age.secrets."nextcloud-database" = { file = ../../secrets/nextcloud-database.age; owner = "nextcloud"; From 94af05654832d19f3bc8219fa09f811ff837df50 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 25 Dec 2025 01:26:09 +0100 Subject: [PATCH 08/10] feat(secrets/forgejo): adding the forgejo secrets --- secrets/forgejo-oidc-secret.age | Bin 0 -> 495 bytes secrets/secrets.nix | 1 + 2 files changed, 1 insertion(+) create mode 100644 secrets/forgejo-oidc-secret.age diff --git a/secrets/forgejo-oidc-secret.age b/secrets/forgejo-oidc-secret.age new file mode 100644 index 0000000000000000000000000000000000000000..d043dc597175d3dec536649c30450fa7bbf6af04 GIT binary patch literal 495 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCUltkgEhELU(0ODamT z%rnb(NeT$h5BJS7bS`$uF-yvca;xyl&MNT9FsSei4-3f(3FLCkamtGFPItHP^YSY; zO>xc(ay9pMF*o*gObShk%E`+$^))ng_w+TkC`Pv}Ke;f|Cr}~HD6uHj$;-DOHPxab zwZPRY#LU04%qJ((%%s3Es5ITRB0aw%FEGQ^C7&xdGt4r)%rnEuE2_jb#oaikG$J)H zIn}_(*&{G9yr|I3-PF%1$iLFk&w@)=S63k~JHXq!z%MVfFwr+V(?8SDBBv-fC8Mm; zr^-3oDb*t_KPSJ$-7CU1$%Jdc)A<_Ln+|^Dog-BL;j?_tAD^|4D>Nkoo_asH`Q7!9 zciykrk9HkZm^vkJCPSpIm`jrWqgivhtA#KAVEZwRBV?)aEf1-py7qvlDu3p0*$`p< zB0W@T%9(2cOI=>A%}UFkWat(7rY?4R0;l)>vg)ne?ksE^RW*V=9gys%p8Q}C%VGcf$%qBK{PiR Date: Thu, 25 Dec 2025 01:26:50 +0100 Subject: [PATCH 09/10] feat(self_host/git): moving from gitea to forgejo --- services/self_host/git.nix | 78 +++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/services/self_host/git.nix b/services/self_host/git.nix index c31e695..445dd22 100644 --- a/services/self_host/git.nix +++ b/services/self_host/git.nix @@ -1,49 +1,57 @@ { config, pkgs, lib, ... }: let - giteaDomain = "git.enium.eu"; + gitDomain = "git.enium.eu"; in { - services.gitea = { - enable = true; - appName = "Enium Git"; - user = "gitea"; - group = "gitea"; - database.type = "sqlite3"; + services = { + forgejo = { + enable = true; + database.type = "postgres"; - settings = { - server = { - DOMAIN = giteaDomain; - ROOT_URL = "https://${giteaDomain}/"; - SSH_PORT = 42131; - HTTP_ADDR = "127.0.0.1"; - HTTP_PORT = 3042; - DISABLE_REGISTRATION = true; - ALLOW_ONLY_EXTERNAL_REGISTRATION = true; - SHOW_REGISTRATION_BUTTON = false; - DISABLE_REGULAR_LOGIN = true; - }; + settings = { + server = { + "DEFAULT.APP_NAME" = "Enium Git"; + "DEFAULT.APP_SLOGAN" = "Born2Code"; + DOMAIN = gitDomain; + ROOT_URL = "https://${gitDomain}/"; + SSH_PORT = 42131; + HTTP_ADDR = "127.0.0.1"; + HTTP_PORT = 3042; + DISABLE_REGISTRATION = true; + ALLOW_ONLY_EXTERNAL_REGISTRATION = true; + SHOW_REGISTRATION_BUTTON = false; + DISABLE_REGULAR_LOGIN = true; + }; - service = { - DISABLE_REGISTRATION = true; - ALLOW_ONLY_EXTERNAL_REGISTRATION = true; - }; + oauth2 = { + ENABLED = true; + NAME = "Enium"; + CLIENT_ID = "forgejo"; + CLIENT_SECRET = "${config.age.secrets.forgejo-oidc-secret.path}"; + SCOPES = "openid email profile groups"; + LOGIN_ATTRIBUTE_PATH = "preferred_username"; + AUTH_URL = "https://git.enium.eu/ui/oauth2"; + TOKEN_URL = "https://git.enium.eu/oauth2/token"; + API_URL = "https://git.enium.eu/oauth2/openid/forgejo/userinfo"; + CODE_CHALLENGE_METHOD = "S256"; + ENABLE_AUTO_REGISTRATION = true; + UPDATE_AVATAR = true; + }; - web = { - DISABLE_LOCAL_LOGIN = true; - }; - - oauth2_client = { - ENABLE_AUTO_REGISTRATION = true; + security = { + LOGIN_REMEMBER_DAYS = 14; + }; }; }; - }; - services.nginx.virtualHosts."${giteaDomain}" = { - enableACME = true; - forceSSL = true; - locations."/" = { - proxyPass = "http://127.0.0.1:3042"; + nginx.virtualHosts."${gitDomain}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:3042"; + proxyWebsockets = true; + }; }; }; } From b9ed7f1eb8f10ce2677d3c937d38e73d19f30b03 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 25 Dec 2025 01:27:31 +0100 Subject: [PATCH 10/10] fix(self_host/mail): restore the connection to mailjet --- services/self_host/mail.nix | 98 +++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 54 deletions(-) diff --git a/services/self_host/mail.nix b/services/self_host/mail.nix index 3bbc01b..eb0b401 100644 --- a/services/self_host/mail.nix +++ b/services/self_host/mail.nix @@ -77,11 +77,6 @@ in smtpd_tls_cert_file = "/var/lib/acme/mail.enium.eu/fullchain.pem"; smtpd_tls_key_file = "/var/lib/acme/mail.enium.eu/key.pem"; - smtpd_milters = "unix:/run/rspamd/rspamd.sock"; - non_smtpd_milters = "unix:/run/rspamd/rspamd.sock"; - milter_protocol = "6"; - milter_default_action = "accept"; - milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_authen}"; }; master."submission" = { type = "inet"; @@ -107,7 +102,7 @@ in systemd.services.postfix.preStart = lib.mkMerge [ (lib.mkAfter '' umask 077 - echo "[in-v3.mailjet.com]:587 $(cat ${mailjet-pass}):$(cat ${mailjet-pass})" > /var/lib/postfix/sasl_passwd + echo "[in-v3.mailjet.com]:587 $(cat ${mailjet-user}):$(cat ${mailjet-pass})" > /var/lib/postfix/sasl_passwd chown postfix:postfix /var/lib/postfix/sasl_passwd chmod 600 /var/lib/postfix/sasl_passwd ${pkgs.postfix}/bin/postmap /var/lib/postfix/sasl_passwd @@ -143,7 +138,7 @@ in extraConfig = '' protocols = imap lmtp auth_mechanisms = plain login - disable_plaintext_auth = yes + disable_plaintext_auth = no base_dir = /run/dovecot userdb { @@ -240,57 +235,51 @@ in services.rspamd = { enable = true; - extraConfig = '' - worker "controller" { - bind_socket = "127.0.0.1:11334"; - password = "admin"; + postfix.enable = true; + extraConfig = '' + worker "controller" { + bind_socket = "127.0.0.1:11334"; + password = "admin"; + }; + + worker "normal" { + bind_socket = "127.0.0.1:11333"; + }; + + worker "rspamd_proxy" { + bind_socket = "127.0.0.1:11332"; + milter = yes; + timeout = 120s; + upstream "local" { + self_scan = yes; + }; + }; + + actions { + reject = 12; + add_header = 6; + greylist = 4; + }; + + classifier "bayes" { + backend = "redis"; + servers = "127.0.0.1:6381"; + autolearn = true; + min_learns = 200; + new_schema = true; + cache = true; + + statfile { + symbol = "BAYES_HAM"; + spam = false; }; - worker "normal" { - bind_socket = "127.0.0.1:11333"; + statfile { + symbol = "BAYES_SPAM"; + spam = true; }; - worker "rspamd_proxy" { - bind_socket = "127.0.0.1:11332"; - milter = yes; - timeout = 120s; - upstream "local" { - self_scan = yes; - }; - }; - - actions { - reject = 12; - add_header = 6; - greylist = 4; - }; - - milter { - unix_socket = "/run/rspamd/milter.sock"; - unix_permissions = 0660; - user = "rspamd"; - group = "postfix"; - }; - - classifier "bayes" { - backend = "redis"; - servers = "127.0.0.1:6381"; - autolearn = true; - min_learns = 200; - new_schema = true; - cache = true; - - statfile { - symbol = "BAYES_HAM"; - spam = false; - }; - - statfile { - symbol = "BAYES_SPAM"; - spam = true; - }; - - learn_condition = <