setup sops, added pg user and pass for vaultwarden
diff --git a/modules/postgres.nix b/modules/postgres.nix
index 742e3d4..8f6c5f1 100644
--- a/modules/postgres.nix
+++ b/modules/postgres.nix
@@ -10,6 +10,10 @@
log_destination = lib.mkForce "syslog";
};
+ ensureDatabases = [
+ "vaultwarden"
+ ];
+
ensureUsers = [
{
name = "clicks_grafana";
@@ -24,6 +28,12 @@
"DATABASE synapse" = "ALL PRIVILEGES";
};
}
+ {
+ name = "vaultwarden";
+ ensurePermissions = {
+ "DATABASE vaultwarden" = "ALL PRIVILEGES";
+ };
+ }
] ++ (map
(name: (
{
@@ -55,6 +65,7 @@
)
(lib.mkAfter (lib.pipe [
{ user = "clicks_grafana"; passwordFile = config.sops.secrets.clicks_grafana_db_password.path; }
+ { user = "vaultwarden"; passwordFile = config.sops.secrets.clicks_bitwarden_db_password.path; }
] [
(map (userData: ''
$PSQL -tAc "ALTER USER ${userData.user} PASSWORD '$(cat ${userData.passwordFile})';"
@@ -65,6 +76,7 @@
sops.secrets = lib.pipe [
"clicks_grafana_db_password"
+ "clicks_bitwarden_db_password"
] [
(map (name: {
inherit name;
diff --git a/modules/vaultwarden.nix b/modules/vaultwarden.nix
index ca7893e..dd06d27 100644
--- a/modules/vaultwarden.nix
+++ b/modules/vaultwarden.nix
@@ -1,10 +1,34 @@
-{ pkgs, drive_paths, ... }: {
- environment.systemPackages = with pkgs; [ vaultwarden ];
+{ pkgs, drive_paths, lib, config, ... }: {
+ environment.systemPackages = with pkgs; [ vaultwarden ];
- services.vaultwarden.enable = true;
- services.vaultwarden.dbBackend = "postgresql";
+ services.vaultwarden.enable = true;
+ services.vaultwarden.dbBackend = "postgresql";
- services.vaultwarden.config = {
+ sops.secrets = lib.pipe [ "ADMIN_TOKEN", "SMTP_PASSWORD", "YUBICO_SECRET_KEY", "HIBP_API_KEY" ] [
+ (name: {
+ inherit name; value = {
+ mode = "0400";
+ owner = config.users.users.root.name;
+ group = config.users.users.nobody.group;
+ sopsFile = ../secrets/vaultwarden.json;
+ format = "json";
+ };
+ })
+ builtins.listToAttrs
+ ];
+} // (
+ let
+ isDerived = base != null;
+ in
+ if isDerived
+ # We cannot use mkIf as both sides are evaluated no matter the condition value
+ # Given we use base as an attrset, mkIf will error if base is null in here
+ then
+ with lib;
+ let
+ cfg = services.vaultwarden;
+
+ vaultwarden_config = {
# Server Settings
DOMAIN = "https://passwords.clicks.codes";
ROCKET_ADDRESS = "127.0.0.1";
@@ -12,25 +36,25 @@
# General Settings
- SIGNUPS_ALLOWED=false;
- INVITATIONS_ALLOWED=true;
- SIGNUPS_DOMAINS_WHITELIST="clicks.codes,coded.codes,thecoded.prof,starrysky.fyi,hopescaramels.com,pinea.dev";
+ SIGNUPS_ALLOWED = false;
+ INVITATIONS_ALLOWED = true;
+ SIGNUPS_DOMAINS_WHITELIST = "clicks.codes,coded.codes,thecoded.prof,starrysky.fyi,hopescaramels.com,pinea.dev";
# TODO: Set folder locations for storing data.
- RSA_KEY_FILENAME="${drive_paths.root}/bitwarden/rsa_key";
- ICON_CACHE_FOLDER="${drive_paths.root}/bitwarden/icon_cache";
- ATTACHMENTS_FOLDER="${drive_paths.External4000HDD}/bitwarden/attachments";
- SENDS_FOLDER="${drive_paths.External4000HDD}/bitwarden/sends";
- TMP_FOLDER="${drive_paths.External4000HDD}/bitwarden/tmp";
+ RSA_KEY_FILENAME = "${drive_paths.root}/bitwarden/rsa_key";
+ ICON_CACHE_FOLDER = "${drive_paths.root}/bitwarden/icon_cache";
+ ATTACHMENTS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/attachments";
+ SENDS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/sends";
+ TMP_FOLDER = "${drive_paths.External4000HDD}/bitwarden/tmp";
- DISABLE_2FA_REMEMBER=true;
+ DISABLE_2FA_REMEMBER = true;
# Admin Account
- ADMIN_TOKEN="!!ADMIN_TOKEN!!";
+ ADMIN_TOKEN = "!!ADMIN_TOKEN!!";
# Database Settings
- DATABASE_URL="postgresql://bitwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${}/bitwarden";
+ DATABASE_URL = "postgresql://vaultwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${config.services.postgresql.port}/vaultwarden";
# Mail Settings
@@ -54,5 +78,56 @@
# TODO: Buy a license
# HIBP Settings
# HIBP_API_KEY="!!HIBP_API_KEY!!";
- };
-}
\ No newline at end of file
+ };
+
+ nameToEnvVar = name:
+ let
+ parts = builtins.split "([A-Z0-9]+)" name;
+ partsToEnvVar = parts: foldl'
+ (key: x:
+ let last = stringLength key - 1; in
+ if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x
+ else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ]
+ substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x
+ else key + toUpper x) ""
+ parts;
+ in
+ if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts;
+
+ # Due to the different naming schemes allowed for config keys,
+ # we can only check for values consistently after converting them to their corresponding environment variable name.
+ configEnv =
+ let
+ configEnv = concatMapAttrs
+ (name: value: optionalAttrs (value != null) {
+ ${nameToEnvVar name} = if isBool value then boolToString value else toString value;
+ })
+ vaultwarden_config;
+ in
+ { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") {
+ WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault";
+ } // configEnv;
+
+ configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
+ in
+ {
+ scalpel.trafos."vaultwarden.env" = {
+ source = toString configFile;
+ matchers."ADMIN_TOKEN".secret =
+ config.sops.secrets.ADMIN_TOKEN.path;
+ matchers."SMTP_PASSWORD".secret =
+ config.sops.secrets.SMTP_PASSWORD.path;
+ matchers."YUBICO_SECRET_KEY".secret =
+ config.sops.secrets.YUBICO_SECRET_KEY.path;
+ matchers."HIBP_API_KEY".secret =
+ config.sops.secrets.HIBP_API_KEY.path;
+ matchers."clicks_bitwarden_db_secret".secret =
+ config.sops.secrets.clicks_bitwarden_db_password.path;
+ owner = config.users.users.vaultwarden.name;
+ group = config.users.groups.vaultwarden.name;
+ mode = "0400";
+ };
+
+ services.vaultwarden.environmentFile = config.scalpel.trafos."vaultwarden.env".destination;
+ } else { }
+)
diff --git a/secrets/postgres.json b/secrets/postgres.json
index 0ef90cf..ae3bcfc 100644
--- a/secrets/postgres.json
+++ b/secrets/postgres.json
@@ -1,6 +1,6 @@
{
"clicks_grafana_db_password": "ENC[AES256_GCM,data:tFByC3OyhRLkDlfjwq3Kmc7PnTHWmkXpXuqOGb2AzA9dkAijPggPhgvCrbkY8/oL8QwQDaI24+XV3U/8A2UwLbzu0L5oaWV/E4EJbyvi8UKp8Wg8Au25E0nD5tJZm7QQ3FVERgoUefcB8AEPJ4Z8Rgx1PuoBeun9toT1GkJtmuYNNHpOcFrbmaI/Qf1MP+yFZLYjvB1jz07V04RGTv4jow61lWFknS2aPJyat43Ogp64lIkfjen7zCvj3CWghfJx87uxeXsnFHMrRwfONozUdw19Bq1uLUJ7xvPqDtr/1WKi1xvBe5ez7/PkPslNJlIToIlL89xN/lOm2iQR2BNeXg==,iv:ruC4PzKpWYsz2qe0KImUo0YhRt2cisYx306yfPtzi6c=,tag:U8vg7w1zyqXAWH3WzNAHFA==,type:str]",
- "clicks_bitwarden_db_password": "ENC[AES256_GCM,data:57vOGaSralBt6w==,iv:b4ujdo16fqA3Ln277ubqp8cLeRlgldUoe5rFNjUmY5U=,tag:Ak79yTs6BkqwuyfYo3i4vg==,type:str]",
+ "clicks_bitwarden_db_password": "ENC[AES256_GCM,data:Xr9h/QVazxn1tzSNJgPH9uk6RE2bk0fNyOVNxSlflQ14wnna0xA9Uw4CcN9DbPyvBCvYsKrxTJOAzLOn/K4rc/G1C7dPKpGADiTH5O+1wX+PifrDHtQyuqvaarwO3QA20ZW48A==,iv:yKYDF3X9fNO+rbnguo5DAiXfCkjH06VkpGBjB9NGv/s=,tag:W8fAVyJGh6jQxwHMN+RAPg==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
@@ -20,8 +20,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByN0hMaXF2S2xiTTNqbm9h\nSGNieGNjNThJTk0wZXNQejBXaW9MOEp2akNFCm8rWVc3WG9pVndERFZzUnFOZnVG\naFBxTENlQ0x0ZjdqUHF6SFBPKzQ4bUEKLS0tIGVJTmdveTZrNTRiSTl0cHRQeWhl\nY2RmUTVQVTNoMFhLdkc3WFZEcHAycnMKqr42TSx7Pqcu62XgX4gj/iq2tbkZjFxg\nOcWBsLzqOsu/r0w5cK2Ple6JFGIJwmT2SqVqZh1pPbPwYHHXHbEphg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
- "lastmodified": "2023-06-13T18:27:44Z",
- "mac": "ENC[AES256_GCM,data:bonRKaRPC5oSlNll4gA2vcOFz2qhmN7JOQftTsHOvsoWjxbFk6gUbvwcc0qHXEClgqnRvbhcKu/ngBlp/w8NpmpzwOhWc023xDOsSheS5U3PwCfh5UIhxWEkaTtxvSScqN5EdwWAAPuSPB6Pdwg1oaS25dI5YCh0tHR56Soizu0=,iv:+pcWDLpEHw/BiTBucYbPTvju1W6sYa1+sW+FIuc6+Qw=,tag:kAjxBms7dXP04TaMRalbAA==,type:str]",
+ "lastmodified": "2023-06-13T21:01:47Z",
+ "mac": "ENC[AES256_GCM,data:vm4yvl63zP9abxXuCtjjRh9LOVq63Q3nc8o8p2wj+v0pd1ltVZAMKmi/c6f4q+s12M0EYNQbqspLpG4OYva6WinAIyVJIvjvBJGKseH+lB2GrO+3jwlanOiHRl2ueAhihfGgj3dgqGiLUKoT1jFewZMoAY+PiGhp+Bup/Ziky9g=,iv:4YGy2zExsKUGQ9WAir0MFH9mFirbCPkjS523w1wpys4=,tag:nF8pO9I57AGAydFupYYU0w==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.7.3"