From 8129b26c4c20849bd9898fbb944234e99cc8e308 Mon Sep 17 00:00:00 2001 From: Jeltz Date: Mon, 7 Apr 2025 20:24:53 +0200 Subject: [PATCH] add backups + fix appservice-irc media proxy --- hive.nix | 7 +- profiles/backups.nix | 152 +++++++++++++++++++++++++++++++ profiles/discourse.nix | 6 ++ profiles/gitlab.nix | 5 + profiles/grafana.nix | 5 + profiles/indico.nix | 9 ++ profiles/irc-bot.nix | 7 +- profiles/matrix-server.nix | 6 ++ profiles/monitoring/default.nix | 7 +- profiles/sysadmin.nix | 3 +- profiles/telegram-bot.nix | 6 +- profiles/vaultwarden.nix | 7 ++ secrets/borgmatic-passphrase.age | Bin 0 -> 2642 bytes secrets/secrets.nix | 2 + 14 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 profiles/backups.nix create mode 100644 secrets/borgmatic-passphrase.age diff --git a/hive.nix b/hive.nix index 410cf9e..99a80c7 100644 --- a/hive.nix +++ b/hive.nix @@ -17,7 +17,6 @@ let nodeNixpkgs = { # FIXME discourse est cassé en unstable pendragon = nixpkgs2411; - martagon = nixpkgs2411; }; in { @@ -31,10 +30,11 @@ in # FIXME nixpkgs.config.permittedInsecurePackage = [ "olm-3.2.16" ]; - defaults = { pkgs, lib, ... }: { + defaults = { name, pkgs, lib, ... }: { imports = [ ./profiles/sysadmin.nix ./profiles/infra.nix + ./profiles/backups.nix ./profiles/prometheus-node-exporter.nix #./profiles/ldap.nix "${src.agenix}/modules/age.nix" @@ -52,6 +52,7 @@ in networking.nftables.enable = true; infra.enabled = true; + backups.enable = true; # Enable system diffs. system.activationScripts.system-diff = { @@ -69,7 +70,7 @@ in time.timeZone = "Europe/Paris"; }; - vogon = { ... }: { + vogon = { pkgs, ... }: { deployment.tags = [ "hypervisor" ]; networking.hostId = "1751e2a7"; diff --git a/profiles/backups.nix b/profiles/backups.nix new file mode 100644 index 0000000..7f757a6 --- /dev/null +++ b/profiles/backups.nix @@ -0,0 +1,152 @@ +{ pkgs, config, lib, name, ... }: + +let + cfg = config.backups; + secrets = config.age.secrets; + postgresql = config.services.postgresql.package; + additionalPackages = [ + pkgs.coreutils + postgresql + pkgs.sudo + pkgs.sqlite + ]; + remotes = { + memoragon = { + host = "memoragon.infra.federez.net"; + user = "borgmatic"; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINdqX4I1JyvhC6dySHLnW1IioYk1ZqltFlbDCygozrWx"; + path = "./${name}"; + }; + harpagon = { + host = "harpagon.infra.federez.net"; + user = "borgmatic"; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH1qDEAEJZ0qDRUq4yeHar5LKFTtsvHJIt2a54TBB/Lz"; + path = "./${name}"; + }; + }; +in +{ + options.backups = lib.mkOption { + type = lib.types.submodule { + options = { + enable = lib.mkEnableOption "Sauvegardes"; + directories = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + description = '' + Répertoires à sauvegarder. + ''; + }; + # FIXME add user ? + postgresqlDatabases = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + Nom des bases de données PostgreSQL à sauvegarder. + ''; + }; + sqliteDatabases = lib.mkOption { + type = lib.types.attrsOf lib.types.path; + default = { }; + description = '' + Chemins des bases de données SQLite à sauvegarder. + ''; + }; + }; + }; + description = '' + Configuration des sauvegardes. + ''; + }; + + config = lib.mkIf cfg.enable { + age.secrets.borgmatic-passphrase = { + file = ../secrets/borgmatic-passphrase.age; + }; + + systemd.services.borgmatic = { + path = additionalPackages; + serviceConfig = { + LoadCredential = "pass:${secrets.borgmatic-passphrase.path}"; + ExecStartPre = '' + ${lib.getExe' pkgs.borgmatic "borgmatic"} init --encryption repokey + ''; + # TODO Remove once all hosts are usign NixOS 25.05+ + NoNewPrivileges = false; + CapabilityBoundingSet = "CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID"; + }; + }; + + environment.systemPackages = + let + # KillMode=process is required to allow the background SSH session + # to persist when FUSE mounting a remote repository + binPath = lib.makeBinPath additionalPackages; + borgmaticWithCreds = pkgs.writeScriptBin "borgmatic-with-creds" '' + #!${pkgs.runtimeShell} + systemd-run --quiet --wait --collect --pipe --pty \ + --service-type=exec \ + --uid=root --gid=root \ + --property=KillMode=none \ + --property=LoadCredential=pass:${secrets.borgmatic-passphrase.path} \ + --property=Environment=${binPath} \ + -- \ + ${lib.getExe' pkgs.borgmatic "borgmatic"} "$@" + ''; + in + [ borgmaticWithCreds ]; + + services.openssh.knownHosts = lib.mapAttrs + (_: remote: { + hostNames = [ remote.host ]; + publicKey = remote.publicKey; + }) + remotes; + + services.borgmatic = let + version = pkgs.borgmatic.version; + hasCredSupport = builtins.compareVersions version "1.9.10" >= 0; + encryption = if hasCredSupport then + { encryption_passphrase = "{credential systemd pass}"; } + else + { encryption_passcommand = "cat \${CREDENTIALS_DIRECTORY}/pass"; }; + pgCommand = exe: "${lib.getExe' pkgs.sudo "sudo"} -u postgres ${lib.getExe' postgresql exe}"; + in { + enable = true; + # $CREDENTIALS_DIRECTORY does not exist when the config check is run + enableConfigCheck = hasCredSupport; + settings = { + source_directories = cfg.directories; + repositories = lib.mapAttrsToList + (name: remote: { + label = name; + path = "ssh://${remote.user}@${remote.host}/${remote.path}"; + }) + remotes; + # Required for databases hooks + read_special = true; + # FIXME pertinent de réutiliser celle-là ? + ssh_command = "ssh -i /etc/ssh/ssh_host_ed25519_key"; + keep_daily = 26; + keep_weekly = 20; + keep_monthly = 12; + # add checks + postgresql_databases = map + (name: { + inherit name; + username = "postgres"; + pg_dump_command = if name == "all" then + pgCommand "pg_dumpall" + else + pgCommand "pg_dump"; + pg_restore_command = pgCommand "pg_restore"; + psql_command = pgCommand "psql"; + }) + cfg.postgresqlDatabases; + sqlite_databases = lib.mapAttrsToList + (name: path: { inherit name path; }) + cfg.sqliteDatabases; + } // encryption; + }; + }; +} \ No newline at end of file diff --git a/profiles/discourse.nix b/profiles/discourse.nix index c2d02cd..75098d5 100644 --- a/profiles/discourse.nix +++ b/profiles/discourse.nix @@ -1,5 +1,6 @@ { config, lib, pkgs, ... }: let + cfg = config.services.discourse; discourse-shared-edits = pkgs.discourse.mkDiscoursePlugin { name = "discourse-shared-edits"; src = pkgs.fetchFromGitHub { @@ -24,6 +25,11 @@ in }; }; + backups = { + directories = [ "/var/lib/discourse" ]; + postgresqlDatabases = [ cfg.database.name ]; + }; + services.postgresql.package = pkgs.postgresql_13; services.discourse = { diff --git a/profiles/gitlab.nix b/profiles/gitlab.nix index 36f83af..60c6bb2 100644 --- a/profiles/gitlab.nix +++ b/profiles/gitlab.nix @@ -17,6 +17,11 @@ in gitlab-ldap-password = ../secrets/gitlab-ldap-password.age; }; + backups = { + directories = [ cfg.statePath ]; + postgresqlDatabases = [ cfg.databaseName ]; + }; + services.gitlab = { enable = true; databasePasswordFile = secrets.gitlab-db-password.path; diff --git a/profiles/grafana.nix b/profiles/grafana.nix index 6657b09..093b7c9 100644 --- a/profiles/grafana.nix +++ b/profiles/grafana.nix @@ -51,6 +51,11 @@ in { }; }; + backups = { + directories = [ cfg.dataDir ]; + sqliteDatabases.grafana = cfg.settings.database.path; + }; + services.grafana = { enable = true; diff --git a/profiles/indico.nix b/profiles/indico.nix index cbd4021..f71f1ef 100644 --- a/profiles/indico.nix +++ b/profiles/indico.nix @@ -5,6 +5,10 @@ ... }: + +let + cfg = config.services.indico; +in { imports = [ ../modules/indico.nix @@ -26,6 +30,11 @@ }; }; + backups = { + directories = [ cfg.stateDir ]; + postgresqlDatabases = [ cfg.user ]; + }; + services.indico = { enable = true; nginx.domain = "events.federez.net"; diff --git a/profiles/irc-bot.nix b/profiles/irc-bot.nix index 09d56f2..5721e0a 100644 --- a/profiles/irc-bot.nix +++ b/profiles/irc-bot.nix @@ -4,6 +4,8 @@ let bindPort = cfg.settings.ircService.mediaProxy.bindPort; upstreamUrl = "127.0.0.1:${toString bindPort}"; in { + backups.directories = [ "/var/lib/matrix-appservice-irc" ]; + services.nginx = { enable = true; recommendedProxySettings = true; @@ -26,7 +28,10 @@ in { homeserver.url = "https://matrix.federez.net"; homeserver.domain = "federez.net"; - ircService.mediaProxy.publicUrl = "https://matrix-irc.federez.net/media"; + ircService.mediaProxy = { + publicUrl = "https://matrix-irc.federez.net/"; + ttlSeconds = 3153600000; # 100 ans + }; ircService.servers."irc.rezosup.org" = { name = "RezoSup"; diff --git a/profiles/matrix-server.nix b/profiles/matrix-server.nix index e2d4de8..fa6152d 100644 --- a/profiles/matrix-server.nix +++ b/profiles/matrix-server.nix @@ -1,5 +1,6 @@ { pkgs, lib, config, ... }: let + cfg = config.services.matrix-synapse; fqdn = "matrix.federez.net"; baseUrl = "https://${fqdn}"; in { @@ -14,6 +15,11 @@ in { LC_CTYPE = "C"; ''; + backups = { + directories = [ cfg.dataDir ]; + postgresqlDatabases = [ "matrix-synapse" ]; + }; + # Surgical operations for various databases. environment.systemPackages = [ pkgs.matrix-synapse pkgs.sqlite ]; services.nginx = { diff --git a/profiles/monitoring/default.nix b/profiles/monitoring/default.nix index 22c9cbe..4bf3941 100644 --- a/profiles/monitoring/default.nix +++ b/profiles/monitoring/default.nix @@ -1,5 +1,6 @@ -{ lib, config, infra, ... }: +{ lib, config, network, ... }: let + cfg = config.services.victoriametrics; mkScrapeConfig = name: path: port: targets: { job_name = name; metrics_path = path; @@ -17,7 +18,7 @@ let nodePort = 9100; vmPort = 8428; nodesConfig = mkScrapeConfig "node" "/metrics" nodePort - (lib.attrsets.mapAttrsToList (n: _: n) infra.nodes); + (lib.attrsets.mapAttrsToList (n: _: n) network.infra.nodes); critical = { severity = "critical"; }; warning = { severity = "warning"; }; importRules = path: let @@ -32,6 +33,8 @@ in { file = ../../secrets/alertbot-matrix-password.age; }; + backups.directories = [ "/var/lib/${cfg.stateDir}" ]; + services.alertbot = { enable = true; listenPort = 8081; diff --git a/profiles/sysadmin.nix b/profiles/sysadmin.nix index 3e3adf4..ddfc053 100644 --- a/profiles/sysadmin.nix +++ b/profiles/sysadmin.nix @@ -6,6 +6,8 @@ ../pubkeys/jeltz.keys ]; + backups.directories = [ "/root" ]; + nix.package = lib.mkDefault pkgs.lix; users.motd = (builtins.readFile ./federez.motd); @@ -49,7 +51,6 @@ "net.ipv4.tcp_fastopen" = 3; }; - environment.systemPackages = [ pkgs.htop pkgs.kitty.terminfo diff --git a/profiles/telegram-bot.nix b/profiles/telegram-bot.nix index a776c4a..5c8854d 100644 --- a/profiles/telegram-bot.nix +++ b/profiles/telegram-bot.nix @@ -1,4 +1,8 @@ { config, lib, ... }: { + backups.sqliteDatabases = { + mautrix-telegram = "/var/lib/mautrix-telegram/mautrix-telegram.db"; + }; + systemd.services.mautrix-telegram.serviceConfig.WorkingDirectory = lib.mkForce "/var/lib/mautrix-telegram"; age.secrets.mautrix-telegram.file = ../secrets/mautrix-telegram.age; services.mautrix-telegram = { @@ -16,7 +20,7 @@ domain = "federez.net"; }; bridge = { - bridge_notices.exceptions = [ "@klingon:federez.net" ]; + bridge_notices.exceptions = [ "@alertbot:federez.net" ]; relay_user_distinguishers = [ "🔴" "🟠" "🟡" "🟢" "🔵" "🟣" "🟤" "⚫" "⚪" "🟧" "🟨" "🟩" "🟦" "🟪" "🟫" "⬜" "🔶" "🔷" ]; displayname_preference = [ "username" diff --git a/profiles/vaultwarden.nix b/profiles/vaultwarden.nix index 1c20d6e..ab20601 100644 --- a/profiles/vaultwarden.nix +++ b/profiles/vaultwarden.nix @@ -2,6 +2,13 @@ age.secrets.vaultwarden-secrets.file = ../secrets/vaultwarden-secrets.age; networking.firewall.allowedTCPPorts = [ 80 443 ]; + backups = { + directories = [ "/var/lib/bitwarden_rs" ]; + sqliteDatabases = { + vaultwarden = "/var/lib/bitwarden_rs/db.sqlite3"; + }; + }; + services.nginx = { enable = true; recommendedTlsSettings = true; diff --git a/secrets/borgmatic-passphrase.age b/secrets/borgmatic-passphrase.age new file mode 100644 index 0000000000000000000000000000000000000000..9091daaf2c59b35aa1d57310c66ae895a24b6ce3 GIT binary patch literal 2642 zcmZXVyUO$m8HE+Q6kdRc3@Qpc{7y1SCYi!tlF2!fWO6>(nDhC3ngn6Dij9R>2-Y@U zg_oeM3Mz+eiqx}+gI@LKCHFgAWJ?ZZ8YxvTy*Vsx-mPiF!15yX`1p6NqoUD z_;%u6?A0evzIPc-*wq7*+NvJ*bIRLh-$JpPCey{SmRIyxIj({14e+;z6TTkzhPVD=lgU^-P0mlmk8Id?#WipoGLAfS60c7l@)7CCWx0*e&GfqXk{P zr#9a0_P`hmR@(C{5Au5&g)B4K3=^HgPOr>!x#0s>)KKx*=#2w9p~H zHNvi*-R?cDqe*StPH$&lKzPqb#%k@rZLX+9V3{8D_h2e>($i%r^{?}hl?0F%d@PD! zn?^Eel)5vsW131Y?5VUmCr617uUaYL`*3*gY0)Dp0`0`WtR>r884lE-V1&j;YXS-9 zWx&@5hk0TGHZ3cG{_W_1B~3*@AZZbD2as zf}^q%dXai-Bp}8Bk1=uiLZxA3taV6x39%v4`#$$Q%acjY0J2jVO2Xx8ppdNtpw95 zc}~5zE(uIn5~Du0sCX~qW^(su%eyFBWXS_pyjEpUvB9xqyy2P8Opa4_E+*OjwD+jon&X~8xmRz>Z7_+LOvfEpFV>ZMG)DpiOX_*# z%*+-oK?W&ISZsS-MKsUrV3e$RO(LDsmIc4`H~y*jV$a?R&JY&Vbt&q&124x$Ilf)B zV$?QHE?6B~VabNPW6-s-XuUc-#K^LA9|`Q}a^=*n4s~*A-tIw9>+ zNU42h`?D=QubUQWroJm^?L8$S|;TV;0EF-pLXc8z~^99pn z4zjEZ>fdS{#MU$v3k@p{hNeCISgj^ncp_ zl2krGrrrR$9x0AA6I3NIHBJpbQWHYoJ=A+qc+jFVRKQf8t%&9N(M^b~&<+vsKI~&i zGnX0xM22|cc;yG#OQQIs#thk6=Md70*6CSt?fTYy*+s2ULp8lrrEKfU+H9+GKyNl$ z9w6@VfFF$4DW$&Uq*a(Ebx}x62qHGuMtj(JXC>HiDF98AcD}F+bW1C=v5U#7yGS$wgYwqGIzMT zb-CkQ2J-Y$%z-}Ki8tqckqFeH4?Hs5J2|4uCUK7U3g} zL~8qzT{Ak~T9SZ*B=7t{wMmcq>aH4?4O6)-77B%p`$Q29N6c@5tu9*x(p2GU(((8P! zGLkG||6&h~OYH~R!ZqH|6i5YP)3A6Lk4_He^;jN^(kC4<0Iy;NxPu$JGwOZ%OOvKX3PBXA=z{Hkq043C7F-;kV!Y!_U9= z?XOUOZGQiQzyJHw-~9TE@E1P$hW4Ky|MHvP``HhF^s7GyKl%9Oe|~@Y7yg%zAOH5H YKehi5e)q|z&+FI!_|xte-}>r*0W*VL2><{9 literal 0 HcmV?d00001 diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 301119f..30122d9 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -27,6 +27,7 @@ let grafana-admins = active-admins; alertbot-admins = active-admins; gitlab-admins = active-admins; + backups-admins = active-admins; servers = [ estragon wagon @@ -62,4 +63,5 @@ in "gitlab-db-password.age".publicKeys = [ aragon ] ++ gitlab-admins; "gitlab-initial-root-password.age".publicKeys = [ aragon ] ++ gitlab-admins; "gitlab-ldap-password.age".publicKeys = [ aragon ] ++ gitlab-admins; + "borgmatic-passphrase.age".publicKeys = servers ++ backups-admins; }