summaryrefslogtreecommitdiff
path: root/guix/vkraus/services/email-key-rotation.scm
blob: 49f12ee29d05e8605707ed7f5e7cd6c40aeb52bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
(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 ((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 (<email-key-rotation-configuration>
	    make-email-key-rotation-configuration
	    email-key-rotation-configuration?
            email-key-rotation-service-type)
  #:declarative? #t)

(define-immutable-record-type <email-key-rotation-configuration>
  (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)))))