diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2021-10-15 00:59:34 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2021-10-15 23:16:20 +0200 |
commit | bd5c5d4e23ebd3863a960976767ed4a83dfd07fe (patch) | |
tree | 270b468d6445365f99bbf80d5e75b6ce5f92fc42 | |
parent | 042ada3bfc4a139a4bae60d5e5d549e41c02bca4 (diff) | |
download | Nix-bd5c5d4e23ebd3863a960976767ed4a83dfd07fe.tar.gz Nix-bd5c5d4e23ebd3863a960976767ed4a83dfd07fe.tar.zst Nix-bd5c5d4e23ebd3863a960976767ed4a83dfd07fe.zip |
Move backups to flake
-rw-r--r-- | flakes/rsync_backup/flake.nix | 245 | ||||
-rw-r--r-- | modules/default.nix | 2 | ||||
-rw-r--r-- | modules/private/system/backup-2.nix | 20 | ||||
-rw-r--r-- | modules/rsync_backup/default.nix | 262 |
4 files changed, 264 insertions, 265 deletions
diff --git a/flakes/rsync_backup/flake.nix b/flakes/rsync_backup/flake.nix new file mode 100644 index 0000000..6d359e5 --- /dev/null +++ b/flakes/rsync_backup/flake.nix | |||
@@ -0,0 +1,245 @@ | |||
1 | { | ||
2 | description = "Rsync backups"; | ||
3 | |||
4 | outputs = { self }: { | ||
5 | nixosModule = { lib, pkgs, config, ... }: { | ||
6 | options.services.rsyncBackup = { | ||
7 | mountpoint = lib.mkOption { | ||
8 | type = lib.types.path; | ||
9 | description = "Path to the base folder for backups"; | ||
10 | }; | ||
11 | profiles = lib.mkOption { | ||
12 | type = lib.types.attrsOf (lib.types.submodule { | ||
13 | options = { | ||
14 | keep = lib.mkOption { | ||
15 | type = lib.types.int; | ||
16 | default = 7; | ||
17 | description = '' | ||
18 | Number of backups to keep | ||
19 | ''; | ||
20 | }; | ||
21 | check_command = lib.mkOption { | ||
22 | type = lib.types.str; | ||
23 | default = "backup"; | ||
24 | description = '' | ||
25 | command to check if backup needs to be done | ||
26 | ''; | ||
27 | }; | ||
28 | login = lib.mkOption { | ||
29 | type = lib.types.str; | ||
30 | description = '' | ||
31 | login to connect to | ||
32 | ''; | ||
33 | }; | ||
34 | host = lib.mkOption { | ||
35 | type = lib.types.str; | ||
36 | description = '' | ||
37 | host to connect to | ||
38 | ''; | ||
39 | }; | ||
40 | port = lib.mkOption { | ||
41 | type = lib.types.str; | ||
42 | default = "22"; | ||
43 | description = '' | ||
44 | port to connect to | ||
45 | ''; | ||
46 | }; | ||
47 | host_key = lib.mkOption { | ||
48 | type = lib.types.str; | ||
49 | description = '' | ||
50 | Host key to use as known host | ||
51 | ''; | ||
52 | }; | ||
53 | host_key_type = lib.mkOption { | ||
54 | type = lib.types.str; | ||
55 | description = '' | ||
56 | Host key type | ||
57 | ''; | ||
58 | }; | ||
59 | parts = lib.mkOption { | ||
60 | type = lib.types.attrsOf (lib.types.submodule { | ||
61 | options = { | ||
62 | remote_folder = lib.mkOption { | ||
63 | type = lib.types.path; | ||
64 | description = '' | ||
65 | Path to backup | ||
66 | ''; | ||
67 | }; | ||
68 | exclude_from = lib.mkOption { | ||
69 | type = lib.types.listOf lib.types.path; | ||
70 | default = []; | ||
71 | description = '' | ||
72 | Paths to exclude from the backup | ||
73 | ''; | ||
74 | }; | ||
75 | files_from = lib.mkOption { | ||
76 | type = lib.types.listOf lib.types.path; | ||
77 | default = []; | ||
78 | description = '' | ||
79 | Paths to take for the backup | ||
80 | (if empty: whole folder minus exclude_from) | ||
81 | ''; | ||
82 | }; | ||
83 | args = lib.mkOption { | ||
84 | type = lib.types.nullOr lib.types.str; | ||
85 | default = null; | ||
86 | description = '' | ||
87 | additional arguments for rsync | ||
88 | ''; | ||
89 | }; | ||
90 | }; | ||
91 | }); | ||
92 | description = '' | ||
93 | folders to backup in the host | ||
94 | ''; | ||
95 | }; | ||
96 | }; | ||
97 | }); | ||
98 | default = {}; | ||
99 | description = '' | ||
100 | Profiles to backup | ||
101 | ''; | ||
102 | }; | ||
103 | ssh_key_public = lib.mkOption { | ||
104 | type = lib.types.str; | ||
105 | description = "Public key for the backup"; | ||
106 | }; | ||
107 | ssh_key_private = lib.mkOption { | ||
108 | type = lib.types.str; | ||
109 | description = "Private key for the backup"; | ||
110 | }; | ||
111 | }; | ||
112 | |||
113 | config = | ||
114 | let | ||
115 | cfg = config.services.rsyncBackup; | ||
116 | in | ||
117 | lib.mkIf (builtins.length (builtins.attrNames cfg.profiles) > 0) { | ||
118 | users.users.backup = { | ||
119 | isSystemUser = true; | ||
120 | uid = config.ids.uids.backup; | ||
121 | group = "backup"; | ||
122 | extraGroups = [ "keys" ]; | ||
123 | }; | ||
124 | |||
125 | users.groups.backup = { | ||
126 | gid = config.ids.gids.backup; | ||
127 | }; | ||
128 | |||
129 | services.cron.systemCronJobs = let | ||
130 | ssh_key = cfg.ssh_key_private; | ||
131 | backup_head = '' | ||
132 | #!${pkgs.stdenv.shell} | ||
133 | EXCL_FROM=`mktemp` | ||
134 | FILES_FROM=`mktemp` | ||
135 | TMP_STDERR=`mktemp` | ||
136 | |||
137 | on_exit() { | ||
138 | if [ -s "$TMP_STDERR" ]; then | ||
139 | cat "$TMP_STDERR" | ||
140 | fi | ||
141 | rm -f $TMP_STDERR $EXCL_FROM $FILES_FROM | ||
142 | } | ||
143 | |||
144 | trap "on_exit" EXIT | ||
145 | |||
146 | exec 2> "$TMP_STDERR" | ||
147 | exec < /dev/null | ||
148 | |||
149 | set -e | ||
150 | ''; | ||
151 | backup_profile_head = name: profile: '' | ||
152 | ##### ${name} ##### | ||
153 | PORT="${profile.port}" | ||
154 | DEST="${profile.login}@${profile.host}" | ||
155 | BASE="${cfg.mountpoint}/${name}" | ||
156 | OLD_BAK_BASE=$BASE/older/j | ||
157 | BAK_BASE=''${OLD_BAK_BASE}0 | ||
158 | RSYNC_OUTPUT=$BASE/rsync_output | ||
159 | NBR=${builtins.toString profile.keep} | ||
160 | |||
161 | if ! ssh \ | ||
162 | -o PreferredAuthentications=publickey \ | ||
163 | -o StrictHostKeyChecking=yes \ | ||
164 | -o ClearAllForwardings=yes \ | ||
165 | -o UserKnownHostsFile=/dev/null \ | ||
166 | -o CheckHostIP=no \ | ||
167 | -p $PORT \ | ||
168 | -i ${ssh_key} \ | ||
169 | $DEST ${profile.check_command}; then | ||
170 | echo "Fichier de verrouillage backup sur $DEST ou impossible de se connecter" >&2 | ||
171 | skip=$DEST | ||
172 | fi | ||
173 | |||
174 | rm -rf ''${OLD_BAK_BASE}''${NBR} | ||
175 | for j in `seq -w $(($NBR-1)) -1 0`; do | ||
176 | [ ! -d ''${OLD_BAK_BASE}$j ] && continue | ||
177 | mv ''${OLD_BAK_BASE}$j ''${OLD_BAK_BASE}$(($j+1)) | ||
178 | done | ||
179 | mkdir $BAK_BASE | ||
180 | mv $RSYNC_OUTPUT $BAK_BASE | ||
181 | mkdir $RSYNC_OUTPUT | ||
182 | |||
183 | if [ "$skip" != "$DEST" ]; then | ||
184 | ''; | ||
185 | backup_profile_tail = name: profile: '' | ||
186 | ssh -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -i ${ssh_key} -p $PORT $DEST sh -c "date > .cache/last_backup" | ||
187 | fi # [ "$skip" != "$DEST" ] | ||
188 | ##### End ${name} ##### | ||
189 | ''; | ||
190 | |||
191 | backup_part = profile_name: part_name: part: '' | ||
192 | ### ${profile_name} ${part_name} ### | ||
193 | LOCAL="${part_name}" | ||
194 | REMOTE="${part.remote_folder}" | ||
195 | |||
196 | if [ ! -d "$BASE/$LOCAL" ]; then | ||
197 | mkdir $BASE/$LOCAL | ||
198 | fi | ||
199 | cd $BASE/$LOCAL | ||
200 | cat > $EXCL_FROM <<EOF | ||
201 | ${builtins.concatStringsSep "\n" part.exclude_from} | ||
202 | EOF | ||
203 | cat > $FILES_FROM <<EOF | ||
204 | ${builtins.concatStringsSep "\n" part.files_from} | ||
205 | EOF | ||
206 | |||
207 | OUT=$RSYNC_OUTPUT/$LOCAL | ||
208 | ${pkgs.rsync}/bin/rsync --new-compress -XAavbr --fake-super -e "ssh -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -i ${ssh_key} -p $PORT" --numeric-ids --delete \ | ||
209 | --backup-dir=$BAK_BASE/$LOCAL \${ | ||
210 | lib.optionalString (part.args != null) "\n ${part.args} \\"}${ | ||
211 | lib.optionalString (builtins.length part.exclude_from > 0) "\n --exclude-from=$EXCL_FROM \\"}${ | ||
212 | lib.optionalString (builtins.length part.files_from > 0) "\n --files-from=$FILES_FROM \\"} | ||
213 | $DEST:$REMOTE . > $OUT || true | ||
214 | ### End ${profile_name} ${part_name} ### | ||
215 | ''; | ||
216 | backup_profile = name: profile: builtins.concatStringsSep "\n" ( | ||
217 | [(backup_profile_head name profile)] | ||
218 | ++ lib.mapAttrsToList (backup_part name) profile.parts | ||
219 | ++ [(backup_profile_tail name profile)]); | ||
220 | |||
221 | backup = pkgs.writeScript "backup.sh" (builtins.concatStringsSep "\n" ([ | ||
222 | backup_head | ||
223 | ] ++ lib.mapAttrsToList backup_profile cfg.profiles)); | ||
224 | in [ | ||
225 | '' | ||
226 | 25 3,15 * * * backup ${backup} | ||
227 | '' | ||
228 | ]; | ||
229 | |||
230 | programs.ssh.knownHosts = lib.attrsets.mapAttrs' (name: profile: lib.attrsets.nameValuePair name { | ||
231 | hostNames = [ profile.host ]; | ||
232 | publicKey = "${profile.host_key_type} ${profile.host_key}"; | ||
233 | }) cfg.profiles; | ||
234 | |||
235 | system.activationScripts.rsyncBackup = { | ||
236 | deps = [ "users" ]; | ||
237 | text = builtins.concatStringsSep "\n" (map (v: '' | ||
238 | install -m 0700 -o backup -g backup -d ${cfg.mountpoint}/${v} ${cfg.mountpoint}/${v}/older ${cfg.mountpoint}/${v}/rsync_output | ||
239 | '') (builtins.attrNames cfg.profiles) | ||
240 | ); | ||
241 | }; | ||
242 | }; | ||
243 | }; | ||
244 | }; | ||
245 | } | ||
diff --git a/modules/default.nix b/modules/default.nix index 630e8f5..b6ac68a 100644 --- a/modules/default.nix +++ b/modules/default.nix | |||
@@ -20,7 +20,7 @@ in | |||
20 | openarc = flakeLib.withNarKeyCompat flakeCompat ../flakes/openarc "nixosModule"; | 20 | openarc = flakeLib.withNarKeyCompat flakeCompat ../flakes/openarc "nixosModule"; |
21 | 21 | ||
22 | duplyBackup = ./duply_backup; | 22 | duplyBackup = ./duply_backup; |
23 | rsyncBackup = ./rsync_backup; | 23 | rsyncBackup = flakeLib.withNarKeyCompat flakeCompat ../flakes/rsync_backup "nixosModule"; |
24 | naemon = ./naemon; | 24 | naemon = ./naemon; |
25 | 25 | ||
26 | php-application = ./websites/php-application.nix; | 26 | php-application = ./websites/php-application.nix; |
diff --git a/modules/private/system/backup-2.nix b/modules/private/system/backup-2.nix index 1f226c0..181f455 100644 --- a/modules/private/system/backup-2.nix +++ b/modules/private/system/backup-2.nix | |||
@@ -7,6 +7,22 @@ | |||
7 | }; | 7 | }; |
8 | # ssh-keyscan backup-2 | nix-shell -p ssh-to-age --run ssh-to-age | 8 | # ssh-keyscan backup-2 | nix-shell -p ssh-to-age --run ssh-to-age |
9 | secrets.ageKeys = [ "age1kk3nr27qu42j28mcfdag5lhq0zu2pky7gfanvne8l4z2ctevjpgskmw0sr" ]; | 9 | secrets.ageKeys = [ "age1kk3nr27qu42j28mcfdag5lhq0zu2pky7gfanvne8l4z2ctevjpgskmw0sr" ]; |
10 | secrets.keys = [ | ||
11 | { | ||
12 | dest = "rsync_backup/identity"; | ||
13 | user = "backup"; | ||
14 | group = "backup"; | ||
15 | permissions = "0400"; | ||
16 | text = config.myEnv.rsync_backup.ssh_key.private; | ||
17 | } | ||
18 | { | ||
19 | dest = "rsync_backup/identity.pub"; | ||
20 | user = "backup"; | ||
21 | group = "backup"; | ||
22 | permissions = "0444"; | ||
23 | text = config.myEnv.rsync_backup.ssh_key.public; | ||
24 | } | ||
25 | ]; | ||
10 | boot.kernelPackages = pkgs.linuxPackages_latest; | 26 | boot.kernelPackages = pkgs.linuxPackages_latest; |
11 | myEnv = import ../../../nixops/secrets/environment.nix; | 27 | myEnv = import ../../../nixops/secrets/environment.nix; |
12 | 28 | ||
@@ -54,8 +70,8 @@ | |||
54 | services.rsyncBackup = { | 70 | services.rsyncBackup = { |
55 | mountpoint = "/backup2"; | 71 | mountpoint = "/backup2"; |
56 | profiles = config.myEnv.rsync_backup.profiles; | 72 | profiles = config.myEnv.rsync_backup.profiles; |
57 | ssh_key_public = config.myEnv.rsync_backup.ssh_key.public; | 73 | ssh_key_public = config.secrets.fullPaths."rsync_backup/identity.pub"; |
58 | ssh_key_private = config.myEnv.rsync_backup.ssh_key.private; | 74 | ssh_key_private = config.secrets.fullPaths."rsync_backup/identity"; |
59 | }; | 75 | }; |
60 | 76 | ||
61 | myServices.mailRelay.enable = true; | 77 | myServices.mailRelay.enable = true; |
diff --git a/modules/rsync_backup/default.nix b/modules/rsync_backup/default.nix deleted file mode 100644 index f0df5a1..0000000 --- a/modules/rsync_backup/default.nix +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | { lib, pkgs, config, ... }: | ||
2 | let | ||
3 | partModule = lib.types.submodule { | ||
4 | options = { | ||
5 | remote_folder = lib.mkOption { | ||
6 | type = lib.types.path; | ||
7 | description = '' | ||
8 | Path to backup | ||
9 | ''; | ||
10 | }; | ||
11 | exclude_from = lib.mkOption { | ||
12 | type = lib.types.listOf lib.types.path; | ||
13 | default = []; | ||
14 | description = '' | ||
15 | Paths to exclude from the backup | ||
16 | ''; | ||
17 | }; | ||
18 | files_from = lib.mkOption { | ||
19 | type = lib.types.listOf lib.types.path; | ||
20 | default = []; | ||
21 | description = '' | ||
22 | Paths to take for the backup | ||
23 | (if empty: whole folder minus exclude_from) | ||
24 | ''; | ||
25 | }; | ||
26 | args = lib.mkOption { | ||
27 | type = lib.types.nullOr lib.types.str; | ||
28 | default = null; | ||
29 | description = '' | ||
30 | additional arguments for rsync | ||
31 | ''; | ||
32 | }; | ||
33 | }; | ||
34 | }; | ||
35 | profileModule = lib.types.submodule { | ||
36 | options = { | ||
37 | keep = lib.mkOption { | ||
38 | type = lib.types.int; | ||
39 | default = 7; | ||
40 | description = '' | ||
41 | Number of backups to keep | ||
42 | ''; | ||
43 | }; | ||
44 | check_command = lib.mkOption { | ||
45 | type = lib.types.str; | ||
46 | default = "backup"; | ||
47 | description = '' | ||
48 | command to check if backup needs to be done | ||
49 | ''; | ||
50 | }; | ||
51 | login = lib.mkOption { | ||
52 | type = lib.types.str; | ||
53 | description = '' | ||
54 | login to connect to | ||
55 | ''; | ||
56 | }; | ||
57 | host = lib.mkOption { | ||
58 | type = lib.types.str; | ||
59 | description = '' | ||
60 | host to connect to | ||
61 | ''; | ||
62 | }; | ||
63 | port = lib.mkOption { | ||
64 | type = lib.types.str; | ||
65 | default = "22"; | ||
66 | description = '' | ||
67 | port to connect to | ||
68 | ''; | ||
69 | }; | ||
70 | host_key = lib.mkOption { | ||
71 | type = lib.types.str; | ||
72 | description = '' | ||
73 | Host key to use as known host | ||
74 | ''; | ||
75 | }; | ||
76 | host_key_type = lib.mkOption { | ||
77 | type = lib.types.str; | ||
78 | description = '' | ||
79 | Host key type | ||
80 | ''; | ||
81 | }; | ||
82 | parts = lib.mkOption { | ||
83 | type = lib.types.attrsOf partModule; | ||
84 | description = '' | ||
85 | folders to backup in the host | ||
86 | ''; | ||
87 | }; | ||
88 | }; | ||
89 | }; | ||
90 | cfg = config.services.rsyncBackup; | ||
91 | |||
92 | ssh_key = config.secrets.fullPaths."rsync_backup/identity"; | ||
93 | |||
94 | backup_head = '' | ||
95 | #!${pkgs.stdenv.shell} | ||
96 | EXCL_FROM=`mktemp` | ||
97 | FILES_FROM=`mktemp` | ||
98 | TMP_STDERR=`mktemp` | ||
99 | |||
100 | on_exit() { | ||
101 | if [ -s "$TMP_STDERR" ]; then | ||
102 | cat "$TMP_STDERR" | ||
103 | fi | ||
104 | rm -f $TMP_STDERR $EXCL_FROM $FILES_FROM | ||
105 | } | ||
106 | |||
107 | trap "on_exit" EXIT | ||
108 | |||
109 | exec 2> "$TMP_STDERR" | ||
110 | exec < /dev/null | ||
111 | |||
112 | set -e | ||
113 | ''; | ||
114 | |||
115 | backup_profile = name: profile: builtins.concatStringsSep "\n" ( | ||
116 | [(backup_profile_head name profile)] | ||
117 | ++ lib.mapAttrsToList (backup_part name) profile.parts | ||
118 | ++ [(backup_profile_tail name profile)]); | ||
119 | |||
120 | backup_profile_head = name: profile: '' | ||
121 | ##### ${name} ##### | ||
122 | PORT="${profile.port}" | ||
123 | DEST="${profile.login}@${profile.host}" | ||
124 | BASE="${cfg.mountpoint}/${name}" | ||
125 | OLD_BAK_BASE=$BASE/older/j | ||
126 | BAK_BASE=''${OLD_BAK_BASE}0 | ||
127 | RSYNC_OUTPUT=$BASE/rsync_output | ||
128 | NBR=${builtins.toString profile.keep} | ||
129 | |||
130 | if ! ssh \ | ||
131 | -o PreferredAuthentications=publickey \ | ||
132 | -o StrictHostKeyChecking=yes \ | ||
133 | -o ClearAllForwardings=yes \ | ||
134 | -o UserKnownHostsFile=/dev/null \ | ||
135 | -o CheckHostIP=no \ | ||
136 | -p $PORT \ | ||
137 | -i ${ssh_key} \ | ||
138 | $DEST ${profile.check_command}; then | ||
139 | echo "Fichier de verrouillage backup sur $DEST ou impossible de se connecter" >&2 | ||
140 | skip=$DEST | ||
141 | fi | ||
142 | |||
143 | rm -rf ''${OLD_BAK_BASE}''${NBR} | ||
144 | for j in `seq -w $(($NBR-1)) -1 0`; do | ||
145 | [ ! -d ''${OLD_BAK_BASE}$j ] && continue | ||
146 | mv ''${OLD_BAK_BASE}$j ''${OLD_BAK_BASE}$(($j+1)) | ||
147 | done | ||
148 | mkdir $BAK_BASE | ||
149 | mv $RSYNC_OUTPUT $BAK_BASE | ||
150 | mkdir $RSYNC_OUTPUT | ||
151 | |||
152 | if [ "$skip" != "$DEST" ]; then | ||
153 | ''; | ||
154 | |||
155 | backup_profile_tail = name: profile: '' | ||
156 | ssh -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -i ${ssh_key} -p $PORT $DEST sh -c "date > .cache/last_backup" | ||
157 | fi # [ "$skip" != "$DEST" ] | ||
158 | ##### End ${name} ##### | ||
159 | ''; | ||
160 | |||
161 | backup_part = profile_name: part_name: part: '' | ||
162 | ### ${profile_name} ${part_name} ### | ||
163 | LOCAL="${part_name}" | ||
164 | REMOTE="${part.remote_folder}" | ||
165 | |||
166 | if [ ! -d "$BASE/$LOCAL" ]; then | ||
167 | mkdir $BASE/$LOCAL | ||
168 | fi | ||
169 | cd $BASE/$LOCAL | ||
170 | cat > $EXCL_FROM <<EOF | ||
171 | ${builtins.concatStringsSep "\n" part.exclude_from} | ||
172 | EOF | ||
173 | cat > $FILES_FROM <<EOF | ||
174 | ${builtins.concatStringsSep "\n" part.files_from} | ||
175 | EOF | ||
176 | |||
177 | OUT=$RSYNC_OUTPUT/$LOCAL | ||
178 | ${pkgs.rsync}/bin/rsync --new-compress -XAavbr --fake-super -e "ssh -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -i ${ssh_key} -p $PORT" --numeric-ids --delete \ | ||
179 | --backup-dir=$BAK_BASE/$LOCAL \${ | ||
180 | lib.optionalString (part.args != null) "\n ${part.args} \\"}${ | ||
181 | lib.optionalString (builtins.length part.exclude_from > 0) "\n --exclude-from=$EXCL_FROM \\"}${ | ||
182 | lib.optionalString (builtins.length part.files_from > 0) "\n --files-from=$FILES_FROM \\"} | ||
183 | $DEST:$REMOTE . > $OUT || true | ||
184 | ### End ${profile_name} ${part_name} ### | ||
185 | ''; | ||
186 | in | ||
187 | { | ||
188 | options.services.rsyncBackup = { | ||
189 | mountpoint = lib.mkOption { | ||
190 | type = lib.types.path; | ||
191 | description = "Path to the base folder for backups"; | ||
192 | }; | ||
193 | profiles = lib.mkOption { | ||
194 | type = lib.types.attrsOf profileModule; | ||
195 | default = {}; | ||
196 | description = '' | ||
197 | Profiles to backup | ||
198 | ''; | ||
199 | }; | ||
200 | ssh_key_public = lib.mkOption { | ||
201 | type = lib.types.str; | ||
202 | description = "Public key for the backup"; | ||
203 | }; | ||
204 | ssh_key_private = lib.mkOption { | ||
205 | type = lib.types.str; | ||
206 | description = "Private key for the backup"; | ||
207 | }; | ||
208 | }; | ||
209 | |||
210 | config = lib.mkIf (builtins.length (builtins.attrNames cfg.profiles) > 0) { | ||
211 | users.users.backup = { | ||
212 | isSystemUser = true; | ||
213 | uid = config.ids.uids.backup; | ||
214 | group = "backup"; | ||
215 | extraGroups = [ "keys" ]; | ||
216 | }; | ||
217 | |||
218 | users.groups.backup = { | ||
219 | gid = config.ids.gids.backup; | ||
220 | }; | ||
221 | |||
222 | services.cron.systemCronJobs = let | ||
223 | backup = pkgs.writeScript "backup.sh" (builtins.concatStringsSep "\n" ([ | ||
224 | backup_head | ||
225 | ] ++ lib.mapAttrsToList backup_profile cfg.profiles)); | ||
226 | in [ | ||
227 | '' | ||
228 | 25 3,15 * * * backup ${backup} | ||
229 | '' | ||
230 | ]; | ||
231 | |||
232 | programs.ssh.knownHosts = lib.attrsets.mapAttrs' (name: profile: lib.attrsets.nameValuePair name { | ||
233 | hostNames = [ profile.host ]; | ||
234 | publicKey = "${profile.host_key_type} ${profile.host_key}"; | ||
235 | }) cfg.profiles; | ||
236 | |||
237 | system.activationScripts.rsyncBackup = { | ||
238 | deps = [ "users" ]; | ||
239 | text = builtins.concatStringsSep "\n" (map (v: '' | ||
240 | install -m 0700 -o backup -g backup -d ${cfg.mountpoint}/${v} ${cfg.mountpoint}/${v}/older ${cfg.mountpoint}/${v}/rsync_output | ||
241 | '') (builtins.attrNames cfg.profiles) | ||
242 | ); | ||
243 | }; | ||
244 | |||
245 | secrets.keys = [ | ||
246 | { | ||
247 | dest = "rsync_backup/identity"; | ||
248 | user = "backup"; | ||
249 | group = "backup"; | ||
250 | permissions = "0400"; | ||
251 | text = cfg.ssh_key_private; | ||
252 | } | ||
253 | { | ||
254 | dest = "rsync_backup/identity.pub"; | ||
255 | user = "backup"; | ||
256 | group = "backup"; | ||
257 | permissions = "0444"; | ||
258 | text = cfg.ssh_key_public; | ||
259 | } | ||
260 | ]; | ||
261 | }; | ||
262 | } | ||