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