blob: 091ef503901a3d5cbf586423658f5f7a7c66677f [file] [log] [blame]
TheCodedProfb6184602023-06-13 17:04:59 -04001{ pkgs, drive_paths, lib, config, ... }: {
2 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
TheCodedProfb6184602023-06-13 17:04:59 -04007 sops.secrets = lib.pipe [ "ADMIN_TOKEN", "SMTP_PASSWORD", "YUBICO_SECRET_KEY", "HIBP_API_KEY" ] [
8 (name: {
9 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 };
16 })
17 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
43 # TODO: Set folder locations for storing data.
TheCodedProfb6184602023-06-13 17:04:59 -040044 RSA_KEY_FILENAME = "${drive_paths.root}/bitwarden/rsa_key";
45 ICON_CACHE_FOLDER = "${drive_paths.root}/bitwarden/icon_cache";
46 ATTACHMENTS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/attachments";
47 SENDS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/sends";
48 TMP_FOLDER = "${drive_paths.External4000HDD}/bitwarden/tmp";
TheCodedProfaec8c452023-06-12 18:26:46 -040049
TheCodedProfb6184602023-06-13 17:04:59 -040050 DISABLE_2FA_REMEMBER = true;
TheCodedProfaec8c452023-06-12 18:26:46 -040051
52 # Admin Account
TheCodedProfb6184602023-06-13 17:04:59 -040053 ADMIN_TOKEN = "!!ADMIN_TOKEN!!";
TheCodedProfaec8c452023-06-12 18:26:46 -040054
55
56 # Database Settings
TheCodedProfb6184602023-06-13 17:04:59 -040057 DATABASE_URL = "postgresql://vaultwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${config.services.postgresql.port}/vaultwarden";
TheCodedProfaec8c452023-06-12 18:26:46 -040058
59
60 # Mail Settings
61 SMTP_HOST = "127.0.0.1";
62 SMTP_FROM = "bitwarden@clicks.codes";
63 SMTP_FROM_NAME = "Clicks Bitwarden";
64 SMTP_SECURITY = "starttls";
65 SMTP_PORT = 587;
66
TheCodedProfbdc23452023-06-14 13:39:10 -040067 SMTP_USERNAME = "FILL_ME_IN";
68 SMTP_PASSWORD = "!!SMTP_PASSWORD!!";
TheCodedProfaec8c452023-06-12 18:26:46 -040069
TheCodedProfbdc23452023-06-14 13:39:10 -040070 REQUIRE_DEVICE_EMAIL = true;
TheCodedProfaec8c452023-06-12 18:26:46 -040071
72
73 # YubiKey Settings
TheCodedProfbdc23452023-06-14 13:39:10 -040074 YUBICO_CLIENT_ID = "89788";
75 YUBICO_SECRET_KEY = "!!YUBICO_SECRET_KEY!!";
TheCodedProfaec8c452023-06-12 18:26:46 -040076
77
78 # TODO: Buy a license
79 # HIBP Settings
TheCodedProfd23784c2023-06-13 14:28:23 -040080 # HIBP_API_KEY="!!HIBP_API_KEY!!";
TheCodedProfb6184602023-06-13 17:04:59 -040081 };
82
83 nameToEnvVar = name:
84 let
85 parts = builtins.split "([A-Z0-9]+)" name;
86 partsToEnvVar = parts: foldl'
87 (key: x:
88 let last = stringLength key - 1; in
89 if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x
90 else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ]
91 substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x
92 else key + toUpper x) ""
93 parts;
94 in
95 if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts;
96
97 # Due to the different naming schemes allowed for config keys,
98 # we can only check for values consistently after converting them to their corresponding environment variable name.
99 configEnv =
100 let
101 configEnv = concatMapAttrs
102 (name: value: optionalAttrs (value != null) {
103 ${nameToEnvVar name} = if isBool value then boolToString value else toString value;
104 })
105 vaultwarden_config;
106 in
107 { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") {
108 WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault";
TheCodedProfbdc23452023-06-14 13:39:10 -0400109 } // configEnv;
TheCodedProfb6184602023-06-13 17:04:59 -0400110
111 configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
112 in
113 {
114 scalpel.trafos."vaultwarden.env" = {
115 source = toString configFile;
116 matchers."ADMIN_TOKEN".secret =
117 config.sops.secrets.ADMIN_TOKEN.path;
118 matchers."SMTP_PASSWORD".secret =
119 config.sops.secrets.SMTP_PASSWORD.path;
120 matchers."YUBICO_SECRET_KEY".secret =
121 config.sops.secrets.YUBICO_SECRET_KEY.path;
122 matchers."HIBP_API_KEY".secret =
123 config.sops.secrets.HIBP_API_KEY.path;
124 matchers."clicks_bitwarden_db_secret".secret =
125 config.sops.secrets.clicks_bitwarden_db_password.path;
126 owner = config.users.users.vaultwarden.name;
127 group = config.users.groups.vaultwarden.name;
128 mode = "0400";
129 };
130
131 services.vaultwarden.environmentFile = config.scalpel.trafos."vaultwarden.env".destination;
132 } else { }
133)