diff options
author | Vivien Kraus <vivien@planete-kraus.eu> | 2024-01-08 13:48:56 +0100 |
---|---|---|
committer | Vivien Kraus <vivien@planete-kraus.eu> | 2024-01-08 13:48:56 +0100 |
commit | c7be4cf367ad39e4a3f01950f39551bc583a08a9 (patch) | |
tree | 78ca1d27dffda949b6fc64271ad52a22672d9ba3 | |
parent | 555b682bf4b25825c8d862a9f00570773e3906ee (diff) |
Add xml->configuration
-rw-r--r-- | README.org | 75 | ||||
-rw-r--r-- | email-key-rotation.scm | 16 |
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) |