Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backup postgres and mattermost to s3 #7

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
]
++ (with pkgs; [
age
age-plugin-yubikey
opentofu
nomad
gh
Expand Down
26 changes: 25 additions & 1 deletion hosts/ares.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{ lib, profiles, ... }:
{
lib,
config,
profiles,
secretsDir,
...
}:
let
mattermost-dirs = [
"config"
Expand Down Expand Up @@ -30,6 +36,24 @@ in
x: "d /var/lib/mattermost/${x} 0750 2000 2000"
);

dsekt.restic = {
backupPrepareCommand = ''
sudo -u postgres pg_dumpall > /root/postgres_dump.sql
'';

paths = [
"/root/postgres_dump.sql"
"/var/lib/mattermost"
];

targets.s3 = {
repository = "s3:https://s3.amazonaws.com/dsekt-restic-ares";
credentialsEnvFile = config.age.secrets.restic-s3-creds-ares.path;
};
};

age.secrets.restic-s3-creds-ares.file = secretsDir + "/restic-s3-creds-ares.env.age";

# Change this if you want to lose all data on this machine!
system.stateVersion = "23.11";
}
115 changes: 115 additions & 0 deletions modules/restic.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
config,
lib,
secretsDir,
...
}:
{
options.dsekt.restic = {
paths = lib.mkOption {
type = with lib.types; listOf singleLineStr;
default = [ ];
example = [
"/home"
"/var/lib/service"
];
description = lib.mdDoc ''
Paths to back up. If empty, no backups are performed.
'';
};

backupPrepareCommand = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = lib.mdDoc ''
Script to run before starting the backup process.
'';
};

targets = lib.mkOption {
default = { };
description = lib.mdDoc ''
Restic repositories to back up to. If empty, no backups are performed.
'';
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
repository = lib.mkOption {
type = lib.types.singleLineStr;
example = "s3:https://s3.amazonaws.com/bucket-name";
description = lib.mdDoc ''
Restic repository to back up to.
'';
};

credentialsEnvFile = lib.mkOption {
type = lib.types.singleLineStr;
example = "/etc/restic/creds";
description = lib.mdDoc ''
Credentials to authenticate with. Must be in env-file format,
understandable by systemd.

Example for S3 (`s3:https://s3.amazonaws.com/bucket-name`):
```
AWS_DEFAULT_REGION=eu-north-1
AWS_ACCESS_KEY_ID=something
AWS_SECRET_ACCESS_KEY=something-else
RESTIC_PASSWORD=secret
```

Example for restic REST server (`rest:https://example.com/path`):
```
RESTIC_PASSWORD=secret
RESTIC_REST_USERNAME=client-hostname
RESTIC_REST_PASSWORD=password123
```
(If server is configured to use private repositories,
`RESTIC_REST_USERNAME` must match the path provided.)
'';
};

timer = lib.mkOption {
type = lib.types.singleLineStr;
default = "03:42";
example = "daily UTC"; # midnight
description = lib.mdDoc ''
When to run the backup. See {manpage}`systemd.timer(7)` § Calendar Events.
'';
};
};
}
)
);
};
};

config =
let
cfg = config.dsekt.restic;
in
lib.mkIf (builtins.length cfg.paths != 0) {

services.restic.backups = builtins.mapAttrs (name: target: {
inherit (cfg) paths backupPrepareCommand;
inherit (target) repository;

initialize = true;
timerConfig = {
OnCalendar = target.timer;
RandomizedDelaySec = 600; # 10min
Persistent = true;
};

passwordFile = "/no-repo-password-set"; # environmentFile (hopefully) overrides this
environmentFile = target.credentialsEnvFile;
pruneOpts = [
"--keep-within-daily 7d"
"--keep-within-weekly 5w"
"--keep-within-monthly 12m"
"--keep-within-yearly 10y"
];
}) cfg.targets;
};
}
2 changes: 1 addition & 1 deletion profiles/users.nix
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@
];
shell = pkgs.bash;
};
users.groups.deploy = {};
users.groups.deploy = { };
}
Binary file added secrets/restic-s3-creds-ares.env.age
Binary file not shown.
3 changes: 3 additions & 0 deletions secrets/secrets.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ in

# `CLOUDFLARE_DNS_API_TOKEN=...`
"cloudflare-dns-api-token.env.age".publicKeys = sysadmins ++ [ ares ];

# `AWS_DEFAULT_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `RESTIC_PASSWORD`
"restic-s3-creds-ares.env.age".publicKeys = sysadmins ++ [ ares ];
}