diff --git a/modules/nixos/barcodebuddy-scanner.nix b/modules/nixos/barcodebuddy-scanner.nix index c718c89c..93070a5e 100644 --- a/modules/nixos/barcodebuddy-scanner.nix +++ b/modules/nixos/barcodebuddy-scanner.nix @@ -92,7 +92,10 @@ in { prepKeyEnvironment = pkgs.writeShellScript "barcodebuddy-scanner-apikey.sh" '' set -eu - printf "API_KEY=$(cat $API_KEY_PATH)\\n" > $RUNTIME_DIRECTORY/${apiKeyFile} + printf "" > $RUNTIME_DIRECTORY/${apiKeyFile} + chmod 0640 $RUNTIME_DIRECTORY/${apiKeyFile} + + printf "API_KEY=$(cat $API_KEY_PATH)\\n" >> $RUNTIME_DIRECTORY/${apiKeyFile} ''; in { wantedBy = [ diff --git a/modules/nixos/vaultwarden.nix b/modules/nixos/vaultwarden.nix new file mode 100644 index 00000000..15c96518 --- /dev/null +++ b/modules/nixos/vaultwarden.nix @@ -0,0 +1,86 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib.options) mkOption; + inherit (lib.modules) mkIf mkOptionDefault; + inherit (lib.attrsets) attrNames filterAttrs mapAttrs' nameValuePair; + inherit (lib.strings) concatMapStringsSep; + cfg = config.services.vaultwarden; + RuntimeDirectory = "bitwarden_rs"; + secretsFile = "secrets.env"; +in { + options.services.vaultwarden = with lib.types; { + port = mkOption { + type = port; + default = 8222; + }; + websocketPort = mkOption { + type = nullOr port; + default = null; + }; + databaseUrlPath = mkOption { + type = nullOr str; + default = null; + }; + adminTokenPath = mkOption { + type = nullOr str; + default = null; + }; + smtpPasswordPath = mkOption { + type = nullOr str; + default = null; + }; + }; + config.services.vaultwarden = { + config = { + DATA_FOLDER = mkOptionDefault "/var/lib/bitwarden_rs"; + WEB_VAULT_ENABLED = mkOptionDefault true; + ROCKET_ENV = mkOptionDefault "production"; + ROCKET_ADDRESS = mkOptionDefault "::1"; + ROCKET_PORT = mkOptionDefault cfg.port; + WEBSOCKET_ENABLED = mkOptionDefault (cfg.websocketPort != null); + WEBSOCKET_ADDRESS = mkOptionDefault "::1"; + WEBSOCKET_PORT = mkIf (cfg.websocketPort != null) cfg.websocketPort; + }; + }; + config.systemd.services.vaultwarden = let + filterNullAttrs = filterAttrs (_: v: v != null); + secretPaths' = { + DATABASE_URL = cfg.databaseUrlPath; + ADMIN_TOKEN = cfg.adminTokenPath; + SMTP_PASSWORD = cfg.smtpPasswordPath; + }; + secretPaths = filterNullAttrs secretPaths'; + hasSecrets = secretPaths != {}; + mkPrintSecret = key: let + path = "${key}_PATH"; + in '' + if [[ -n ''${${path}-} ]]; then + printf "${key}=$(cat ''${${path}})\\n" >> $RUNTIME_DIRECTORY/${secretsFile} + fi + ''; + prepSecrets = pkgs.writeShellScript "vaultwarden-secrets.sh" '' + set -eu + + printf "" > $RUNTIME_DIRECTORY/${secretsFile} + chmod 0640 $RUNTIME_DIRECTORY/${secretsFile} + + ${concatMapStringsSep "\n" mkPrintSecret (attrNames secretPaths')} + ''; + in + mkIf cfg.enable { + environment = mkIf hasSecrets (mapAttrs' (key: nameValuePair "${key}_PATH") secretPaths); + serviceConfig = { + inherit RuntimeDirectory; + EnvironmentFile = mkIf hasSecrets [ + "-/run/${RuntimeDirectory}/${secretsFile}" + ]; + ExecStartPre = mkIf hasSecrets [ + "${prepSecrets}" + ]; + }; + }; +} diff --git a/modules/system/exports/vaultwarden.nix b/modules/system/exports/vaultwarden.nix new file mode 100644 index 00000000..6446ec34 --- /dev/null +++ b/modules/system/exports/vaultwarden.nix @@ -0,0 +1,41 @@ +{ + lib, + gensokyo-zone, + ... +}: let + inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; + inherit (lib.modules) mkIf; + inherit (lib.attrsets) mapAttrs; +in { + config.exports.services.vaultwarden = {config, ...}: { + id = mkAlmostOptionDefault "bw"; + defaults.port.listen = mkAlmostOptionDefault "lan"; + nixos = { + serviceAttr = "vaultwarden"; + assertions = mkIf config.enable [ + (nixosConfig: { + assertion = config.ports.default.port == nixosConfig.services.vaultwarden.port; + message = "port mismatch"; + }) + (nixosConfig: { + assertion = nixosConfig.services.vaultwarden.websocketPort == null || config.ports.websocket.port == nixosConfig.services.vaultwarden.websocketPort; + message = "websocketPort mismatch"; + }) + (nixosConfig: { + assertion = config.ports.websocket.enable == (nixosConfig.services.vaultwarden.websocketPort != null); + message = "websocketPort enable mismatch"; + }) + ]; + }; + ports = mapAttrs (_: mapAlmostOptionDefaults) { + default = { + port = 8222; + protocol = "http"; + }; + websocket = { + port = 8223; + protocol = "http"; + }; + }; + }; +} diff --git a/nixos/access/vaultwarden.nix b/nixos/access/vaultwarden.nix new file mode 100644 index 00000000..80889760 --- /dev/null +++ b/nixos/access/vaultwarden.nix @@ -0,0 +1,80 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf mkDefault; + cfg = config.services.vaultwarden; + upstreamName = "vaultwarden'access"; + upstreamName'websocket = "vaultwarden'websocket'access"; + locations = { + "/".proxy.enable = true; + "/notifications/hub" = { + proxy = { + enable = true; + upstream = mkDefault upstreamName'websocket; + websocket.enable = true; + }; + }; + "/notifications/hub/negotiate" = { + proxy = { + enable = true; + websocket.enable = true; + }; + }; + }; + name.shortServer = mkDefault "bw"; + copyFromVhost = mkDefault "vaultwarden"; +in { + config.services.nginx = { + upstreams' = { + ${upstreamName}.servers = { + local = mkIf cfg.enable { + enable = mkDefault true; + addr = mkDefault "localhost"; + port = mkDefault cfg.port; + }; + access = {upstream, ...}: { + enable = mkDefault (!upstream.servers.local.enable or false); + accessService = { + name = "vaultwarden"; + }; + }; + }; + ${upstreamName'websocket}.servers = { + local = mkIf cfg.enable { + enable = mkDefault (cfg.websocketPort != null); + addr = mkDefault "localhost"; + port = mkIf (cfg.websocketPort != null) (mkDefault cfg.websocketPort); + }; + access = {upstream, ...}: { + enable = mkDefault (!cfg.enable && !upstream.servers.local.enable or false); + accessService = { + name = "vaultwarden"; + port = "websocket"; + }; + }; + }; + }; + virtualHosts = { + vaultwarden = { + inherit name locations; + ssl.force = mkDefault true; + proxy.upstream = mkDefault upstreamName; + }; + vaultwarden'local = { + inherit name locations; + ssl = { + force = mkDefault true; + cert = { + inherit copyFromVhost; + }; + }; + local.enable = true; + proxy = { + inherit copyFromVhost; + }; + }; + }; + }; +} diff --git a/nixos/postgres.nix b/nixos/postgres.nix index f1e5ee6d..fef3f32f 100644 --- a/nixos/postgres.nix +++ b/nixos/postgres.nix @@ -9,7 +9,7 @@ in { services.postgresql = { enable = mkDefault true; - ensureDatabases = ["hass" "invidious" "dex" "keycloak"]; + ensureDatabases = ["hass" "invidious" "dex" "keycloak" "vaultwarden"]; ensureUsers = [ { name = "hass"; @@ -19,7 +19,7 @@ in { { name = "invidious"; ensureDBOwnership = true; - authentication.int.allow = true; + authentication.int.allow = !config.services.invidious.enable; } { name = "dex"; @@ -29,7 +29,12 @@ in { { name = "keycloak"; ensureDBOwnership = true; - authentication.int.allow = true; + authentication.int.allow = !config.services.keycloak.enable; + } + { + name = "vaultwarden"; + ensureDBOwnership = true; + authentication.int.allow = !config.services.vaultwarden.enable; } ]; }; diff --git a/nixos/secrets/postgres.yaml b/nixos/secrets/postgres.yaml index 13695c9b..17c7c614 100644 --- a/nixos/secrets/postgres.yaml +++ b/nixos/secrets/postgres.yaml @@ -1,4 +1,4 @@ -postgresql-init: ENC[AES256_GCM,data:lbkeMv6PZgB7tEl4VbIYX9VUAgJ6Kcj0jLNyyqxJJcVJPjo1lF2d/i5bFnU1/6aJ2T7ftMW4hefYgrnIMdKXxPPfrHftaEMhl9bfJIsuX2I1CXAasZOhpsmg9Wf2cvXuVYIlqTVssg+3EKW0ejCMdX6OfGdAXvBlio1DQs7YrUc+BjDiEuAUAaaYbz67EYY3dpYQixQGl/8G2w7S897uCXpc1oOh6vbGY4Nl+GGQ7B5xrrbYcdATwfGyYlZYSlIv8feDsLv7Rt+w3o4tTAxcz+8qZ7KZ6sIsu/nUoYeqoT9MJ8uRpWccXKcBVAFSEooUIHUEBA/QsGizAXBgzCnyLDvuv3DOquo2xeMg0kWM8zsF1f9YRyUKqQ==,iv:RKIvggRZlPocygabF0iKNBThBRFG5rlzrIvGjjt7s0o=,tag:U/XUDJs5J8lHB9BJ5/0fFA==,type:str] +postgresql-init: ENC[AES256_GCM,data:hsSiYNQy9G/zw+XVGW2ewu9/5pz9QobrpOZ/3a00pjtbW03Yn7t2NlELMKsz1cLkkzSfvLQC7hVCONNrlxMYc0zOIhGNH4rpY8FzMa5q2oXmouO5zE2wYqBTjx/9KezXrRJv32g0s4wxP7RoBBC9fRqbOmYrXQJZQZDV7kze6NdXv0WtvAwp54/szG5TeQkXymNP+TKtI9qV8EMBcSXze5Gr2ia625TSYvY7/cbOTeMvOaQ9Y1SKm1G10dLwIxE2Wolc/qOs0kzUzT7ZLPAo8TSW3vBCojMv1xZahF7M7PGQih4gR8XMZLvAVRrUBfVuZpbWcvqijgTjqhn5wegBL8RI0ry/Dw07Cx/31+9Zcwtqt0l3LDM56XFYFBKY/oscsbhd1RAKcK2iPI9HXWB5Jipu6B0OLJd7CWWcuCrPP2YjKJVyDVR0Sgrnc0bcefXJs/5e+1yNzeorbvPtIvxItLeeoQ==,iv:sauPtv+SK7T/+T1gXO7RjAeLwH3nKJgf8d8tPBbVWgw=,tag:6ZtuRsPvL9+Y8CUNHqmrgg==,type:str] sops: shamir_threshold: 1 kms: [] @@ -78,8 +78,8 @@ sops: NVg3YVJ0eDFDZTZuSjIzdlVWZnI0OVUKMZ0vG0GIfyGtmNZQ6C94bABpI6Fb6VVJ 8vGv1rf2kxJXy9dktQs1pvgP6CD1ZQu9qCGvd+UjQgrgmqy0HABhKA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-03-13T21:46:56Z" - mac: ENC[AES256_GCM,data:rEtRHX3PH1B+uoR82lDH3ACKHPbhxy+y7B9YgR6TzPSU4yIaTSqSK51eLJZoUtW6UTl6QDcTrsKDA8lGu9M/Ohfx8ayp6rkX63H/hkl0h6YaQmWDAQoNAAEWqfJ9r8O8tKKpE6qF/rw4c4KpuA5ONufOl9qj1KSgFzz0WHaKtWk=,iv:TUBAe62dmF6FAjZOPaxwzQjWL21TdWQG0YyuXJGgtk8=,tag:dewWivfnZO30Np2gajwLIw==,type:str] + lastmodified: "2024-05-26T19:56:47Z" + mac: ENC[AES256_GCM,data:6GHSGv54tO4SH7fb1ud4Zrht+ncmEyaVVByppEFPbm4e0cUHr0/sM06dfaB8baoM0knA2VlJRJE1zpfANYmYHbtGBDqHW0yhmh9UhwQFUUah9LjNXdsiPzTLPUq3vuaadO1BnPiZEqk1lToVNr3LN+V4LaD3nLMVRSp1dGhgCNk=,iv:9IrRC1UlYZpY/K2kDiHXhIydR5qBo94p0odS/WnAZZA=,tag:0wVyXa06MWP6xFh6ebUb+w==,type:str] pgp: - created_at: "2024-03-21T17:42:39Z" enc: |- diff --git a/nixos/secrets/vaultwarden.yaml b/nixos/secrets/vaultwarden.yaml new file mode 100644 index 00000000..57a280f6 --- /dev/null +++ b/nixos/secrets/vaultwarden.yaml @@ -0,0 +1,139 @@ +vaultwarden-database-url: ENC[AES256_GCM,data:S1VaNmBE1ZRvxxDOpRLS5K5bZ6YqzKD7Gw1fd8lzkv8iHfirdMb6fiJS37+z2yMmgGFktO7nLoy+y05yxTzpECAtlhfwQtuahKCS7g8HT27sVAB/oILmfVAYzm51uVQViII=,iv:2uvFAht47GSNQYyljqvJlGcN09vdJAEPKWsIPuYgIYE=,tag:CptCKjyBNv/eHd6kVhNbiQ==,type:str] +vaultwarden-admin-token: ENC[AES256_GCM,data:aGJpvhYKU/BnjH9QaSCuvpCEVWaCI39EXY7pN3BCmqmFhueze6XNodcmcNmtdrKJrGf8fibi01kO4zzBN1LSEw==,iv:tOpEn1ipuVMXV8PQ40jFtCbfVhLKcLK2wwfzJuK+7ic=,tag:ZRK/F2JijQgjof94bSu0CQ==,type:str] +sops: + shamir_threshold: 1 + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age12ze362pu5mza6ef9akrptr7hfe4auaqul4rkta7kyy2tnrstqensgmujeq + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArTkpmTzg2TVNkUzN1anhn + Tm9uVXlwTlJnTFdqNFMrODhRYW1lWnlFcEhBCnVrTjhWZWpFMUR6MDZXZUIwVXZB + L1JWZFRZcGt0cDBlU2ZVeXNjSEszSFEKLS0tIHZRSEJPamlsRTRjV05JWUFkcWZL + UmIwbU5yTkltYWRnbVlXcTR3RGFCajAKiwxNJsd9UNFBarTTGNQBz9tx6OKWLFO0 + WCsMtiNwJcxOtBTcLL1GwalwOCnN2Cc9xy37V/4np5dQL8d22EegjQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age176uyyyk7veqnzmm8xzwfhf0u23m6hm02cldlfkldunqe6std0gcq6lg057 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvTDlhWDE3WGxybTNTQVZk + WE04VmI4MFJnMzdLRmdJcWlxOTVOa2pNL0VBCkFHS21UcDZ2VTUwdUNUK1NjQWdl + MFcySERHdGU4SjlkdUZ6VTg0QlNxdWcKLS0tIGFZYVYwelA2Q1JuTWVvdUpJR0pL + ZW9YakoxSGRBa3J2YUlaOEFFd25BSVEKyObsLBi3Jkyu8GIbuTFZQU7l2plH6zS0 + TF1lBGu8dSgZicGUqhspC0BvXPd1GtIxBXpT3RCc4mK8HITirT2AjQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age15hmlkd9p5rladsjzpmvrh6u34xvggu9mzdsdxdj3ms43tltxeuhq4g7g9k + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrU0FWVDFwcUdFazByYjBM + YWVYTWZBVzM0T1NqbEpGZVVKR2pJVWxhVGtRCng2eXlWdmF3RzREQ2RTeTNVTWM2 + cDFoYW9FdTBqcURjdmlZN3pHQ0ZxU2sKLS0tIDFxUHhSTlI4clZJcEE5a3kzSXo4 + aVdXM1pQREFjcFJIR3FDdGcvVHQrbzgKu98WWiatWhlBvPNQsZMiI1NMXpwBlxlo + GhP85QXIUa4V1BWSvmnRw9ljYrpviFBFLmk7sZOLpJoJzcsjIRLMnA== + -----END AGE ENCRYPTED FILE----- + - recipient: age10t6kc5069cyky929vvxk8aznqyxpkx3k5h5rmlyz83xtjmr22ahqe8mzes + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuMSsrMHNXN3BGNlF2Zkd6 + bTdNV2dNSDhmK1NtTDFkMklRVkhwY2dyQjE4CnNQd1NmT0sxUXZBeUlRQWVTQU5z + ZkVCbW5WYjB6RHpOU1NpWGtOSHAycE0KLS0tIHRVaUtFWW5CbS9ZRVRUeWVKVFRh + WHBJaTVENW9uUmNZTDE5L0NhZG5NL3MKqwcV1HZs21z895ujeLHNHHCgDMNztdTG + zQYhqgQ7P7S/ykT8a2Qc/Y2SLIo2ECX5wSV+a+vWkpTaJSf4hp0yLg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a2quf2ekkj94ygu7wgvhrvh44fwn32c0l2cwvgvjh23wst90s54szdsvgr + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGcW9ualNLNjQrOTlGcjQr + UzNoYkp3a1JYSUpYZEdYNXdNOERRcVNqb0dVCndGSmtCNGdZdEpBcTI4NTduVUFk + NytqRnVUYXFadjhyUkdVbWtOOUwzb2sKLS0tIHVLNHl0dHdLRkFXa1phWkR2VFVY + SmNORjRlMHVzQm9nLy9TTURtcndQMlkKRn2ldZek0F8l+KiUvikcvi/oudO7byPK + xYhs9QrZS0CmE94k7cYrI2yE7TdwE03BcSY2Sv90F06uSdHdRnBFqQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age16klpkaut5759dut8mdm3jn0rnp8w6kxyvs9n6ntqrdsayjtd7upqlvw489 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJY1lhMWFsaXNUSFFWRHNK + WVVxeVB4VkVpTWFkVndZdSthVDAwY295Um1jCjdXa05uSFMwTXBacmYyZmZFeXNM + RnBjWjA0aUVQaVJIUTNIb3FmUERMR2sKLS0tIGRBZlRTekVrenIrZU5kKzVVOURi + ckcvRXdSbGMxUTRzb1ovNUI2R0JEc00K1NodlRscDSzyJvOvLLDQ/csQ9bNNIcrZ + LS3CegfUNASprO+k3/L+5laAm0WYpgZL5YFbgzh8zs+s0Q9R2e7Qqg== + -----END AGE ENCRYPTED FILE----- + - recipient: age13qgddr326g5je0fpq2r3k940vsr3fh9nlvl9xtcxk3xg2x0k3vsq7pvzaj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxY2xSaW51dVpEOHcwbkli + dDNNQk1aVFM5Z0gvVHR1WVpaY0t6YWt0UXdnCkEyZ2Y5OThPZmRNK3I4eW1sc0RY + M3Z1OExkTnAwRzBmVndDMVZyYjJzbUUKLS0tIFZNWG1TdkVpZ1UzL2owQ0gvS1NM + c25Zb0xkUlZKNE9lRHdSekVjRWtUYVEK5A4L6xhv4OMrEXPJfcRO2BDuQ591DSb+ + 4AJ5Sy/dwecZ1O/j7HvPwb6i/euXtDDLMjh+5m0G5tx3TpUtmO4nEg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1ktmx2szedfnpe5xumnzs8vkk0ffqgga6ved3drtksg9pye6ndsnsnqq488 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpajhMK1p2YU5iakUyYzVR + TkdFSWVFZ3VJRXI2Z1ljU0FvalIvU1M0TlVrCmNEVUJyV1ZURy9TUHJHMkc5cWZ0 + YVhoMFl4U0NqdUl1V1lNdGh0K0RjalEKLS0tIDQyV2g1SkhuVHFMY0toWFg3NWVo + UDNIYnpKcncrYWNTRlIzbHZUVk9WOE0Kbko4KSTQSqIjET6iBnaYyRI749QfQGEk + /5IZGBQdhERaeU4WCm0UHxyyiEyUbfmCJYQrxdxaRzVVEX2lJQddtQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1fjcafp0j45sz03zq5srnxyq2mujndmn25vceg3wj2cgzymqm73ssmhdgku + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBycWJSbXZiK0VHTjRlMjJT + enUxRmM1QjVEVHFSYWM1Y1VPSEdsdXZBNFZBCjFWM2ZjdFV6TWhkZnZ3ZlVFT2Jm + SHRwTE05RFgyUGhwZVp6ODJiRXlSOGsKLS0tIDdnZTFNTGNFdnV3NGJKbG9Fb0lB + UXg2N0xKUml4dy9SOGN3NGRYa3JRN28K4+tqEeK+TuLuSFbC/Cu7K+jMK2tx96FG + RJ+Y3tOJTt4jd66jwrslcyyZmWHhDSajVnsYWBy6XQPBGqPd6RYkhQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1tkkau8vk5h9dh3kemash4eghn7lk84j0hhpmvvf7j6phgcsm9vmsphv0py + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaUDNvMGs2QUt1VE9uVjdH + OCtjbkxRTWpRTFhzY2gySjNzb1BmMFk1dXhJCjZpV1lTU1ltTFZlQitucGN2cGli + VW9IdnRFRnN5cDdoYXVjQUtFVlBFckEKLS0tIEhrdnp3blFyajN4OTRCZDVmeXJs + QTZ0Y2NrYi9WbGpCd0d1dHRqS1AzYk0K2TgpwYN+rcnoxURWJeQe3JlKXTRg2reR + 6+DgdrZ/geJbKVmCQkeCxxbMU1zUqpbB9B8AxsunsiKhdZnohm5NYw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-05-26T20:29:52Z" + mac: ENC[AES256_GCM,data:5rt1+feYuDESuYd/MpD+Dcf0SPjgaetWFq3ZoH9Fb6tE+2I183wQzMLO/ToxGP+Ea2o8Z/FbPesZ9P6hmKzLpHQdEhSmfilpCU0LYr98ze+9xFzuHfUWJ5u4ZZZ8uqZ7U7wW3GKM0YBtihSNBN/LF+gKUazC9pLZ/IoQEmvTwxs=,iv:O6EAod7lCtwalVw2xOYDu8Ifnb99YsL6C+hO0zngOj4=,tag:uN5z7lighvrSyjHYDSW2Hg==,type:str] + pgp: + - created_at: "2024-05-26T20:06:39Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQIMA82M54yws73UAQ/+Nfgm6hU+WiiRLwJdyPO8iWnPjB4ELWcmQw7I/QLg4jti + 4vGMyGq+F6v4nZorvsmk/OVde2rTUvKmENCy6Bh1/TbfHxSCJkJJi1L8oxZiwA3M + oJoC5usQ5K0kWPiHZgsjHNiEGsPfSO8FBV+ipYYzPpXsBKNS+jg4Lv+kkRga1TUx + lky2ffJmjrjLp3In+EicnQIt7J43KZzE2hbJ45vGbr6IjspqvdTHfJ6upRXWu+Xy + acYr9uC/W6ZbsTkhcES9GS9ZqJZ/WTh1l5lrVWztcMgtG1SDZJee2GxAVTL85X+N + Y61s6D5gJJLWO0HF5tCRaCjs0MsaJkDIF9U3z5jwXX1BSoa6QA6qErPM6PQ4bVI3 + dQ5zJ6dLKzRcP4vR4k9SSWE51FVU1zKzsrEHPAm15dCix3+TqnxPCERwlZgvsvWp + B+yp2jZfAL7C3sJqUIv92+DVszA5ZA5ZWLTAsyakFHzdNz4VNahIO/edGH57YXu3 + whvpDUgscqNdXaADwwzBEzAsByB/G21PM+W20LT5vfyyb0Nkprin1T9ZBpGJIyuP + WSzfoOvxPuJVa/SIOwfYtEZUAUquMI4f9og+0YU+ZiQuMIXGCoHNZX4y5ivxiG22 + vcvPgdvJNllb8ix2gGGGCGTVwqCdyAuN48UtqESclDiC9jJ7KdjXXs+AefRXSzPS + XgGyTVziTQQjenT+ZNH5rAtBzVGLqtRsU0mKquce22AxGy8jlsAJ0340VEth2Rnd + Qk8mlzZg14IYP2/qy3qvwozv9ygP02ROhfXMO0RjfqnRybRuSHCj1d9mmp/YUno= + =iYQp + -----END PGP MESSAGE----- + fp: CD8CE78CB0B3BDD4 + - created_at: "2024-05-26T20:06:39Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQEMA2W9MER3HLb7AQf/V6GhWuzdF3iW+1O4m6FhONNfVbqvWsPcZrMXiyXTqxk4 + G+tNh2ccIXDCDBdfGC5vhdOFv12tn6bTyuFwPmCf8r+2pKtRn3omn4mRlsGspgP8 + kM8xIwsBgRwkbg+u4rQpNb/3RGcC5Sm8SY3bNgTLU8rWI/s1+ppyhn67Ep2E8IrQ + Foe8mKnbZihFFxzj3VhV4IyysJgPoIxG9Z/Mnc5DAUso1nK4mzC80INgnoSEhYAk + RIuENp2R45tE/p1h2ITZqsI9eT6QY/OjgDWp6kAWIH5jehUFep3tU9rkQRCfZLbT + SQARFuzXC5xAuQTOUCpGMedkgv6V/oCESkhl6dNbG9JeAShLF4YWeLyG7Ftrxqfz + iA+K0UA0qywo0mHZyl8K1bJwQJONbBb2RbjbJiAfkfOdWXQBH3AkkQdDTGUGjKQR + 4lFDSo4cYk6CnB5XI3jDrJE4rX24oAg+KNPKu3GTpw== + =1ZB1 + -----END PGP MESSAGE----- + fp: 65BD3044771CB6FB + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nixos/vaultwarden.nix b/nixos/vaultwarden.nix new file mode 100644 index 00000000..3be06501 --- /dev/null +++ b/nixos/vaultwarden.nix @@ -0,0 +1,48 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf mkDefault; + inherit (config.services) postgresql; + cfg = config.services.vaultwarden; + enableAdmin = false; +in { + config.services.vaultwarden = { + enable = mkDefault true; + dbBackend = mkDefault "postgresql"; + websocketPort = mkDefault 8223; + databaseUrlPath = mkIf (!postgresql.enable) (mkDefault config.sops.secrets.vaultwarden-database-url.path); + adminTokenPath = mkIf enableAdmin (mkDefault config.sops.secrets.vaultwarden-admin-token.path); + config = { + SIGNUPS_ALLOWED = mkDefault false; + ROCKET_ADDRESS = mkDefault "::"; + WEBSOCKET_ADDRESS = mkDefault "::"; + DATABASE_URL = mkIf postgresql.enable (mkDefault "postgresql://vaultwarden@/vaultwarden"); + }; + }; + config.systemd.services.vaultwarden = mkIf cfg.enable { + gensokyo-zone.sharedMounts.vaultwarden.path = mkDefault cfg.config.DATA_FOLDER; + }; + config.users = mkIf cfg.enable { + users.vaultwarden.uid = 915; + groups.vaultwarden.gid = config.users.users.vaultwarden.uid; + }; + config.networking.firewall = mkIf cfg.enable { + interfaces.lan.allowedTCPPorts = [ + cfg.port + (mkIf (cfg.websocketPort != null) cfg.websocketPort) + ]; + }; + config.sops.secrets = let + sopsFile = mkDefault ./secrets/vaultwarden.yaml; + owner = "vaultwarden"; + in { + vaultwarden-database-url = mkIf (!postgresql.enable) { + inherit sopsFile owner; + }; + vaultwarden-admin-token = mkIf enableAdmin { + inherit sopsFile owner; + }; + }; +} diff --git a/systems/hakurei/nixos.nix b/systems/hakurei/nixos.nix index 1a330b1b..3cdcd158 100644 --- a/systems/hakurei/nixos.nix +++ b/systems/hakurei/nixos.nix @@ -32,6 +32,7 @@ in { nixos.access.mosquitto nixos.access.gensokyo nixos.access.keycloak + nixos.access.vaultwarden nixos.access.vouch nixos.access.freeipa nixos.access.freepbx @@ -112,6 +113,14 @@ in { virtualHosts.keycloak'local.allServerNames ]; }; + bw = { + inherit (nginx) group; + domain = virtualHosts.vaultwarden.serverName; + extraDomainNames = mkMerge [ + virtualHosts.vaultwarden.otherServerNames + virtualHosts.vaultwarden'local.allServerNames + ]; + }; home = { inherit (nginx) group; domain = virtualHosts.home-assistant.serverName; @@ -266,6 +275,11 @@ in { local.denyGlobal = true; ssl.cert.enable = true; }; + vaultwarden = { + # we're not the real bw record-holder, so don't respond globally.. + local.denyGlobal = true; + ssl.cert.enable = true; + }; vouch = { ssl.cert.enable = true; }; diff --git a/systems/keycloak/default.nix b/systems/keycloak/default.nix index 28166e86..04a11be9 100644 --- a/systems/keycloak/default.nix +++ b/systems/keycloak/default.nix @@ -12,6 +12,7 @@ _: { sshd.enable = true; keycloak.enable = true; vouch-proxy.enable = true; + vaultwarden.enable = true; }; }; } diff --git a/systems/keycloak/lxc.json b/systems/keycloak/lxc.json index 277ebf9b..0c037b58 100644 --- a/systems/keycloak/lxc.json +++ b/systems/keycloak/lxc.json @@ -1,6 +1,7 @@ { "lxc": { "lxc.mount.entry": [ + "/rpool/shared/vaultwarden mnt/shared/vaultwarden none bind,optional,create=dir", "/dev/net/tun dev/net/tun none bind,optional,create=file" ], "lxc.idmap": [ diff --git a/systems/keycloak/nixos.nix b/systems/keycloak/nixos.nix index bd171450..e5c2cac0 100644 --- a/systems/keycloak/nixos.nix +++ b/systems/keycloak/nixos.nix @@ -12,6 +12,7 @@ nixos.reisen-ct nixos.ipa nixos.keycloak + nixos.vaultwarden nixos.cloudflared nixos.vouch ]; @@ -27,6 +28,8 @@ inherit (keycloak'system.exports.services) keycloak; vouch'system = access.systemForServiceId "login"; inherit (vouch'system.exports.services) vouch-proxy; + vaultwarden'system = access.systemForServiceId "bw"; + inherit (vaultwarden'system.exports.services) vaultwarden; in { "${keycloak.id}.${config.networking.domain}" = let portName = @@ -52,6 +55,12 @@ service = vouch-proxy; }; }; + "${vaultwarden.id}.${config.networking.domain}" = { + service = access.proxyUrlFor { + system = vaultwarden'system; + service = vaultwarden; + }; + }; }; }; }; diff --git a/systems/reisen/setup.sh b/systems/reisen/setup.sh index 9ee83b1d..88d1546e 100644 --- a/systems/reisen/setup.sh +++ b/systems/reisen/setup.sh @@ -160,6 +160,7 @@ mkshared plex 100193 100193 0750 mkshared postgresql 100071 100071 0750 mkshared unifi 100990 100990 0750 mkshared zigbee2mqtt 100317 100317 0700 +mkshared vaultwarden 100915 100915 0750 mkshared minecraft 100913 100913 0750 mkshared minecraft/bedrock 100913 100913 0750 diff --git a/tf/cloudflare_records.tf b/tf/cloudflare_records.tf index 801fd254..09abe0fc 100644 --- a/tf/cloudflare_records.tf +++ b/tf/cloudflare_records.tf @@ -18,6 +18,7 @@ module "hakurei_system_records" { "krb5", "ipa", "ipa-cock", + "bw", "unifi", "pbx", "smb", diff --git a/tf/cloudflare_tunnels.tf b/tf/cloudflare_tunnels.tf index a2aa0bff..4b38d5cb 100644 --- a/tf/cloudflare_tunnels.tf +++ b/tf/cloudflare_tunnels.tf @@ -44,6 +44,7 @@ module "keycloak" { subdomains = [ "sso", "login", + "bw", ] }