From e0c62036cee57afa25b8cd398cef7f5064ea9d6c Mon Sep 17 00:00:00 2001
From: Freya Murphy <freya@freyacat.org>
Date: Mon, 9 Dec 2024 11:21:09 -0500
Subject: [PATCH] add certbot to cuirass

---
 systems/cuirass.scm | 159 +++++++++++++++++++++++++++-----------------
 1 file changed, 97 insertions(+), 62 deletions(-)

diff --git a/systems/cuirass.scm b/systems/cuirass.scm
index 2804619..79532f5 100644
--- a/systems/cuirass.scm
+++ b/systems/cuirass.scm
@@ -7,8 +7,10 @@
              (gnu services avahi)
              (gnu services mcron)
              (gnu services web)
+             (gnu services certbot)
              (gnu services databases)
              (gnu services networking)
+             (guix modules)
              (guix gexp)
              (gnu))
 
@@ -42,6 +44,13 @@
   #~(job "0 2 * * *"
          "herd restart cuirass-remote-worker"))
 
+;; Nginx deploy hook for certbot
+(define %nginx-deploy-hook
+  (program-file
+    "nginx-deploy-hook"
+    #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read)))
+        (kill pid SIGHUP))))
+
 ;; Curiass module filter
 (define default-module-filter
   (match-lambda
@@ -93,69 +102,95 @@
 -A INPUT -p tcp --dport 8080:8081 ! -s 127.0.0.1 -j REJECT
 COMMIT
 "))))
+                   ; certbot
+                   (service certbot-service-type
+                     (certbot-configuration
+                       (certificates
+                         (list
+                           (certificate-configuration
+                             (deploy-hook %nginx-deploy-hook)
+                             (domains '("cuirass.in.freya.cat"
+                                        "substitutes.in.freya.cat")))))
+                       (server "https://ca.in.freya.cat/acme/acme/directory")
+                       (email "freya@freyacat.org")
+                       (webroot "/srv/http")))
                    ; nginx
-                   (service nginx-service-type
-                     (nginx-configuration
-                       (upstream-blocks
-                         (list
-                           (nginx-upstream-configuration
-                             (name "cuirass")
-                             (servers (list "localhost:8081")))
-                           (nginx-upstream-configuration
-                             (name "publish")
-                             (servers (list "localhost:8080")))))
-                       (server-blocks
-                         (list
-                           (nginx-server-configuration
-                             (server-name '("cuirass.in.freya.cat"))
-                             (listen '("80"))
-                             (locations
-                               (list
-                                 (nginx-location-configuration
-                                   (uri "/")
-                                   (body
-                                     (list "proxy_pass http://cuirass;"
-                                           "proxy_set_header X-Forwarded-Proto https;"))))))
-                           (nginx-server-configuration
-                             (server-name '("substitutes.in.freya.cat"))
-                             (listen '("80"))
-                             (raw-content '("rewrite ^//(.*)$ /$1 redirect;"))
-                             (index (list "index.html"))
-                             (locations
-                               (list
-                                 (nginx-location-configuration
-                                   (uri "/signing-key.pub")
-                                        (body '("proxy_pass http://publish;")))
-                                      (nginx-location-configuration
-                                        (uri "/file/")
-                                        (body '("proxy_pass http://publish;")))
-                                      (nginx-location-configuration
-                                        (uri "/log/")
-                                        (body '("proxy_pass http://publish;")))
-                                      (nginx-location-configuration
-                                        (uri "/nix-cache-info")
-                                        (body (list
-                                          "proxy_pass http://publish;"
-                                          "proxy_hide_header Set-Cookie;")))
-                                 (nginx-location-configuration
-                                   (uri "/nar/")
-                                   (body (list
-                                     "proxy_pass http://publish;"
-                                     "client_body_buffer_size 256k;"
-                                     ;; Nars are already compressed. -> no perf change
-                                     "gzip off;"
-                                     "proxy_pass_header Cache-Control;")))
-                                 (nginx-location-configuration
-                                   (uri "~ \\.narinfo$")
-                                   (body
-                                    (list
-                                      "proxy_pass http://publish;"
-                                      "client_body_buffer_size 128k;"
-                                      "proxy_connect_timeout 2s;"
-                                      "proxy_read_timeout 2s;"
-                                      "proxy_send_timeout 2s;"
-                                      "proxy_pass_header Cache-Control;"
-                                      "proxy_ignore_client_abort on;"))))))))))
+                   (let* ((certificate "/etc/letsencrypt/live/cuirass.in.freya.cat/fullchain.pem")
+                          (certificate-key "/etc/letsencrypt/live/cuirass.in.freya.cat/privkey.pem")
+                          (bootstrapping (not (access? certificate F_OK))))
+                     (service nginx-service-type
+                       (nginx-configuration
+                         (upstream-blocks
+                           (list
+                             (nginx-upstream-configuration
+                               (name "cuirass")
+                               (servers (list "localhost:8081")))
+                             (nginx-upstream-configuration
+                               (name "publish")
+                               (servers (list "localhost:8080")))))
+                         (server-blocks
+                           (list
+                             (nginx-server-configuration
+                               (server-name '("cuirass.in.freya.cat"))
+                               (listen (if bootstrapping
+                                         '("9090") ; allow default 80 server to handle .well-known
+                                         '("443 ssl")))
+                               (ssl-certificate (if bootstrapping #f certificate))
+                               (ssl-certificate-key (if bootstrapping #f certificate-key))
+                               (locations
+                                 (list
+                                   (nginx-location-configuration
+                                     (uri "~ ^/admin")
+                                     (body
+                                       (list "if ($ssl_client_verify != SUCCESS) { return 403; } proxy_pass http://cuirass;")))
+                                   (nginx-location-configuration
+                                     (uri "/")
+                                     (body
+                                       (list "proxy_pass http://cuirass;"))))))
+                             (nginx-server-configuration
+                               (server-name '("substitutes.in.freya.cat"))
+                               (listen (if bootstrapping
+                                         '("9090") ; allow default 80 server to handle .well-known
+                                         '("443 ssl")))
+                               (ssl-certificate (if bootstrapping #f certificate))
+                               (ssl-certificate-key (if bootstrapping #f certificate-key))
+                               (raw-content '("rewrite ^//(.*)$ /$1 redirect;"))
+                               (index (list "index.html"))
+                               (locations
+                                 (list
+                                   (nginx-location-configuration
+                                     (uri "/signing-key.pub")
+                                     (body '("proxy_pass http://publish;")))
+                                   (nginx-location-configuration
+                                     (uri "/file/")
+                                     (body '("proxy_pass http://publish;")))
+                                   (nginx-location-configuration
+                                     (uri "/log/")
+                                     (body '("proxy_pass http://publish;")))
+                                   (nginx-location-configuration
+                                     (uri "/nix-cache-info")
+                                     (body (list
+                                       "proxy_pass http://publish;"
+                                       "proxy_hide_header Set-Cookie;")))
+                                   (nginx-location-configuration
+                                     (uri "/nar/")
+                                     (body (list
+                                       "proxy_pass http://publish;"
+                                       "client_body_buffer_size 256k;"
+                                       ;; Nars are already compressed. -> no perf change
+                                       "gzip off;"
+                                       "proxy_pass_header Cache-Control;")))
+                                   (nginx-location-configuration
+                                     (uri "~ \\.narinfo$")
+                                     (body
+                                      (list
+                                        "proxy_pass http://publish;"
+                                        "client_body_buffer_size 128k;"
+                                        "proxy_connect_timeout 2s;"
+                                        "proxy_read_timeout 2s;"
+                                        "proxy_send_timeout 2s;"
+                                        "proxy_pass_header Cache-Control;"
+                                        "proxy_ignore_client_abort on;")))))))))))
                    %base-freya-services))
   (swap-devices (list (swap-space
                         (target (uuid