(define-module (vkraus services email-key-rotation) #:use-module ((gnu services) #:select (service-type service-extension special-files-service-type activation-service-type)) #:use-module ((gnu services mcron) #:select (mcron-service-type)) #:use-module ((guix gexp) #:select (gexp plain-file program-file with-imported-modules file-append with-extensions mixed-text-file)) #:use-module ((guix modules) #:select (source-module-closure)) #:use-module ((vkraus packages email-key-rotation) #:select (email-key-rotation)) #:use-module ((gnu packages guile) #:select (guile-3.0)) #:use-module ((gnu packages guile) #:select (guile-3.0)) #:use-module ((gnu packages tls) #:select (guile-gnutls gnutls)) #:use-module ((gnu packages guile-xyz) #:select (guile-json-4)) #:use-module ((ice-9 match) #:select (match match-lambda*)) #:use-module ((ice-9 optargs) #:select (define*)) #:use-module ((srfi srfi-26) #:select (cute)) #:use-module ((srfi srfi-9 gnu) #:select (define-immutable-record-type)) #:export ( make-email-key-rotation-configuration email-key-rotation-configuration? email-key-rotation-service-type) #:declarative? #t) (define-immutable-record-type (make-ekrconf state-file selectors opensmtpd-conf selector-file key-file gandi-key-file gandi-domain services-to-restart) email-key-rotation-configuration? (state-file state-file set-state-file) (selectors selectors set-selectors) (opensmtpd-conf opensmtpd-conf set-opensmtpd-conf) (selector-file selector-file set-selector-file) (key-file key-file set-key-file) (gandi-key-file gandi-key-file set-gandi-key-file) (gandi-domain gandi-domain set-gandi-domain) (services-to-restart services-to-restart set-services-to-restart)) (define* (make-email-key-rotation-configuration filename #:key selectors opensmtpd-conf selector-file key-file gandi-key-file gandi-domain (services-to-restart '())) (make-ekrconf filename selectors opensmtpd-conf selector-file key-file gandi-key-file gandi-domain services-to-restart)) (define (ensure-init-job config) (with-extensions (list guile-3.0 guile-json-4 gnutls guile-gnutls email-key-rotation) (with-imported-modules (source-module-closure '((guix build utils))) #~(begin (use-modules (email-key-rotation) (guix build utils) (ice-9 rdelim)) (mkdir-p (dirname #$(state-file config))) #$@(when (opensmtpd-conf config) #~((mkdir-p (dirname #$(opensmtpd-conf config)))) #~()) #$@(when (selector-file config) #~((mkdir-p (dirname #$(selector-file config)))) #~()) #$@(when (key-file config) #~((mkdir-p (dirname #$(key-file config)))) #~()) (let ((gandi-key #$(if (gandi-key-file config) #~(call-with-input-file #$(gandi-key-file config) read-line) #~#f)) (gandi-domain #$(gandi-domain config))) (unless (file-exists? #$(state-file config)) (let ((module (initialize (map string->symbol (list #$@(selectors config))) #$(opensmtpd-conf config) #$(selector-file config) #$(key-file config) gandi-key gandi-domain))) (call-with-output-file #$(state-file config) (lambda (port) (materialize module port)))))))))) (define (rotate-job config) (with-extensions (list guile-3.0 guile-json-4 gnutls guile-gnutls email-key-rotation) (with-imported-modules (source-module-closure '((guix build utils))) #~(begin (use-modules (email-key-rotation) (guix build utils)) (let* ((previous-module (call-with-input-file #$(state-file config) xml->configuration)) (next-module (rotate previous-module))) (call-with-output-file #$(state-file config) (lambda (port) (materialize next-module port)))) (for-each (lambda (service) (invoke "herd" "restart" service)) (list #$@(services-to-restart config))))))) (define (email-key-rotation-activation configuration) (ensure-init-job configuration)) (define (email-key-rotation-mcron configuration) (list #~(job '(next-month) (lambda () (system* "/var/lib/email/rotate-keys"))))) (define (email-key-rotation-special-files configuration) `(("/var/lib/email/rotate-keys" ,(program-file "rotate-keys" (rotate-job configuration))))) (define email-key-rotation-service-type (service-type (name 'email-key-rotation) (description "Rotate DKIM and SRS keys") (extensions (list (service-extension mcron-service-type email-key-rotation-mcron) (service-extension activation-service-type email-key-rotation-activation) (service-extension special-files-service-type email-key-rotation-special-files)))))