diff --git a/.just/machine.just b/.just/machine.just index 1ce791f..6dabbc0 100644 --- a/.just/machine.just +++ b/.just/machine.just @@ -5,6 +5,5 @@ ls -1 ../systems/x86_64-linux/ [doc('Update the target machine')] -@update machine: - just assert '-d "../systems/x86_64-linux/{{ machine }}"' "Machine {{ machine }} does not exist, must be one of: $(ls ../systems/x86_64-linux/ | tr '\n' ' ')" +update machine: nixos-rebuild switch --use-remote-sudo --target-host {{ machine }} --flake ..#{{ machine }} \ No newline at end of file diff --git a/.justfile b/.justfile index 3a15d20..2788376 100644 --- a/.justfile +++ b/.justfile @@ -19,15 +19,4 @@ mod machine '.just/machine.just' [doc('Introspection on flake output')] @select key: - nix eval --json .#{{ key }} | jq . - - - -#=============================================================================================== -# Utils -#=============================================================================================== -[no-exit-message] -[no-cd] -[private] -@assert condition message: - [ {{ condition }} ] || { echo -e 1>&2 "\n\x1b[1;41m Error \x1b[0m {{ message }}\n"; exit 1; } \ No newline at end of file + nix eval --json .#{{ key }} | jq . \ No newline at end of file diff --git a/modules/nixos/services/authentication/zitadel/default.nix b/modules/nixos/services/authentication/zitadel/default.nix index 917bde4..eaa3c60 100644 --- a/modules/nixos/services/authentication/zitadel/default.nix +++ b/modules/nixos/services/authentication/zitadel/default.nix @@ -1,6 +1,6 @@ { config, lib, pkgs, namespace, system, inputs, ... }: let - inherit (lib) mkIf mkEnableOption mkOption types toUpper toSentenceCase nameValuePair mapAttrs' concatMapAttrs concatMap listToAttrs imap0 getAttrs getAttr hasAttr typeOf head drop length; + inherit (lib) mkIf mkEnableOption mkOption types toUpper nameValuePair mapAttrs' concatMapAttrs getAttrs getAttr hasAttr typeOf head drop length; inherit (lib.${namespace}.strings) toSnakeCase; cfg = config.${namespace}.services.authentication.zitadel; @@ -73,40 +73,6 @@ in ''; }; - role = mkOption { - default = {}; - type = types.attrsOf (types.submodule ({ name, ... }: { - options = - let - roleName = name; - in - { - displayName = mkOption { - type = types.str; - default = toSentenceCase name; - example = "RoleName"; - description = '' - Name used for project role. - ''; - }; - - group = mkOption { - type = types.nullOr types.str; - default = null; - example = "some_group"; - description = '' - Group used for project role. - ''; - }; - }; - })); - }; - - assign = mkOption { - default = {}; - type = types.attrsOf (types.listOf types.str); - }; - application = mkOption { default = {}; type = types.attrsOf (types.submodule { @@ -208,74 +174,6 @@ in }; })); }; - - action = mkOption { - default = {}; - type = types.attrsOf (types.submodule ({ name, ... }: { - options = { - script = mkOption { - type = types.str; - example = '' - (ctx, api) => { - api.v1.claims.setClaim('some_claim', 'some_value'); - }; - ''; - description = '' - The script to run. This must be a function that receives 2 parameters, and returns void. During the creation of the action's script this module simly does `const {{name}} = {{script}}`. - ''; - }; - - timeout = mkOption { - type = (types.ints.between 0 20); - default = 10; - example = "10"; - description = '' - After which time the action will be terminated if not finished. - ''; - }; - - allowedToFail = mkOption { - type = types.bool; - default = true; - example = "true"; - description = '' - Allowed to fail. - ''; - }; - }; - })); - }; - - triggers = mkOption { - default = []; - type = types.listOf (types.submodule { - options = { - flowType = mkOption { - type = types.enum [ "authentication" "customiseToken" "internalAuthentication" "samlResponse" ]; - example = "customiseToken"; - description = '' - Type of the flow to which the action triggers belong. - ''; - }; - - triggerType = mkOption { - type = types.enum [ "postAuthentication" "preCreation" "postCreation" "preUserinfoCreation" "preAccessTokenCreation" "preSamlResponse" ]; - example = "postAuthentication"; - description = '' - Trigger type on when the actions get triggered. - ''; - }; - - actions = mkOption { - type = types.nonEmptyListOf types.str; - example = ''[ "action_name" ]''; - description = '' - Names of actions to trigger - ''; - }; - }; - }); - }; }; })); }; @@ -293,28 +191,23 @@ in mapEnum = prefix: value: "${prefix}_${value |> toSnakeCase |> toUpper}"; mapValue = type: value: ({ - appType = mapEnum "OIDC_APP_TYPE" value; grantTypes = map (t: mapEnum "OIDC_GRANT_TYPE" t) value; responseTypes = map (t: mapEnum "OIDC_RESPONSE_TYPE" t) value; - authMethodType = mapEnum "OIDC_AUTH_METHOD_TYPE" value; - - flowType = mapEnum "FLOW_TYPE" value; - triggerType = mapEnum "TRIGGER_TYPE" value; - accessTokenType = mapEnum "OIDC_TOKEN_TYPE" value; }."${type}" or value); toResource = name: value: nameValuePair (toSnakeCase name) (lib.mapAttrs' (k: v: nameValuePair (toSnakeCase k) (mapValue k v)) value); + withName = name: attrs: attrs // { inherit name; }; withRef = type: name: attrs: attrs // (mapRef type name); + withDefaults = defaults: attrs: defaults // attrs; select = keys: callback: set: if (length keys) == 0 then mapAttrs' callback set else let key = head keys; in - concatMapAttrs (k: v: select (drop 1 keys) (callback k) (v.${key} or {})) set - ; + concatMapAttrs (k: v: select (drop 1 keys) (callback k) (v.${key} or {})) set; config' = config; @@ -338,105 +231,57 @@ in resource = { # Organizations - zitadel_org = cfg.organization |> select [] (name: { isDefault, ... }: - { inherit name isDefault; } + zitadel_org = cfg.organization |> select [] (name: value: + value + |> getAttrs [ "isDefault" ] + |> withName name |> toResource name ); # Projects per organization - zitadel_project = cfg.organization |> select [ "project" ] (org: name: { hasProjectCheck, privateLabelingSetting, projectRoleAssertion, projectRoleCheck, ... }: - { - inherit name hasProjectCheck privateLabelingSetting projectRoleAssertion projectRoleCheck; - } - |> withRef "org" org - |> toResource "${org}_${name}" + zitadel_project = cfg.organization |> select [ "project" ] (org: name: value: + value + |> getAttrs [ "hasProjectCheck" "privateLabelingSetting" "projectRoleAssertion" "projectRoleCheck" ] + |> withName name + |> withRef "org" org + |> toResource name ); # Each OIDC app per project - zitadel_application_oidc = cfg.organization |> select [ "project" "application" ] (org: project: name: { redirectUris, grantTypes, responseTypes, ...}: - { - inherit name redirectUris grantTypes responseTypes; - - accessTokenRoleAssertion = true; - idTokenRoleAssertion = true; - accessTokenType = "JWT"; - } + zitadel_application_oidc = cfg.organization |> select [ "project" "application" ] (org: project: name: value: + value + |> getAttrs [ "redirectUris" "grantTypes" "responseTypes" ] + |> withName name |> withRef "org" org - |> withRef "project" "${org}_${project}" - |> toResource "${org}_${project}_${name}" - ); - - # Each project role - zitadel_project_role = cfg.organization |> select [ "project" "role" ] (org: project: name: value: - { inherit (value) displayName group; roleKey = name; } - |> withRef "org" org - |> withRef "project" "${org}_${project}" - |> toResource "${org}_${project}_${name}" - ); - - # Each project role assignment - zitadel_user_grant = cfg.organization |> select [ "project" "assign" ] (org: project: user: roles: - { roleKeys = roles; } - |> withRef "org" org - |> withRef "project" "${org}_${project}" - |> withRef "user" "${org}_${user}" - |> toResource "${org}_${project}_${user}" + |> withRef "project" project + |> toResource name ); # Users - zitadel_human_user = cfg.organization |> select [ "user" ] (org: name: { email, userName, firstName, lastName, ... }: - { - inherit email userName firstName lastName; - - isEmailVerified = true; - } + zitadel_human_user = cfg.organization |> select [ "user" ] (org: name: value: + value + |> getAttrs [ "email" "userName" "firstName" "lastName" ] |> withRef "org" org - |> toResource "${org}_${name}" + |> withDefaults { isEmailVerified = true; } + |> toResource name ); # Global user roles zitadel_instance_member = cfg.organization |> select [ "user" ] (org: name: value: { roles = value.instanceRoles; } - |> withRef "user" "${org}_${name}" - |> toResource "${org}_${name}" + |> withRef "user" name + |> toResource name ); # Organazation specific roles - zitadel_org_member = cfg.organization |> select [ "user" ] (org: name: { roles, ... }: - { inherit roles; } + zitadel_org_member = cfg.organization |> select [ "user" ] (org: name: value: + value + |> getAttrs [ "roles" ] |> withRef "org" org - |> withRef "user" "${org}_${name}" - |> toResource "${org}_${name}" + |> withRef "user" name + |> toResource name ); - # Organazation's actions - zitadel_action = cfg.organization |> select [ "action" ] (org: name: { timeout, allowedToFail, script, ...}: - { - inherit allowedToFail name; - timeout = "${toString timeout}s"; - script = "const ${name} = ${script}"; - } - |> withRef "org" org - |> toResource "${org}_${name}" - ); - - # Organazation's action assignments - zitadel_trigger_actions = cfg.organization - |> concatMapAttrs (org: { triggers, ... }: - triggers - |> imap0 (i: { flowType, triggerType, actions, ... }: (let name = "trigger_${toString i}"; in - { - inherit flowType triggerType; - - actionIds = actions - |> map (action: (lib.tfRef "zitadel_action.${org}_${toSnakeCase action}.id")); - } - |> withRef "org" org - |> toResource "${org}_${name}" - )) - |> listToAttrs - ); - # SMTP config zitadel_smtp_config.default = { sender_address = "chris@kruining.eu"; @@ -444,18 +289,18 @@ in tls = true; host = "black-mail.nl:587"; user = "chris@kruining.eu"; - password = lib.tfRef "file(\"${config'.sops.secrets."zitadel/email".path}\")"; + password = lib.tfRef "file(\"${config'.sops.secrets."email/chris_kruining_eu".path}\")"; set_active = true; }; # Client credentials per app local_sensitive_file = cfg.organization |> select [ "project" "application" ] (org: project: name: value: - nameValuePair "${org}_${project}_${name}" { + nameValuePair name { content = '' - CLIENT_ID=${lib.tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_id"} - CLIENT_SECRET=${lib.tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_secret"} + CLIENT_ID=${lib.tfRef "resource.zitadel_application_oidc.${name}.client_id"} + CLIENT_SECRET=${lib.tfRef "resource.zitadel_application_oidc.${name}.client_secret"} ''; - filename = "/var/lib/zitadel/clients/${org}_${project}_${name}"; + filename = "/var/lib/zitadel/clients/${name}"; } ); }; @@ -490,9 +335,6 @@ in exit 1 fi - # Print the path to the source for easier debugging - echo "config location: ${terraformConfiguration}" - # Copy infra code into workspace cp -f ${terraformConfiguration} config.tf.json @@ -500,7 +342,6 @@ in ${lib.getExe pkgs.opentofu} init # Run the infrastructure code - # ${lib.getExe pkgs.opentofu} plan ${lib.getExe pkgs.opentofu} apply -auto-approve ''; @@ -634,10 +475,9 @@ in restartUnits = [ "zitadel.service" ]; #EMGDB#6O$8qpGoLI1XjhUhnng1san@0 }; - "zitadel/email" = { + "email/chris_kruining_eu" = { owner = "zitadel"; group = "zitadel"; - key = "email/chris_kruining_eu"; restartUnits = [ "zitadel.service" ]; }; }; diff --git a/modules/nixos/services/communication/matrix/default.nix b/modules/nixos/services/communication/matrix/default.nix index 2d9ecd5..38dfe0c 100644 --- a/modules/nixos/services/communication/matrix/default.nix +++ b/modules/nixos/services/communication/matrix/default.nix @@ -29,33 +29,43 @@ in enable = true; extras = [ "oidc" ]; - - extraConfigFiles = [ - config.sops.templates."synapse-oidc.yaml".path - ]; + # plugins = with config.services.matrix-synapse.package.plugins; []; settings = { server_name = domain; public_baseurl = "https://${fqn}"; - enable_metrics = true; - registration_shared_secret = "tZtBnlhEmLbMwF0lQ112VH1Rl5MkZzYH9suI4pEoPXzk6nWUB8FJF4eEnwLkbstz"; url_preview_enabled = true; precence.enabled = true; # Since we'll be using OIDC for auth disable all local options - enable_registration = true; - enable_registration_without_verification = true; + enable_registration = false; password_config.enabled = false; - backchannel_logout_enabled = true; sso = { client_whitelist = [ "http://[::1]:9092" ]; update_profile_information = true; }; + oidc_providers = [ + { + discover = true; + + idp_id = "zitadel"; + idp_name = "Zitadel"; + issuer = "https://auth.kruining.eu"; + client_id = "337858153251143939"; + client_secret = "ePkf5n8BxGD5DF7t1eNThTL0g6PVBO5A1RC0EqPp61S7VsiyXvDs8aJeczrpCpsH"; + scopes = [ "openid" "profile" ]; + # user_mapping_provider.config = { + # localpart_template = "{{ user.prefered_username }}"; + # display_name_template = "{{ user.name }}"; + # }; + } + ]; + database = { # this is postgresql (also the default, but I prefer to be explicit) name = "psycopg2"; @@ -75,7 +85,7 @@ in resources = [ { - names = [ "client" "federation" "openid" "metrics" "media" "health" ]; + names = [ "client" "federation" ]; compress = true; } ]; @@ -165,30 +175,5 @@ in }; }; }; - - sops = { - secrets = { - "synapse/oidc_id" = {}; - "synapse/oidc_secret" = {}; - }; - - templates = { - "synapse-oidc.yaml" = { - owner = "matrix-synapse"; - content = '' - oidc_providers: - - discover: true - idp_id: zitadel - idp_name: Zitadel - issuer: "https://auth.kruining.eu" - scopes: - - openid - - profile - client_id: '${config.sops.placeholder."synapse/oidc_id"}' - client_secret: '${config.sops.placeholder."synapse/oidc_secret"}' - ''; - }; - }; - }; }; } diff --git a/modules/nixos/services/development/forgejo/default.nix b/modules/nixos/services/development/forgejo/default.nix index 39e8215..46e0995 100644 --- a/modules/nixos/services/development/forgejo/default.nix +++ b/modules/nixos/services/development/forgejo/default.nix @@ -1,7 +1,6 @@ { config, lib, pkgs, namespace, ... }: let - inherit (builtins) toString; - inherit (lib) mkIf mkEnableOption mkOption; + inherit (lib) mkIf mkEnableOption; cfg = config.${namespace}.services.development.forgejo; domain = "git.amarth.cloud"; @@ -9,15 +8,6 @@ in { options.${namespace}.services.development.forgejo = { enable = mkEnableOption "Forgejo"; - - port = mkOption { - type = lib.types.port; - default = 5002; - example = "1234"; - description = '' - Which port to bind forgejo to - ''; - }; }; config = mkIf cfg.enable { @@ -43,7 +33,7 @@ in server = { DOMAIN = domain; ROOT_URL = "https://${domain}/"; - HTTP_PORT = cfg.port; + HTTP_PORT = 5002; LANDING_PAGE = "explore"; }; @@ -93,7 +83,7 @@ in openid = { ENABLE_OPENID_SIGNIN = true; ENABLE_OPENID_SIGNUP = true; - WHITELISTED_URIS = "https://auth.kruining.eu"; + WHITELISTED_URIS = "https://auth.amarth.cloud"; }; oauth2_client = { @@ -112,10 +102,6 @@ in SHOW_FOOTER_TEMPLATE_LOAD_TIME = false; }; - metrics = { - ENABLED = true; - }; - api = { ENABLE_SWAGGER = false; }; @@ -134,9 +120,9 @@ in PROTOCOL = "smtp+starttls"; SMTP_ADDR = "black-mail.nl"; SMTP_PORT = 587; - FROM = "chris@kruining.eu"; - USER = "chris@kruining.eu"; - PASSWD_URI = "file:${config.sops.secrets."forgejo/email".path}"; + FROM = "info@amarth.cloud"; + USER = "info@amarth.cloud"; + PASSWD = "__TODO_USE_SOPS__"; }; }; }; @@ -151,8 +137,8 @@ in url = "https://git.amarth.cloud"; # Obtaining the path to the runner token file may differ # tokenFile should be in format TOKEN=, since it's EnvironmentFile for systemd - tokenFile = config.sops.secrets."forgejo/action_runner_token".path; - # token = "ZBetud1F0IQ9VjVFpZ9bu0FXgx9zcsy1x25yvjhw"; + # tokenFile = config.age.secrets.forgejo-runner-token.path; + token = "ZBetud1F0IQ9VjVFpZ9bu0FXgx9zcsy1x25yvjhw"; labels = [ "default:docker://nixos/nix:latest" "ubuntu:docker://ubuntu:24-bookworm" @@ -167,32 +153,17 @@ in caddy = { enable = true; virtualHosts = { - "${domain}".extraConfig = '' - # import auth + ${domain}.extraConfig = '' + # import auth-z # stupid dumb way to prevent the login page and go to zitadel instead # be aware that this does not disable local login at all! # rewrite /user/login /user/oauth2/Zitadel - reverse_proxy http://127.0.0.1:${toString cfg.port} + reverse_proxy http://127.0.0.1:5002 ''; }; }; }; - - sops.secrets = { - "forgejo/action_runner_token" = { - owner = "gitea-runner"; - group = "gitea-runner"; - restartUnits = [ "gitea-runner-default.service" ]; - }; - - "forgejo/email" = { - owner = "forgejo"; - group = "forgejo"; - key = "email/chris_kruining_eu"; - restartUnits = [ "forgejo.service" ]; - }; - }; }; } diff --git a/systems/x86_64-linux/ulmo/default.nix b/systems/x86_64-linux/ulmo/default.nix index 0c8a67b..e776927 100644 --- a/systems/x86_64-linux/ulmo/default.nix +++ b/systems/x86_64-linux/ulmo/default.nix @@ -57,23 +57,6 @@ project = { ulmo = { - projectRoleCheck = true; - projectRoleAssertion = true; - hasProjectCheck = true; - - role = { - jellyfin = { - group = "jellyfin"; - }; - jellyfin_admin = { - group = "jellyfin"; - }; - }; - - assign = { - chris = [ "jellyfin" "jellyfin_admin" ]; - }; - application = { jellyfin = { redirectUris = [ "https://jellyfin.kruining.eu/sso/OID/redirect/zitadel" ]; @@ -95,27 +78,6 @@ }; }; }; - - action = { - flattenRoles = { - script = '' - (ctx, api) => { - if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) { - return; - } - - const roles = ctx.v1.user.grants.grants.flatMap(({ roles, projectId }) => roles.map(role => projectId + ':' + role)); - - api.v1.claims.setClaim('nix:zitadel:custom', JSON.stringify({ roles })); - }; - ''; - }; - }; - - triggers = [ - { flowType = "customiseToken"; triggerType = "preUserinfoCreation"; actions = [ "flattenRoles" ]; } - { flowType = "customiseToken"; triggerType = "preAccessTokenCreation"; actions = [ "flattenRoles" ]; } - ]; }; }; }; diff --git a/systems/x86_64-linux/ulmo/secrets.yml b/systems/x86_64-linux/ulmo/secrets.yml index 250b1af..f9e4a82 100644 --- a/systems/x86_64-linux/ulmo/secrets.yml +++ b/systems/x86_64-linux/ulmo/secrets.yml @@ -3,11 +3,6 @@ email: info_amarth_cloud: ENC[AES256_GCM,data:/x7aAFAxXYYf79tB08VQmmuTIy2TvdSTFfAzIWdIr+I=,iv:plNxS6oOin+oEql+1xsePOsUfLJkf+ZPBviPRTbIghE=,tag:hjtK3rysd2NNBA2mWdv8cw==,type:str] zitadel: masterKey: ENC[AES256_GCM,data:4MPvBo407qrS7NF4oUTf84tZoPkSRmiHdD7qpkYeHME=,iv:H2NIAN0xBUDqnyco9gA3zYAsKtSeA/JpqYrPhc1eqc0=,tag:6OFGDfsucG5gDerImgpuXA==,type:str] -forgejo: - action_runner_token: ENC[AES256_GCM,data:yJ6OnRq5kinbuhvH06K5o3l86EafuBoojMwg/qhP+cgeH+BwPeE+Ng==,iv:IeXJahPxgLNIUFmkgp495tLVh8UyQBmJ2SnVEUhlhHs=,tag:XYQi613CxSp8AQeilJMrsg==,type:str] -synapse: - oidc_id: ENC[AES256_GCM,data:GPc4XBmIqWKbisN8patC0MNR,iv:wKCZ7PWn1WZOboc9I3JQXaxn4NiqMckCgC4d001F7jk=,tag:CBKcW4luhrJ+BOGH+UBmog==,type:str] - oidc_secret: ENC[AES256_GCM,data:3Z8XwAPBHUG7Z09uTkd0ZH80lRVPF2a8tt0cFvrFA9s5R6G2ULkbHZM5V2VZBZ7FNhv7JINilGdRaibvF3U3Tg==,iv:U5Z3VcuWxwX5kNTvmG7YFiPJSl8Xg2nRDPdz0tekric=,tag:o2s67WjB7mXJlyo8jlcUzw==,type:str] sops: age: - recipient: age19qfpf980tadguqq44zf6xwvjvl428dyrj46ha3n6aeqddwhtnuqqml7etq @@ -28,7 +23,7 @@ sops: TTRWaHhpNWlkVDFmMFN4ZTNHMUxyNVkKV693pzTKRkZboQCMPr9IyMGSgxfuHXcb Y6BNcp6Qg6PWtX5QI7wRkPNINAK1TEbRBba+b8h6gMmVU4DliQyFiQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-10-30T20:58:01Z" - mac: ENC[AES256_GCM,data:7vQ5wV58UNUH5bOgyUxaifAbU3GTqZi2gH+rpAR+d/31rx8yeKVNMj0aWA5ianpUvVt2kbaap6Aj+Sxl3M8wI9jtg2o/3FmR+xEHEWgQ/jw1q9zvKIAUV6SeM1Hg639iV3xcC8F8U+Xy50H85f4B3XQWGJMnUamqH9LYrUjv8nY=,iv:vOGvilRSrPZW3uir1nwlxzhg+hXE5yw6r8vCr5Cxmt0=,tag:X9OYdCPuDz3o5kYLUKHmXg==,type:str] + lastmodified: "2025-10-27T13:11:41Z" + mac: ENC[AES256_GCM,data:0LS7xQlkfIZRVwAZPE33KmPA19CpnXj/t4hpDrVW+BbESpnBku2oxPB/Cvp0dY5MGnDFgU4Htp0JoppHCgKvkaSBhvjxjW2DT1Nkk5PBmAtuzZLW4qc25ZVlqiKgzj1LE3XPTbqUJyp+X3U23BnU1ViTGgHuBcdEV7TFNHjmnwk=,iv:HpVIDAU1FbrUKXW8klWq0Kn9ZtKcgwR1jKXLkGtDd5A=,tag:50P0UZtj77npD92zxCaZHw==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0