feat(backups): restic

This commit is contained in:
arcnmx 2024-09-27 18:35:34 -07:00
parent 455aca9312
commit 760fddae16
6 changed files with 275 additions and 2 deletions

12
nixos/backups/default.nix Normal file
View file

@ -0,0 +1,12 @@
{config, lib, ...}: let
in {
users = {
groups.backups = {
gid = config.users.users.backups.uid;
};
users.backups = {
uid = 919;
group = "backups";
};
};
}

89
nixos/backups/restic.nix Normal file
View file

@ -0,0 +1,89 @@
{config, systemConfig, lib, ...}: let
inherit (lib.modules) mkIf mkMerge mkDefault;
inherit (lib.attrsets) mapAttrs' mapAttrsToList nameValuePair;
inherit (lib.lists) concatMap;
inherit (lib.strings) replaceStrings;
inherit (config.sops.secrets) restic-shared-repo-b2 restic-shared-password restic-shared-env-b2;
group = "backups";
# TODO: this properly as a module or something
sharedServices = {
hass.config = config.services.home-assistant;
grocy.config = config.services.grocy;
barcodebuddy.config = config.services.barcodebuddy;
kanidm = {
config = config.services.kanidm;
enable = config.services.kanidm.enableServer;
};
mosquitto.config = config.services.mosquitto;
plex = {
config = config.services.plex;
compression = "auto";
};
postgresql = {
# TODO: synchronize with postgresqlBackup service via flock or After=
config = config.services.postgresql;
subpath = "postgresql/dump";
};
taskchampion.config = config.services.taskchampion-sync-server;
unifi = {
config = config.services.unifi;
subpath = "unifi/data/backup";
};
zigbee2mqtt.config = config.services.zigbee2mqtt;
vaultwarden.config = config.services.vaultwarden;
"minecraft/bedrock".config = config.services.minecraft-bedrock-server;
minecraft-java = {
config = config.services.minecraft-java-server;
subpath = "minecraft/java/marka-server";
};
};
in {
services.restic.backups = let
isBackup = config.networking.hostName == "hakurei";
mkSharedPath = subpath: "/mnt/shared/${subpath}";
mkBackupB2 = name: subpath': { config, enable ? config.enable, user ? config.user or null, subpath ? subpath', path ? mkSharedPath subpath, compression ? "max" }: let
tags = [
"infra"
"shared-${name}"
"system-${systemConfig.name}"
];
in mkIf (enable || isBackup) {
user = mkIf (enable && user != null) user;
repositoryFile = restic-shared-repo-b2.path;
passwordFile = restic-shared-password.path;
environmentFile = restic-shared-env-b2.path;
paths = [path];
extraBackupArgs = mkMerge [
(mkIf (compression != "auto") [
"--compression" compression
])
(concatMap (tag: ["--tag" tag]) tags)
];
timerConfig = {
OnCalendar = "03:30";
Persistent = true;
RandomizedDelaySec = "4h";
};
};
backups = mapAttrs' (subpath: service: let
name = replaceStrings [ "/" ] [ "-" ] subpath;
in nameValuePair "${name}-b2" (mkBackupB2 name subpath service)) sharedServices;
in backups;
users.groups.${group} = {
members = mapAttrsToList (_: { config, enable ? config.enable, user ? config.user or null, ... }: mkIf (enable && user != null) user) sharedServices;
};
sops.secrets = let
sopsFile = mkDefault ../secrets/restic.yaml;
mode = "0640";
in {
restic-shared-env-b2 = {
inherit group mode;
};
restic-shared-password = {
inherit sopsFile group mode;
};
restic-shared-repo-b2 = {
inherit sopsFile group mode;
};
};
}

View file

