blob: 0a3764e52262793bf21b6527ee0bba1a8e162526 [file] [log] [blame]
Skyler Grey (Minion3665)e430df32023-06-23 18:22:19 +00001{ base, pkgs, drive_paths, lib, config, ... }:
Skyler Grey31618512023-08-20 21:54:44 +00002lib.recursiveUpdate
3{
TheCodedProfb6184602023-06-13 17:04:59 -04004 environment.systemPackages = with pkgs; [ vaultwarden ];
TheCodedProfaec8c452023-06-12 18:26:46 -04005
TheCodedProfb6184602023-06-13 17:04:59 -04006 services.vaultwarden.enable = true;
7 services.vaultwarden.dbBackend = "postgresql";
TheCodedProfaec8c452023-06-12 18:26:46 -04008
Skyler Grey87a11552023-06-14 23:02:25 +02009 sops.secrets = lib.pipe [ "ADMIN_TOKEN" "SMTP_PASSWORD" "YUBICO_SECRET_KEY" "HIBP_API_KEY" ] [
10 (map (name: {
TheCodedProfb6184602023-06-13 17:04:59 -040011 inherit name; value = {
12 mode = "0400";
13 owner = config.users.users.root.name;
14 group = config.users.users.nobody.group;
15 sopsFile = ../secrets/vaultwarden.json;
16 format = "json";
17 };
Skyler Grey87a11552023-06-14 23:02:25 +020018 }))
TheCodedProfb6184602023-06-13 17:04:59 -040019 builtins.listToAttrs
20 ];
Skyler Grey31618512023-08-20 21:54:44 +000021}
22 (
TheCodedProfb6184602023-06-13 17:04:59 -040023 let
Skyler Grey31618512023-08-20 21:54:44 +000024 isDerived = base != null;
TheCodedProfb6184602023-06-13 17:04:59 -040025 in
Skyler Grey31618512023-08-20 21:54:44 +000026 if isDerived
27 # We cannot use mkIf as both sides are evaluated no matter the condition value
28 # Given we use base as an attrset, mkIf will error if base is null in here
29 then
30 with lib;
31 let
32 cfg = config.services.vaultwarden;
TheCodedProfb6184602023-06-13 17:04:59 -040033
Skyler Grey31618512023-08-20 21:54:44 +000034 vaultwarden_config = {
35 # Server Settings
36 DOMAIN = "https://passwords.clicks.codes";
37 ROCKET_ADDRESS = "127.0.0.1";
38 ROCKET_PORT = 8452;
39
40
41 # General Settings
42 SIGNUPS_ALLOWED = false;
43 INVITATIONS_ALLOWED = true;
44 SIGNUPS_DOMAINS_WHITELIST = "clicks.codes,coded.codes,thecoded.prof,starrysky.fyi,hopescaramels.com,pinea.dev,trans.gg";
45 SIGNUPS_VERIFY = true;
46
47 RSA_KEY_FILENAME = "${drive_paths.External1000SSD.path}/bitwarden/rsa_key";
48 ICON_CACHE_FOLDER = "${drive_paths.External1000SSD.path}/bitwarden/icon_cache";
49 ATTACHMENTS_FOLDER = "${drive_paths.External4000HDD.path}/bitwarden/attachments";
50 SENDS_FOLDER = "${drive_paths.External4000HDD.path}/bitwarden/sends";
51 TMP_FOLDER = "${drive_paths.External4000HDD.path}/bitwarden/tmp";
52
53 DISABLE_2FA_REMEMBER = true;
54
55 # Admin Account
56 ADMIN_TOKEN = "!!ADMIN_TOKEN!!";
57
58
59 # Database Settings
60 DATABASE_URL =
61 "postgresql://vaultwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${toString config.services.postgresql.port}/vaultwarden";
62
63
64 # Mail Settings
65 SMTP_HOST = "mail.clicks.codes";
66 SMTP_FROM = "bitwarden@clicks.codes";
67 SMTP_FROM_NAME = "Clicks Bitwarden";
68 SMTP_SECURITY = "starttls";
69 SMTP_PORT = 587;
70
71 SMTP_USERNAME = "bitwarden@clicks.codes";
72 SMTP_PASSWORD = "!!SMTP_PASSWORD!!";
73
74 REQUIRE_DEVICE_EMAIL = true;
75
76 IP_HEADER = "X-Forwarded-For";
77
78 # YubiKey Settings
79 YUBICO_CLIENT_ID = "89788";
80 YUBICO_SECRET_KEY = "!!YUBICO_SECRET_KEY!!";
81
82
83 # TODO: Buy a license
84 # HIBP Settings
85 # HIBP_API_KEY="!!HIBP_API_KEY!!";
86
87 ORG_ENABLE_GROUPS = true;
88 # I have looked at the risks. They seem relatively small in comparison to the utility
89 # (stuff like sync issues if you don't refresh your page)
90 # Also a general lack of real-world testing. Which, honestly, doesn't
91 # seem too bad. Please contact me *immediately* upon noticing issues
92 # as I want to make sure that as little as possible is lost if we need
93 # to restore from backups (although I doubt it'll come to that)
94 };
95
96 nameToEnvVar = name:
97 let
98 parts = builtins.split "([A-Z0-9]+)" name;
99 partsToEnvVar = parts: foldl'
100 (key: x:
101 let last = stringLength key - 1; in
102 if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x
103 else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ]
104 substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x
105 else key + toUpper x) ""
106 parts;
107 in
108 if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts;
109
110 # Due to the different naming schemes allowed for config keys,
111 # we can only check for values consistently after converting them to their corresponding environment variable name.
112 configEnv =
113 let
114 configEnv = concatMapAttrs
115 (name: value: optionalAttrs (value != null) {
116 ${nameToEnvVar name} = if isBool value then boolToString value else toString value;
117 })
118 vaultwarden_config;
119 in
120 { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") {
121 WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault";
122 } // configEnv;
123
124 configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
125 in
126 {
127 scalpel.trafos."vaultwarden.env" = {
128 source = toString configFile;
129 matchers."ADMIN_TOKEN".secret =
130 config.sops.secrets.ADMIN_TOKEN.path;
131 matchers."SMTP_PASSWORD".secret =
132 config.sops.secrets.SMTP_PASSWORD.path;
133 matchers."YUBICO_SECRET_KEY".secret =
134 config.sops.secrets.YUBICO_SECRET_KEY.path;
135 matchers."HIBP_API_KEY".secret =
136 config.sops.secrets.HIBP_API_KEY.path;
137 matchers."clicks_bitwarden_db_secret".secret =
138 config.sops.secrets.clicks_bitwarden_db_password.path;
139 owner = config.users.users.vaultwarden.name;
140 group = config.users.groups.vaultwarden.name;
141 mode = "0400";
142 };
143
144 services.vaultwarden.environmentFile = config.scalpel.trafos."vaultwarden.env".destination;
145 } else { }
146 )