summaryrefslogtreecommitdiff
path: root/tw/services
diff options
context:
space:
mode:
authorTimo Wilken2023-09-19 23:32:26 +0200
committerTimo Wilken2023-09-19 23:47:46 +0200
commit47f8e82a3c33fadce4524b750915d92e8e5b9c4b (patch)
tree5393cc33e9befa9395643b04239a092e4b107c58 /tw/services
parentf0a13928bcc907a92e01f194ceef806318d42f3c (diff)
Formalise password keys to avoid PATH issues
Mcron seems to set a restricted PATH now, so make sure it knows where to find "pass". Also use less shell substitution and implement repository URL building in Guile.
Diffstat (limited to 'tw/services')
-rw-r--r--tw/services/restic.scm68
1 files changed, 43 insertions, 25 deletions
diff --git a/tw/services/restic.scm b/tw/services/restic.scm
index eda02d3e..ec2c9f87 100644
--- a/tw/services/restic.scm
+++ b/tw/services/restic.scm
@@ -3,19 +3,25 @@
#:use-module (gnu home services mcron)
#:use-module ((gnu packages admin)
#:select (shadow))
- #:use-module (gnu packages backup)
+ #:use-module ((gnu packages backup)
+ #:select (restic))
+ #:use-module ((gnu packages password-utils)
+ #:select (password-store))
#:use-module (gnu services)
#:use-module (gnu services configuration)
#:use-module (gnu services mcron)
#:use-module (gnu services shepherd)
#:use-module (guix gexp)
#:use-module (guix packages)
+ #:use-module ((guix records)
+ #:select (match-record))
#:use-module (srfi srfi-1)
#:export (restic-server-service-type
restic-server-configuration
restic-cleanup-service-type
restic-cleanup-repository
home-restic-backup-service-type
+ restic-rest-repository
restic-backup-repository))
(define %restic-user "restic")
@@ -190,6 +196,13 @@ true."
(define (nonempty-list-of-strings? thing)
(and (pair? thing) (list-of-strings? thing)))
+(define-configuration/no-serialization restic-rest-repository
+ (username string "The HTTP username for the repository.")
+ (password-key string "The password-store key of the repo's HTTP password.")
+ (hostname string "The hostname serving the repository.")
+ (port (integer 80) "The port number to connect to.")
+ (path (string "/") "The HTTP path at which the repository is found."))
+
(define-configuration/no-serialization restic-backup-repository
(schedule gexp "An mcron schedule, specified as a gexp
(@pxref{G-Expressions}), to use for the backup job. String, list or lambda
@@ -197,35 +210,40 @@ syntax is fine (@pxref{Syntax, mcron job specifications,, mcron,
GNU@tie{}mcron}).")
(paths nonempty-list-of-strings "List of paths to back up. At least one
must be given. Leading @code{~/} are replaced with @code{$HOME}.")
- (url-command string "Run this command (inside @code{sh -c}) to obtain the
-directory or URL of the repo to back up to. This allows you to substitute
-passwords in @code{rest:} URLs.")
- (password-command string "Run this command to obtain the repository password.")
+ (url restic-rest-repository "Back up to the given @code{rest:} repository.")
+ (password-key string "Obtain the repository password from password-store at
+the given key.")
(tags (list-of-strings '()) "Optional tags to add to the snapshot.")
(restic (package restic) "The restic package to use."))
(define (restic-backup-cronjobs repositories)
(define (cronjob repo)
- #~(job #$(restic-backup-repository-schedule repo)
- #$(program-file "restic-backup-command"
- #~(begin
- (use-modules (ice-9 popen)
- (ice-9 textual-ports)
- (srfi srfi-1))
- (define (replace-home path)
- (if (string-prefix? "~/" path)
- (string-replace path (getenv "HOME") 0 1)
- path))
- (setenv "RESTIC_PASSWORD_COMMAND"
- '#$(restic-backup-repository-password-command repo))
- (let ((pipe (open-pipe '#$(restic-backup-repository-url-command repo) OPEN_READ)))
- (setenv "RESTIC_REPOSITORY" (string-trim-right (get-string-all pipe) #\newline))
- (close-pipe pipe))
- (apply execl #$(file-append (restic-backup-repository-restic repo) "/bin/restic")
- "restic" "backup" "--cleanup-cache"
- #$@(append-map (lambda (tag) (list "--tag" tag))
- (restic-backup-repository-tags repo))
- (map replace-home '#$(restic-backup-repository-paths repo)))))))
+ (match-record repo <restic-backup-repository>
+ (schedule paths url password-key tags restic)
+ (match-record url <restic-rest-repository>
+ (username hostname port path)
+ #~(job #$schedule
+ #$(program-file "restic-backup-command"
+ #~(begin
+ (use-modules (ice-9 popen)
+ (ice-9 textual-ports)
+ (srfi srfi-1))
+ (define pass #$(file-append password-store "/bin/pass"))
+ (define (replace-home path)
+ (if (string-prefix? "~/" path)
+ (string-replace path (getenv "HOME") 0 1)
+ path))
+ (let ((pipe (open-pipe* OPEN_READ pass #$(restic-rest-repository-password-key url))))
+ (setenv "RESTIC_REPOSITORY"
+ (format #f "rest:http://~a:~a@~a:~a/~a"
+ #$username (get-line pipe) #$hostname #$port
+ (string-trim #$path #\/)))
+ (close-pipe pipe))
+ (setenv "RESTIC_PASSWORD_COMMAND" (string-append pass " " #$password-key))
+ (apply execl #$(file-append restic "/bin/restic")
+ "restic" "backup" "--cleanup-cache"
+ #$@(append-map (lambda (tag) (list "--tag" tag)) tags)
+ (map replace-home '#$paths))))))))
(map cronjob repositories))
(define home-restic-backup-service-type