@ -38,6 +38,19 @@ in {
}
];
};
services.postgresqlBackup = {
enable = mkDefault cfg.enable;
compression = mkDefault "none";
location = mkDefault "/mnt/shared/postgresql/dump";
startAt = mkDefault "*-*-* 00:30:00";
databases = [
#"hass" # only used for recorder (entity state history) module, so just a useless large cache?
"invidious"
#"dex"
"keycloak"
"vaultwarden"
];
};
systemd = {
services.postgresql = mkIf cfg.enable {

157
nixos/secrets/restic.yaml Normal file
View file

@ -0,0 +1,157 @@
restic-shared-repo-b2: ENC[AES256_GCM,data:u38WuYb62lp975YZ/gromxWx42iWOSKzfvMaPYQ6mFQ4SQTw0vYLglHoZbzT4j3NFK/jaeLmD/g1G1G7,iv:ES9OFQLKMQi/JHiCPFV3HrHyDmZLSPIon3Z6TFkrsNg=,tag:TTg/ThCEnoiFpyRlcD269w==,type:str]
restic-shared-password: ENC[AES256_GCM,data:SfZEXkRx1bJE0aRu7lPiHsM4/zdVAul2xIPWW42cl1yAg3RVDMcp0WVXSPXk1pQR,iv:7QAMSQ37t0QbQaltk/egDlIrTlUgC4leK2lcZQDTSFs=,tag:KUn4AgRAgLthuG7APi1gtw==,type:str]
sops:
shamir_threshold: 1
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age12ze362pu5mza6ef9akrptr7hfe4auaqul4rkta7kyy2tnrstqensgmujeq
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEcFRIUmdWd0N4V1cxTU5q
LzZWWlAvZ0Jhd0JTc2ZrUmR3N3k3ZmxlaEI4Cno3OWYvWml3VnI5SXVQWmtsbUlB
ci9XS2MxWjhXaTF6M25BdXFlNW0yMzgKLS0tIHM4YXdjYTVxNzZqVDVBdWtkYWhj
MkY4SFkxdTZ1MGxKdUxYZityS3JrdmMKB25ME24dJdCOVolBcS/FeAe9XdrUsOMK
bJRatB6nxTlzeczDFd2aWGy+/6Ztxrd9Ilc5eFZgOZHguU48EWXN7A==
-----END AGE ENCRYPTED FILE-----
- recipient: age176uyyyk7veqnzmm8xzwfhf0u23m6hm02cldlfkldunqe6std0gcq6lg057
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBySmVGbHVxRnErVUFWN1Z2
bmRiU3NMUEl4VE1kNEYxUm9HZW9xMVluRHg0CnhpeTR2Rytnck52bjdaWmkzdi8y
UGdIUGIyZzVFR1JWNURhWW9OcitwbE0KLS0tIFRiY3NPd1F3KzA0VnZ4dEplL2Jj
aDFYek9MN0F4b2RSZmR4K1Z6YU5UVWsKZCbI2JNlgX4CxQ9Y5JhddhiPnTEuCE3T
ao7iReVCoeCMgc6Kq93VzMsWZQj3kgBlR/XuZSaCfMgtmG10p6p8oQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age15hmlkd9p5rladsjzpmvrh6u34xvggu9mzdsdxdj3ms43tltxeuhq4g7g9k
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHQlFsZHRyMk1zeEFOWFl5
dXVqV0Z4STM3M3V6cWJDamNTc0JuNDVrdkQwCjZOSkRNcUV6c1ljRnhVR3BvZ2Ur
VGdoUXN0WTFiQzNJQmZYVU4xOEk0Z28KLS0tIGc1SGFzOTRCWUdxblpXYmZLVjk3
amNyOTZwTEdZZ21XblJlNjdrcEZTUVEKHPZSpWRNuLpzE+SxZeiRrfvIAWe76A8K
oqQbOMOWP4+tCtwVUcO/UcmcYQaF7E5XGpqf3jE4W4fOmmjDWm+6vQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age10t6kc5069cyky929vvxk8aznqyxpkx3k5h5rmlyz83xtjmr22ahqe8mzes
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0L1BGdFlxOHdid2RZbGND
NC8yRy9oYmNkNDR2Nkd1SUQxVG9XeUl1dDJZCll4d1VRRjRNanBXRXM5aFpJNWVF
RUtoMitZS1hLdkJjSnNaMmhCcktCd0EKLS0tIG9MSDMzQ2pSUHdTWDZsQ2UrR1pm
TXc2RWJlMDFkZE1Lc1FBK3U1M240Q3cKwzof0LudBd3SH4cxgZLxg4tB19qSho1q
IbziETKVChcokhwxLOrrFfdhQirRN4lj11Db4uxPuCyAmjxWGSzBVA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1a2quf2ekkj94ygu7wgvhrvh44fwn32c0l2cwvgvjh23wst90s54szdsvgr
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxTmJsZ2JYZVNBb3NsQ2ZL
SitaRU9YbG5pZjdtdUdLckFBcnY0TWhTK2xFCmZ2MTdDOVpkTFlTalRKV0JtR210
WjJUQUQ2VzFLbWRIbTVDZWFsOThwYW8KLS0tIC9Lamt3MGtuQVRjR3BYM1kwSHgv
dDVIL3ZLS1ZmQkNZb0kyS2crNVJBN0kKgKng9O4aguLD6Ygkmj6V/v4XeSVjiOiH
pJOhw8rsvefkPnT2WiB2wshoS6fPDpmn1WY3RPXWQDzztOQUmJzheg==
-----END AGE ENCRYPTED FILE-----
- recipient: age16klpkaut5759dut8mdm3jn0rnp8w6kxyvs9n6ntqrdsayjtd7upqlvw489
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjL3duZENkRVJxNHdzYWxP
WW9CSzJBbWhtbE9aVGhuRytBc1J0OTR5SlJjCjh3K0J6bnpCc1dKMVRKcUUxNnFt
K1h5eWJOVC9GajZ5TUZSVEtSbWJHNDgKLS0tIGFURVFwdkE0UllFcTFuRy8wQXlo
dnhPMWZmMVV2Nko3WXdJWUlxTUx6RGMKtPOaGa+mKDMHRfcCy4jqqtCfNC6SiAJN
5DzbQW7lGOtz0Sk4PcLUkukg7Go4/PkPtKF459rajSMF+Fp3yO0y6A==
-----END AGE ENCRYPTED FILE-----
- recipient: age1xg6zm9t25wjakljm54m38pjdr9q53jysdcl82r5xwkrn0cgyuvvsuh63eh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2RmtrUmV1NFpHYm14cXJm
TlZQZUwrcURJdlhsVmo1UmpRK1pkM0Rvd3lvCmIrR1ZRRlJ0RUMxbnpvbFExTjg0
dnE1WEJCWEhyWERWRkFMK0Vtd3UwcW8KLS0tIE9rK2Z4RkpTdTc4QkJKZlJ1NTc4
c3BSVTJqL1NUc2hXTnBQYm45UGZja1UKahunBqn7PbhnRkO2F3h4J7/gpjppiVG6
QaTpaMa/p/YdvQifj+EFUEE0EKZV5ddI0bydiapqq3mDatjfAAf4dw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ktmx2szedfnpe5xumnzs8vkk0ffqgga6ved3drtksg9pye6ndsnsnqq488
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1Lyt5US9lV0lpYjhjWEZU
VzlFUStIQytmYmdycUVZS2xYRXI5cG5MK2dRCkNBRGpCeThSbTMvOWpxZGtoeXZt
VVp1ZW15czlLeHNrOCtTOENtUzVpZ0kKLS0tIEV0dTRNOVJMZHJ1OERwNTZTcndN
OFY4U3IvbDdyWEowdnJkUXd3eEh0SzQKnY79a15VJg96V2kZlr3vp2su84ed/NLM
bXUzbSiM+2hAK+GvcVw1jtHEzmy+iHln44mOiiwxFdCwR1ANq/iUHQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1fjcafp0j45sz03zq5srnxyq2mujndmn25vceg3wj2cgzymqm73ssmhdgku
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1azc5Q3kzQ3VEQjZ4WDhm
Y2dZOUNlYmtNd04vSGtFNkhwbUlpYThyTUNJCkphRHJGRmZzVjJiejEyS05XOVFk
N1NsVmlpVGQrbVV3SVNiTUYzS0RoQUEKLS0tIHhOV1dMVTAzbTNPUUVWZWFWZ0Mx
N2g5V3NycnlsV2VEQ2c5NEVrbTNjTWsKEOHrYeNSUCE0DulOTnHvXO0hcN3XhDD1
iTJ6tKQoITRAaJ0rtTHJiODfgvY99FFPZlckIIw6M93EWyD81E0d3A==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ehdj6hghtr8sf5s5c03rru4y3a02nwrt694e36tjnd6g7eq4l43qfradn6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBcW02WDIzeEo4SndmZURO
YUhlL1R0YktjOXBMWURMQS9FNGxIdjdPU3l3Ck9MQmNXWEFES0NUcVh6Vkh5TkRh
TEcwdXJ2bVZMT28xTmpJVitFK0dFRlkKLS0tIFhnZlJ1bDRGUWVqSVhIL3JDMFdS
MVJzMFZzYlJ0ZjRha09MR1lMK3VFZk0KXn4BDf0g01sSYSdU3XPeeXUTNJ38Bijp
l7BnqbUxpp1qpX43bEu9iV4z1GNzs3cb27zRbXgpHeBLKW4DUfS4nw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1tkkau8vk5h9dh3kemash4eghn7lk84j0hhpmvvf7j6phgcsm9vmsphv0py
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvM1NVT2pNUENIemFsRDdR
SUdacmVFV3cxVmpTUGhHTFhvZjljVDJodDJrCkczUFNhNlZhdUx6OGFhemNkczhs
S2ZyVm0yMmhlTlZtU2NWRG52Q2lnU1UKLS0tIE5ZcjNmQ1dGYWVZbGt2cnRrUHIr
a2RyL3dLaHp1RWtvaWhKbUw0Sk81WkUKacxUoV8DaHgarccwO0qgpw1P3I7Ga6t4
NRtt5bO7Vw1qSrmeGlOgo1YCvvy99+5J2mEFBZxPB/IyVCg4GLy7ow==
-----END AGE ENCRYPTED FILE-----
- recipient: age16yjxkz4pzuu5qqenmyh9ecwmqkar6ehclvss7wx7mesdntwwy9ys6e7m3c
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPOGphdy94WThWc0JHWjFH
a1prQ056c0xpRXBIU3JqeWMrWlI4bElEcEIwCjQ2MEV1eEMxTUFDNWFoWDAwSXRk
VDNLdVYxQ0UzcVNWSUlSTnl0N0p4d00KLS0tIGlweU9EZjJTUEdWdEZHUE4vY1h3
R0Z1dEFnWndpNE1YQ3Z6NnlFcDlYVUEKmP8XxeQu35Dq555l9e3h2CexKDNXBI+M
SWDobnUMkfzf9E2Znbtf9v/H28AqdDiR9WwHbsawIoJVk2dMWIyc9A==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-09-28T00:55:11Z"
mac: ENC[AES256_GCM,data:GEfVFwn5ifevDhQcQnlhV+F56bajrMqSkP0GjR9c2o4rtfa5JWmvAJnqOJGxOhpeFnZcgUbXqaJt+uLnve8SoKGEb/dMnvbU4oO+mKhH9/aoecAuHfIeHZNPw63p3ncojFTov3U5Z/X/Pw9KaWDqesVtDeN4INizCJSJs29EzrE=,iv:sHbQog8BdbOpYr2v94YjcRm/YbZTbQYjM1aPX2XG1AQ=,tag:zvNNioCKecSCq498q1HRyQ==,type:str]
pgp:
- created_at: "2024-09-28T00:34:30Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMA82M54yws73UAQ/9FzRSDYFEFqNVkEzgZdRhPl7vf36K0jFMQ+7WBaUsx2TG
y0zMEWkck0ayJEHqBHPIsbVOeh+aOLw0LCMfKxu75ZWLtUorVMLD84AztdHl8LpL
WntNSYi5iCihHV4i9YYvopInpIL5KRu0QzptoJQQqZwsJHz9gHB5of48icCIfyG0
r19YikLHHhLSy/5fg7TrrqCzuMUE1ufblZiDGXLWfhuUkkdDTomDcNBSn3mu+1qa
oVXK0a/SLIOcXds1uDWjQea/XowGYzZvH2aF/X+U38TitEJ8cx64lDfKagPHwppQ
Oh85LPb9r/5/vuzs3BQ2saFurjGO7zr5qGHjkB3ICXdXxFecdMwZeohUCN5atPUO
GCQGZbqD75WsJsPV9VgeNliqFtvi+Wmo+xRWpqBpFml5iX+SLQ4Klvcg87Fuw79N
QmDdyACdp++NSEvZ3OR0zZPSn62v+ojq9+YhragSB72X17Ufkpfq+a2PRixz82gC
Bh3FN0Z7z2z7+bhaMPAX+O2KlbQqHi5N3tU7yMnD+j4IMl5Xy8NbWc+rbcQQ8ytg
Jn9bSlkjtwuHktnk/be4eKvKkbF0PnmiJufw0Gn+mHoDgekFSl5F0mKpqYDOP6m9
hE0KIN1duXnV3Iyvy7QFWgfv6wv9hCytoSXM4gsBjFgUIOrvMICIab1fHfdzgBvS
XgEDq6HCf/xWkXM5CW1hp2EGGETkjqHoJWQ/XppDtqduGoXv7s9sQOOuDbiUPYFb
ZNkq2Oo4zTpdWUffrjZupxWye58NkG3irIS9buVdVV0NeX6FmDgQJPTIZtIesc8=
=XL7a
-----END PGP MESSAGE-----
fp: CD8CE78CB0B3BDD4
- created_at: "2024-09-28T00:34:30Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQEMA2W9MER3HLb7AQf8DPn5pHq7VRzvpfV0WJq47u91a7Wx4migC+5dF/V/YhHY
1LXJEEUXBfnnhWzFH298rREG6oxNkw305mXpBBnm4gv9qGNPDS1Dmgbg++cJgeCO
+oWrvckn2CzATTazXgfqrMD03bxFCfvqzV+VDxGQ7vB1hwiX39g6aKxe94fKriQ4
CxQFKV72WtllSErJ5Azpa2y0TfaE9M7UbxQVOhawqLersFC7Pj3BXSzGFSOjjRo1
XuV0YWPsIz1h4AMuSkGqPk//VyEj7IAuhQ2oSwmDlZepzvTxBrLvvyr+Eu3OORFi
z6joFIs4EEwFoPT/aLbsLBy7ABaSpXf7Pf8ROVceRdJeAbn1RA/NjY2Q4Q9jJRkT
Hg7iYuOfs8Fty60umO2JeEvb4jAq0s1vT2ErjrHV68SGdeNJczO2fNqNio7ZMeQx
JPvt+uIvxtzHD18MWESMVeT25+qvETo7r4Sn/KtTAQ==
=kJZE
-----END PGP MESSAGE-----
fp: 65BD3044771CB6FB
unencrypted_suffix: _unencrypted
version: 3.9.0