diff --git a/sp-modules/roundcube/config-paths-needed.json b/sp-modules/roundcube/config-paths-needed.json index aff2a53..a759840 100644 --- a/sp-modules/roundcube/config-paths-needed.json +++ b/sp-modules/roundcube/config-paths-needed.json @@ -7,5 +7,7 @@ [ "passthru", "selfprivacy", "auth", "oauth2-systemd-service" ], [ "selfprivacy", "domain" ], [ "selfprivacy", "modules", "auth" ], - [ "selfprivacy", "modules", "roundcube" ] + [ "selfprivacy", "modules", "roundcube" ], + [ "selfprivacy", "passthru", "mailserver", "oauth-client-id" ], + [ "selfprivacy", "passthru", "mailserver", "oauth-client-secret-fp" ] ] diff --git a/sp-modules/roundcube/module.nix b/sp-modules/roundcube/module.nix index b5d6ddf..f01831d 100644 --- a/sp-modules/roundcube/module.nix +++ b/sp-modules/roundcube/module.nix @@ -5,24 +5,21 @@ let is-auth-enabled = config.selfprivacy.modules.auth.enable or false; auth-passthru = config.passthru.selfprivacy.auth; auth-fqdn = auth-passthru.auth-fqdn; - oauth-client-id = "roundcube"; - roundcube-user = "roundcube"; - roundcube-group = "roundcube"; - kanidmExecStartPreScriptRoot = pkgs.writeShellScript - "${oauth-client-id}-kanidm-ExecStartPre-root-script.sh" - '' - # set-group-ID bit allows for kanidm user to create files, - mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/${oauth-client-id} - chown kanidm:${roundcube-group} /run/keys/${oauth-client-id} - ''; + sp-module-name = "roundcube"; + user = "roundcube"; + group = "roundcube"; + oauth-donor = config.selfprivacy.passthru.mailserver; kanidm-oauth-client-secret-fp = - "/run/keys/${oauth-client-id}/kanidm-oauth-client-secret"; - kanidmExecStartPreScript = pkgs.writeShellScript - "${oauth-client-id}-kanidm-ExecStartPre-script.sh" '' - set -o xtrace - [ -f "${kanidm-oauth-client-secret-fp}" ] || \ - "${lib.getExe pkgs.openssl}" rand -base64 -out "${kanidm-oauth-client-secret-fp}" 32 - ''; + "/run/keys/${group}/kanidm-oauth-client-secret"; + kanidmExecStartPreScriptRoot = pkgs.writeShellScript + "${sp-module-name}-kanidm-ExecStartPre-root-script.sh" + '' + # set-group-ID bit allows for kanidm user to create files inheriting group + mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/${group} + chown kanidm:${group} /run/keys/${group} + + install -v -m640 -o kanidm -g ${group} ${oauth-donor.oauth-client-secret-fp} ${kanidm-oauth-client-secret-fp} + ''; in { options.selfprivacy.modules.roundcube = { @@ -72,21 +69,23 @@ in }; systemd.slices.roundcube.description = "Roundcube service slice"; + # Roundcube depends on Dovecot and its OAuth2 client secret. + systemd.services.roundcube.after = [ "dovecot2.service" ]; } # the following part is active only when "auth" module is enabled (lib.attrsets.optionalAttrs (options.selfprivacy.modules ? "auth") (lib.mkIf is-auth-enabled { # for phpfpm-roundcube to have access to get through /run/keys directory - users.groups.keys.members = [ roundcube-user ]; + users.groups.keys.members = [ user ]; services.roundcube.extraConfig = lib.mkAfter '' $config['oauth_provider'] = 'generic'; $config['oauth_provider_name'] = '${auth-passthru.oauth2-provider-name}'; - $config['oauth_client_id'] = '${oauth-client-id}'; + $config['oauth_client_id'] = '${oauth-donor.oauth-client-id}'; $config['oauth_client_secret'] = file_get_contents('${kanidm-oauth-client-secret-fp}'); $config['oauth_auth_uri'] = 'https://${auth-fqdn}/ui/oauth2'; $config['oauth_token_uri'] = 'https://${auth-fqdn}/oauth2/token'; - $config['oauth_identity_uri'] = 'https://${auth-fqdn}/oauth2/openid/${oauth-client-id}/userinfo'; + $config['oauth_identity_uri'] = 'https://${auth-fqdn}/oauth2/openid/${oauth-donor.oauth-client-id}/userinfo'; $config['oauth_scope'] = 'email profile openid'; # FIXME $config['oauth_auth_parameters'] = []; $config['oauth_identity_fields'] = ['email']; @@ -96,11 +95,9 @@ in # $config['oauth_pkce'] = 'S256'; # FIXME ''; systemd.services.kanidm = { - serviceConfig.ExecStartPre = lib.mkAfter [ + serviceConfig.ExecStartPre = lib.mkBefore [ ("-+" + kanidmExecStartPreScriptRoot) - ("-" + kanidmExecStartPreScript) ]; - requires = [ auth-passthru.oauth2-systemd-service ]; }; services.kanidm.provision = { groups = { @@ -108,7 +105,7 @@ in "sp.roundcube.users".members = [ "sp.roundcube.admins" auth-passthru.full-users-group ]; }; - systems.oauth2.roundcube = { + systems.oauth2.${oauth-donor.oauth-client-id} = { displayName = "Roundcube"; originUrl = "https://${cfg.subdomain}.${domain}/index.php/login/oauth"; originLanding = "https://${cfg.subdomain}.${domain}/"; diff --git a/sp-modules/simple-nixos-mailserver/auth-dovecot.nix b/sp-modules/simple-nixos-mailserver/auth-dovecot.nix index 10dbb3d..4a2615b 100644 --- a/sp-modules/simple-nixos-mailserver/auth-dovecot.nix +++ b/sp-modules/simple-nixos-mailserver/auth-dovecot.nix @@ -1,14 +1,15 @@ { config, lib, pkgs, ... }@nixos-args: let inherit (import ./common.nix nixos-args) - appendLdapBindPwd + appendSetting auth-passthru cfg domain + group is-auth-enabled ; - runtime-directory = "dovecot2"; + runtime-directory = group; ldapConfFile = "/run/${runtime-directory}/dovecot-ldap.conf.ext"; mkLdapSearchScope = scope: ( @@ -37,7 +38,7 @@ let user_filter = ${config.mailserver.ldap.dovecot.userFilter} ''; }; - setPwdInLdapConfFile = appendLdapBindPwd { + setPwdInLdapConfFile = appendSetting { name = "ldap-conf-file"; file = dovecot-ldap-config; prefix = ''dnpass = "''; @@ -45,24 +46,39 @@ let passwordFile = config.mailserver.ldap.bind.passwordFile; destination = ldapConfFile; }; - dovecot-oauth2-conf-file = pkgs.writeTextFile { - name = "dovecot-oauth2.conf.ext"; - text = '' + oauth-client-id = "mailserver"; + oauth-client-secret-fp = + "/run/keys/${group}/kanidm-oauth-client-secret"; + oauth-secret-ExecStartPreScript = pkgs.writeShellScript + "${oauth-client-id}-kanidm-ExecStartPre-script.sh" '' + set -o xtrace + [ -f "${oauth-client-secret-fp}" ] || \ + "${lib.getExe pkgs.openssl}" rand -base64 32 | tr -d "\n" > "${oauth-client-secret-fp}" + ''; + dovecot-oauth2-conf-fp = "/run/${runtime-directory}/dovecot-oauth2.conf.ext"; + write-dovecot-oauth2-conf = appendSetting { + name = "oauth2-conf-file"; + file = builtins.toFile "dovecot-oauth2.conf.ext.template" '' introspection_mode = post - introspection_url = ${auth-passthru.oauth2-introspection-url "roundcube" "VERYSTRONGSECRETFORROUNDCUBE"} - client_id = roundcube - client_secret = VERYSTRONGSECRETFORROUNDCUBE # FIXME username_attribute = username scope = email profile openid tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt active_attribute = active active_value = true - openid_configuration_url = ${auth-passthru.oauth2-discovery-url "roundcube"} + openid_configuration_url = ${auth-passthru.oauth2-discovery-url oauth-client-id} debug = "no" ''; + prefix = ''introspection_url = "'' + + (auth-passthru.oauth2-introspection-url-prefix oauth-client-id); + suffix = auth-passthru.oauth2-introspection-url-postfix + ''"''; + passwordFile = oauth-client-secret-fp; + destination = dovecot-oauth2-conf-fp; }; in { + # for dovecot2 to have access to get through /run/keys directory + users.groups.keys.members = [ group ]; + mailserver.ldap = { # note: in `ldapsearch` first comes filter, then attributes dovecot.userAttrs = "+"; # all operational attributes @@ -76,7 +92,7 @@ in passdb { driver = oauth2 mechanisms = xoauth2 oauthbearer - args = ${dovecot-oauth2-conf-file} + args = ${dovecot-oauth2-conf-fp} } userdb { @@ -114,13 +130,22 @@ in services.dovecot2.enablePAM = false; systemd.services.dovecot2 = { # TODO does it merge with existing preStart? - preStart = setPwdInLdapConfFile + "\n"; + preStart = setPwdInLdapConfFile + "\n" + write-dovecot-oauth2-conf + "\n"; # FIXME pass dependant services to auth module option instead? wants = [ auth-passthru.oauth2-systemd-service ]; after = [ auth-passthru.oauth2-systemd-service ]; serviceConfig.RuntimeDirectory = lib.mkForce [ runtime-directory ]; }; + systemd.services.kanidm.serviceConfig.ExecStartPre = lib.mkAfter [ + ("-" + oauth-secret-ExecStartPreScript) + ]; # does it merge with existing restartTriggers? - systemd.services.postfix.restartTriggers = [ setPwdInLdapConfFile ]; + systemd.services.postfix.restartTriggers = [ + setPwdInLdapConfFile + write-dovecot-oauth2-conf + ]; + selfprivacy.passthru.mailserver = { + inherit oauth-client-id oauth-client-secret-fp; + }; } diff --git a/sp-modules/simple-nixos-mailserver/auth-postfix.nix b/sp-modules/simple-nixos-mailserver/auth-postfix.nix index 38b141c..1d1029e 100644 --- a/sp-modules/simple-nixos-mailserver/auth-postfix.nix +++ b/sp-modules/simple-nixos-mailserver/auth-postfix.nix @@ -1,7 +1,7 @@ { config, lib, pkgs, ... }@nixos-args: let inherit (import ./common.nix nixos-args) - appendLdapBindPwd + appendSetting auth-passthru is-auth-enabled ; @@ -29,7 +29,7 @@ let query_filter = ${cfg.ldap.postfix.filter} result_attribute = ${cfg.ldap.postfix.mailAttribute} ''; - appendPwdInSenderLoginMap = appendLdapBindPwd { + appendPwdInSenderLoginMap = appendSetting { name = "ldap-sender-login-map"; file = ldapSenderLoginMap; prefix = "bind_pw = "; @@ -43,7 +43,7 @@ let result_attribute = ${cfg.ldap.postfix.uidAttribute} ''; ldapVirtualMailboxMapFile = "/run/postfix/ldap-virtual-mailbox-map.cf"; - appendPwdInVirtualMailboxMap = appendLdapBindPwd { + appendPwdInVirtualMailboxMap = appendSetting { name = "ldap-virtual-mailbox-map"; file = ldapVirtualMailboxMap; prefix = "bind_pw = "; diff --git a/sp-modules/simple-nixos-mailserver/common.nix b/sp-modules/simple-nixos-mailserver/common.nix index eba175b..17ce303 100644 --- a/sp-modules/simple-nixos-mailserver/common.nix +++ b/sp-modules/simple-nixos-mailserver/common.nix @@ -3,8 +3,9 @@ rec { auth-passthru = config.passthru.selfprivacy.auth; domain = config.selfprivacy.domain; is-auth-enabled = config.selfprivacy.modules.auth.enable or false; + group = "dovecot2"; - appendLdapBindPwd = + appendSetting = { name, file, prefix, suffix ? "", passwordFile, destination }: pkgs.writeScript "append-ldap-bind-pwd-in-${name}" '' #!${pkgs.stdenv.shell} diff --git a/sp-modules/simple-nixos-mailserver/config-paths-needed.json b/sp-modules/simple-nixos-mailserver/config-paths-needed.json index 3e0ce04..bb0c127 100644 --- a/sp-modules/simple-nixos-mailserver/config-paths-needed.json +++ b/sp-modules/simple-nixos-mailserver/config-paths-needed.json @@ -1,10 +1,15 @@ [ [ "mailserver" ], + [ "passthru", "selfprivacy", "auth", "admins-group" ], + [ "passthru", "selfprivacy", "auth", "full-users-group" ], [ "passthru", "selfprivacy", "auth", "ldap-base-dn" ], [ "passthru", "selfprivacy", "auth", "ldap-port" ], [ "passthru", "selfprivacy", "auth", "oauth2-discovery-url" ], - [ "passthru", "selfprivacy", "auth", "oauth2-introspection-url" ], + [ "passthru", "selfprivacy", "auth", "oauth2-introspection-url-postfix" ], + [ "passthru", "selfprivacy", "auth", "oauth2-introspection-url-prefix" ], [ "passthru", "selfprivacy", "auth", "oauth2-systemd-service" ], + [ "passthru", "selfprivacy", "roundcube", "oauth-client-id" ], + [ "passthru", "selfprivacy", "roundcube", "oauth-client-secret-fp" ], [ "security", "acme", "certs" ], [ "selfprivacy", "domain" ], [ "selfprivacy", "hashedMasterPassword" ], diff --git a/sp-modules/simple-nixos-mailserver/config.nix b/sp-modules/simple-nixos-mailserver/config.nix index 6868666..68cd44c 100644 --- a/sp-modules/simple-nixos-mailserver/config.nix +++ b/sp-modules/simple-nixos-mailserver/config.nix @@ -5,20 +5,22 @@ let inherit (import ./common.nix { inherit config pkgs; }) auth-passthru domain + group is-auth-enabled ; mailserver-service-account-name = "sp.mailserver.service-account"; mailserver-service-account-token-name = "mailserver-service-account-token"; mailserver-service-account-token-fp = - "/run/keys/mailserver/kanidm-service-account-token"; # FIXME sync with auth module - kanidmExecStartPostScriptRoot = pkgs.writeShellScript - "mailserver-kanidm-ExecStartPost-root-script.sh" + "/run/keys/${group}/kanidm-service-account-token"; # FIXME sync with auth module + kanidmExecStartPreScriptRoot = pkgs.writeShellScript + "mailserver-kanidm-ExecStartPre-root-script.sh" '' - # set-group-ID bit allows for kanidm user to create files, - mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/mailserver - chown kanidm:kanidm /run/keys/mailserver + # set-group-ID bit allows for kanidm user to create files inheriting group + mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/${group} + chown kanidm:${group} /run/keys/${group} ''; + # create service account token, needed for LDAP kanidmExecStartPostScript = pkgs.writeShellScript "mailserver-kanidm-ExecStartPost-script.sh" '' @@ -173,7 +175,7 @@ lib.mkIf sp.modules.simple-nixos-mailserver.enable (lib.mkMerge [ }; }; } - # the following part is active only when "auth" module is enabled + # the following parts are active only when "auth" module is enabled (lib.attrsets.optionalAttrs (options.selfprivacy.modules ? "auth") (lib.mkIf is-auth-enabled { @@ -199,9 +201,11 @@ lib.mkIf sp.modules.simple-nixos-mailserver.enable (lib.mkMerge [ }; }; # FIXME set auth module option instead + systemd.services.kanidm.serviceConfig.ExecStartPre = lib.mkBefore [ + ("-+" + kanidmExecStartPreScriptRoot) + ]; systemd.services.kanidm.serviceConfig.ExecStartPost = lib.mkAfter [ - ("+" + kanidmExecStartPostScriptRoot) - kanidmExecStartPostScript + ("-" + kanidmExecStartPostScript) ]; })) (lib.attrsets.optionalAttrs