summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2024-01-08 13:48:56 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2024-01-08 13:48:56 +0100
commitc7be4cf367ad39e4a3f01950f39551bc583a08a9 (patch)
tree78ca1d27dffda949b6fc64271ad52a22672d9ba3
parent555b682bf4b25825c8d862a9f00570773e3906ee (diff)
Add xml->configuration
-rw-r--r--README.org75
-rw-r--r--email-key-rotation.scm16
2 files changed, 91 insertions, 0 deletions
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..bd7359a
--- /dev/null
+++ b/README.org
@@ -0,0 +1,75 @@
+#+title: Email Key Rotation
+#+language: en
+#+author: Vivien Kraus
+#+email: vivien@planete-kraus.eu
+
+I present to you this humble package that can help you rotate your
+DKIM keys and SRS secrets.
+
+DKIM rotation can be done in various different ways, but this package
+assumes that you have at least a couple of selectors, such as
+=selectorA= and =selectorB=. When the current selector is =selectorB=,
+the DNS entry for =selectorA= is the previous expired public key, and
+the DNS entry for =selectorB= is the current public key. In this case,
+after rotation, the DNS entry for =selectorB= does not change, but
+that of =selectorA= becomes the new public key, and the email server
+starts signing outbound emails with =selectorA= instead of
+=selectorB=, provided that you restart it.
+
+This package can:
+- rotate DKIM keys;
+- rotate SRS secrets for opensmtpd;
+- “materialize” the keys.
+
+When materialized, the DKIM key is saved as an openssl private key (so
+that it can be used by your DKIM signing SMTP server), the current
+selector is written to a file on its only line, the SRS secrets are
+written to an OpenSMTPD configuration file, and, if configured, the
+Gandi LiveDNS zone is updated.
+
+This package uses the =openssl= program to generate keys and
+secrets. You can customize this by parameterizing
+=current-openssl-binary= in /(email-key-rotation openssl)/, either to
+a program name to invoke, or to a procedure that accepts 1 argument
+(the command-line for openssl, without the program name).
+
+This package manages different secrets: both[fn::current and expired]
+DKIM keys, both SRS secrets, and the Gandi LiveDNS API key. Files
+containing these secrets are always written with mode =0600=, but not
+much else is considered for security.
+
+* Initialize the configuration
+You initialize the configuration by calling =initialize= in
+/(email-key-rotation)/. The arguments are:
+- the list of selectors, for instance ='(selectorA selectorB)=;
+- the file name for the private opensmtpd configuration file, or =#f=
+ if you do not want to configure SRS;
+- the name of the file that will contain the current DKIM selector, or
+ =#f= if you do not want to configure DKIM;
+- the name of the file that will contain the current DKIM private key,
+ or =#f= if you do not want to configure DKIM;
+- the Gandi LiveDNS API key, or =#f= if you do not wish to publish DNS
+ records on Gandi LiveDNS;
+- the Gandi domain name.
+
+This function returns a configuration object that you may save to disk
+with =materialize=, in /(email-key-rotation)/. This function takes the
+configuration object as the first argument, and an optional output
+port to save the configuration object itself. If the port is not set,
+then it is saved to the current Guile output port. If the port is set,
+*and* is set to a file port, then it will be made only readable by the
+current owner.
+
+* Rotate the configuration
+Every once in a while, say, every week, you would load the current
+configuration object, and rotate it with =rotate=, in
+/(email-key-rotation)/. The return value is a new configuration object
+that you can materialize.
+
+The configuration object is saved to disk as XML. You may convert it
+with =xml->sxml= in /(sxml simple)/, and then convert it to a
+configuration object with =sxml->configuration= in
+/(email-key-rotation)/, or use the shortcut =xml->configuration= in
+/(email-key-rotation)/. The latter accept only one optional argument,
+the port to read XML from. It defaults to the Guile current input
+port.
diff --git a/email-key-rotation.scm b/email-key-rotation.scm
index 686aafb..de6fdec 100644
--- a/email-key-rotation.scm
+++ b/email-key-rotation.scm
@@ -27,6 +27,7 @@
set-dkim-current-key-file
set-gandi-configuration
sxml->configuration
+ xml->configuration
configuration->sxml
initialize
rotate
@@ -117,6 +118,21 @@
(essential-configuration sxml)
(refine-configuration extra-state essential)))))
+(define* (xml->configuration #:optional (port (current-input-port)))
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-exception
+ (make-error)
+ (make-exception-with-origin 'xml->configuration)
+ (make-exception-with-irritants (list port))
+ (make-exception-with-message
+ "cannot read a configuration from file.")
+ exn)))
+ (lambda ()
+ (sxml->configuration
+ (xml->sxml port)))))
+
(define (configuration->sxml config)
(with-exception-handler
(lambda (exn)