From bddc465bf484ddf78cf3576c77b10eff4e753ef8 Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Mon, 20 Nov 2023 20:59:04 +0100 Subject: Make WireGuard service install its own secrets automatically --- tw/services/wireguard.scm | 86 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 23 deletions(-) (limited to 'tw/services/wireguard.scm') diff --git a/tw/services/wireguard.scm b/tw/services/wireguard.scm index 3d35cd2e..e975fe46 100644 --- a/tw/services/wireguard.scm +++ b/tw/services/wireguard.scm @@ -6,6 +6,10 @@ #:use-module (gnu services base) #:use-module (gnu services configuration) #:use-module (gnu services vpn) + #:use-module (guix gexp) + #:use-module ((guix records) #:select (match-record)) + #:use-module ((guix utils) #:select (current-source-directory)) + #:use-module (tw services secrets) #:export (%wireguard-peers tw-wireguard-configuration tw-wireguard-service-type)) @@ -56,41 +60,76 @@ "The host name of the machine being configured.") (peers (wireguard-peers-list %wireguard-peers) - "An alist of WireGuard peers to install.")) + "An alist of WireGuard peers to install.") + (private-key-file + (string "/etc/wireguard/private.key") + "Where to store this host's private key.")) + +(define (other-peers this-host peers) + (let ((own-peer (assoc-ref peers this-host))) + (delq own-peer (map cdr peers)))) (define (tw-wireguard-service config) "Create a full WireGuard config from the personal network CONFIG." - (let ((own-peer (assoc-ref (tw-wireguard-configuration-peers config) - (tw-wireguard-configuration-this-host config)))) - (wireguard-configuration - (addresses - (map (lambda (cidr) - (let ((ipv4 (string-match "/32$" cidr)) - (ipv6 (string-match "/128$" cidr))) - (cond - (ipv4 (regexp-substitute #f ipv4 'pre "/24")) - (ipv6 (regexp-substitute #f ipv6 'pre "/64")) - (#t cidr)))) - (wireguard-peer-allowed-ips own-peer))) - (port - (let ((endpoint (wireguard-peer-endpoint own-peer))) + (match-record config (this-host peers private-key-file) + (match-record (assoc-ref peers this-host) (@@ (gnu services vpn) ) (endpoint allowed-ips) + (wireguard-configuration + (addresses + (map (lambda (cidr) + (let ((ipv4 (string-match "/32$" cidr)) + (ipv6 (string-match "/128$" cidr))) + (cond + (ipv4 (regexp-substitute #f ipv4 'pre "/24")) + (ipv6 (regexp-substitute #f ipv6 'pre "/64")) + (#t cidr)))) + allowed-ips)) + (port (if endpoint (string->number (cadr (string-split endpoint #\:))) - 58921))) - (private-key "/etc/wireguard/private.key") - (peers (delq own-peer (map cdr (tw-wireguard-configuration-peers config))))))) + 58921)) + (private-key private-key-file) + (peers (other-peers this-host peers)))))) + +(define (cut-string-at-char str char-pred) + "Return the first part of STR up to the first occurrence of CHAR-PRED." + (substring str 0 (string-index str char-pred))) (define (peer->ips peer) "Extract IP addresses assigned to the given `wireguard-peer' PEER." - (map (compose car (cut string-split <> #\/)) + (map (cut cut-string-at-char <> #\/) (wireguard-peer-allowed-ips peer))) (define (tw-wireguard-hosts config) "Generate a hosts file entries from the personal WireGuard network CONFIG." - (append-map (lambda (peer) - (map (cut host <> (wireguard-peer-name peer)) - (peer->ips peer))) - (map cdr (tw-wireguard-configuration-peers config)))) + (define (peer->entries peer) + (map (cut host <> (wireguard-peer-name peer)) + (peer->ips peer))) + (append-map (compose peer->entries cdr) + (tw-wireguard-configuration-peers config))) + +(define (tw-wireguard-secrets config) + "Install secrets for the host's private key and preshared keys with peers." + (define (local-file-here path) + (local-file + (canonicalize-path + (string-append + (current-source-directory) "/" path)))) + (match-record config (this-host peers private-key-file) + (define short-host (cut-string-at-char this-host #\.)) + (define private-key + (secret + (encrypted-file + (local-file-here (string-append "files/wireguard/" short-host ".key.enc"))) + (destination private-key-file))) + (define (peer->secret peer) + (let ((short-peer (cut-string-at-char (wireguard-peer-name peer) #\.))) + (secret + (encrypted-file + (local-file-here + (string-append "files/wireguard/" short-host "-" short-peer ".psk.enc"))) + (destination + (string-append "/etc/wireguard/" short-peer ".psk"))))) + (cons private-key (map peer->secret (other-peers this-host peers))))) (define tw-wireguard-service-type (service-type @@ -98,6 +137,7 @@ (description "Set up my personal WireGuard network.") (extensions (cons* (service-extension hosts-service-type tw-wireguard-hosts) + (service-extension secrets-service-type tw-wireguard-secrets) ;; FIXME: `wireguard-service-type' cannot be extended, so copy its ;; service-extensions directly. (map (lambda (ext) -- cgit v1.2.3