forked from
lass.pds.lassul.us/superconfig
This repository has no description
3.4 kB
95 lines
1{ config, ... }:
2let
3 domain = "mail.lassul.us";
4 zitadelEnv = config.lass.zitadel.projects.mail.apps.roundcube.envFile.path;
5 # Basic-auth introspection URL with the roundcube client's id and secret,
6 # read by dovecot at config parse time.
7 introspectionUrl = "/var/lib/dovecot-oauth2/introspection-url";
8in
9{
10 # Webmail on mail.lassul.us. Login only via Zitadel (id.lassul.us); roundcube
11 # hands the access token to dovecot (IMAP, ManageSieve) and postfix (SMTP via
12 # dovecot SASL) with OAUTHBEARER/XOAUTH2, so no mail password is stored.
13 services.roundcube = {
14 enable = true;
15 hostName = domain;
16 maxAttachmentSize = 25;
17 plugins = [
18 "archive"
19 "managesieve"
20 "zipdownload"
21 ];
22 extraConfig = ''
23 $config['product_name'] = 'lassulus webmail';
24 $config['default_list_mode'] = 'threads';
25 $config['imap_host'] = 'ssl://${domain}:993';
26 $config['smtp_host'] = 'ssl://${domain}:465';
27 $config['managesieve_host'] = 'tls://${domain}:4190';
28
29 $oidc = parse_ini_file('${zitadelEnv}', false, INI_SCANNER_RAW);
30 $config['oauth_provider'] = 'generic';
31 $config['oauth_provider_name'] = 'lassul.us ID';
32 $config['oauth_client_id'] = $oidc['CLIENT_ID'];
33 $config['oauth_client_secret'] = $oidc['CLIENT_SECRET'];
34 $config['oauth_config_uri'] = 'https://id.lassul.us/.well-known/openid-configuration';
35 $config['oauth_scope'] = 'openid email profile offline_access';
36 $config['oauth_identity_fields'] = ['email'];
37 $config['oauth_login_redirect'] = true;
38 '';
39 };
40
41 services.nginx.virtualHosts.${domain} = {
42 enableACME = false;
43 useACMEHost = domain;
44 };
45
46 # Only lass may log in; dovecot maps the token's email to the mailbox.
47 lass.zitadel.projects.mail = {
48 access = "declarative";
49 users = [ "lass@lassul.us" ];
50 apps.roundcube = {
51 redirectUris = [ "https://${domain}/index.php/login/oauth" ];
52 # roundcube sends the client secret in the token request body
53 authMethod = "post";
54 refreshTokens = true;
55 envFile.owner = "roundcube";
56 };
57 };
58
59 # Dovecot checks tokens at Zitadel's introspection endpoint as the roundcube
60 # client. Zitadel reports a token as active only if its audience contains
61 # this project, so tokens issued to other lassul.us ID apps are refused.
62 services.dovecot2.settings = {
63 auth_mechanisms = [
64 "oauthbearer"
65 "xoauth2"
66 ];
67 oauth2_introspection_mode = "post";
68 oauth2_introspection_url = "<${introspectionUrl}";
69 oauth2_force_introspection = true;
70 oauth2_active_attribute = "active";
71 oauth2_active_value = "true";
72 oauth2_username_attribute = "email";
73 oauth2.ssl_client_ca_file = "/etc/ssl/certs/ca-certificates.crt";
74 };
75
76 systemd.services.dovecot-oauth2-url = {
77 wants = [ "zitadel-reconcile.service" ];
78 after = [ "zitadel-reconcile.service" ];
79 before = [ "dovecot.service" ];
80 wantedBy = [ "dovecot.service" ];
81 serviceConfig = {
82 Type = "oneshot";
83 RemainAfterExit = true;
84 StateDirectory = "dovecot-oauth2";
85 StateDirectoryMode = "0700";
86 UMask = "0077";
87 EnvironmentFile = zitadelEnv;
88 };
89 script = ''
90 printf '%s' "https://$CLIENT_ID:$CLIENT_SECRET@id.lassul.us/oauth/v2/introspect" \
91 > ${introspectionUrl}.tmp
92 mv ${introspectionUrl}.tmp ${introspectionUrl}
93 '';
94 };
95}