blob: d20981365abfbc2f2c1e387291e83c2596acf273 [file] [log] [blame]
Skyler Grey87a11552023-06-14 23:02:25 +02001{ base, pkgs, drive_paths, lib, config, ... }: {
TheCodedProfb6184602023-06-13 17:04:59 -04002 environment.systemPackages = with pkgs; [ vaultwarden ];
TheCodedProfaec8c452023-06-12 18:26:46 -04003
TheCodedProfb6184602023-06-13 17:04:59 -04004 services.vaultwarden.enable = true;
5 services.vaultwarden.dbBackend = "postgresql";
TheCodedProfaec8c452023-06-12 18:26:46 -04006
Skyler Grey87a11552023-06-14 23:02:25 +02007 sops.secrets = lib.pipe [ "ADMIN_TOKEN" "SMTP_PASSWORD" "YUBICO_SECRET_KEY" "HIBP_API_KEY" ] [
8 (map (name: {
TheCodedProfb6184602023-06-13 17:04:59 -04009 inherit name; value = {
10 mode = "0400";
11 owner = config.users.users.root.name;
12 group = config.users.users.nobody.group;
13 sopsFile = ../secrets/vaultwarden.json;
14 format = "json";
15 };
Skyler Grey87a11552023-06-14 23:02:25 +020016 }))
TheCodedProfb6184602023-06-13 17:04:59 -040017 builtins.listToAttrs
18 ];
19} // (
20 let
21 isDerived = base != null;
22 in
23 if isDerived
24 # We cannot use mkIf as both sides are evaluated no matter the condition value
25 # Given we use base as an attrset, mkIf will error if base is null in here
26 then
27 with lib;
28 let
29 cfg = services.vaultwarden;
30
31 vaultwarden_config = {
TheCodedProfaec8c452023-06-12 18:26:46 -040032 # Server Settings
33 DOMAIN = "https://passwords.clicks.codes";
34 ROCKET_ADDRESS = "127.0.0.1";
35 ROCKET_PORT = 8452;
36
37
38 # General Settings
TheCodedProfb6184602023-06-13 17:04:59 -040039 SIGNUPS_ALLOWED = false;
40 INVITATIONS_ALLOWED = true;
41 SIGNUPS_DOMAINS_WHITELIST = "clicks.codes,coded.codes,thecoded.prof,starrysky.fyi,hopescaramels.com,pinea.dev";
TheCodedProfaec8c452023-06-12 18:26:46 -040042
Skyler Grey87a11552023-06-14 23:02:25 +020043 RSA_KEY_FILENAME = "${drive_paths.External1000SSD}/bitwarden/rsa_key";
44 ICON_CACHE_FOLDER = "${drive_paths.External1000SSD}/bitwarden/icon_cache";
TheCodedProfb6184602023-06-13 17:04:59 -040045 ATTACHMENTS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/attachments";
46 SENDS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/sends";
47 TMP_FOLDER = "${drive_paths.External4000HDD}/bitwarden/tmp";
TheCodedProfaec8c452023-06-12 18:26:46 -040048
TheCodedProfb6184602023-06-13 17:04:59 -040049 DISABLE_2FA_REMEMBER = true;
TheCodedProfaec8c452023-06-12 18:26:46 -040050
51 # Admin Account
TheCodedProfb6184602023-06-13 17:04:59 -040052 ADMIN_TOKEN = "!!ADMIN_TOKEN!!";
TheCodedProfaec8c452023-06-12 18:26:46 -040053
54
55 # Database Settings
TheCodedProfb6184602023-06-13 17:04:59 -040056 DATABASE_URL = "postgresql://vaultwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${config.services.postgresql.port}/vaultwarden";
TheCodedProfaec8c452023-06-12 18:26:46 -040057
58
59 # Mail Settings
60 SMTP_HOST = "127.0.0.1";
61 SMTP_FROM = "bitwarden@clicks.codes";
62 SMTP_FROM_NAME = "Clicks Bitwarden";
63 SMTP_SECURITY = "starttls";
64 SMTP_PORT = 587;
65
TheCodedProfbdc23452023-06-14 13:39:10 -040066 SMTP_USERNAME = "FILL_ME_IN";
67 SMTP_PASSWORD = "!!SMTP_PASSWORD!!";
TheCodedProfaec8c452023-06-12 18:26:46 -040068
TheCodedProfbdc23452023-06-14 13:39:10 -040069 REQUIRE_DEVICE_EMAIL = true;
TheCodedProfaec8c452023-06-12 18:26:46 -040070
71
72 # YubiKey Settings
TheCodedProfbdc23452023-06-14 13:39:10 -040073 YUBICO_CLIENT_ID = "89788";
74 YUBICO_SECRET_KEY = "!!YUBICO_SECRET_KEY!!";
TheCodedProfaec8c452023-06-12 18:26:46 -040075
76
77 # TODO: Buy a license
78 # HIBP Settings
TheCodedProfd23784c2023-06-13 14:28:23 -040079 # HIBP_API_KEY="!!HIBP_API_KEY!!";
TheCodedProfb6184602023-06-13 17:04:59 -040080 };
81
82 nameToEnvVar = name:
83 let
84 parts = builtins.split "([A-Z0-9]+)" name;
85 partsToEnvVar = parts: foldl'
86 (key: x:
87 let last = stringLength key - 1; in
88 if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x
89 else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ]
90 substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x
91 else key + toUpper x) ""
92 parts;
93 in
94 if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts;
95
96 # Due to the different naming schemes allowed for config keys,
97 # we can only check for values consistently after converting them to their corresponding environment variable name.
98 configEnv =
99 let
100 configEnv = concatMapAttrs
101 (name: value: optionalAttrs (value != null) {
102 ${nameToEnvVar name} = if isBool value then boolToString value else toString value;
103 })
104 vaultwarden_config;
105 in
106 { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") {
107 WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault";
TheCodedProfbdc23452023-06-14 13:39:10 -0400108 } // configEnv;
TheCodedProfb6184602023-06-13 17:04:59 -0400109
110 configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
111 in
112 {
113 scalpel.trafos."vaultwarden.env" = {
114 source = toString configFile;
115 matchers."ADMIN_TOKEN".secret =
116 config.sops.secrets.ADMIN_TOKEN.path;
117 matchers."SMTP_PASSWORD".secret =
118 config.sops.secrets.SMTP_PASSWORD.path;
119 matchers."YUBICO_SECRET_KEY".secret =
120 config.sops.secrets.YUBICO_SECRET_KEY.path;
121 matchers."HIBP_API_KEY".secret =
122 config.sops.secrets.HIBP_API_KEY.path;
123 matchers."clicks_bitwarden_db_secret".secret =
124 config.sops.secrets.clicks_bitwarden_db_password.path;
125 owner = config.users.users.vaultwarden.name;
126 group = config.users.groups.vaultwarden.name;
127 mode = "0400";
128 };
129
130 services.vaultwarden.environmentFile = config.scalpel.trafos."vaultwarden.env".destination;
131 } else { }
132)