From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp0.migadu.com ([2001:41d0:303:e16b::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms8.migadu.com with LMTPS id gFoXLDk0umXbaQAAqHPOHw:P1 (envelope-from ) for ; Wed, 31 Jan 2024 12:51:21 +0100 Received: from aspmx1.migadu.com ([2001:41d0:303:e16b::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp0.migadu.com with LMTPS id gFoXLDk0umXbaQAAqHPOHw (envelope-from ) for ; Wed, 31 Jan 2024 12:51:21 +0100 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=zancanaro.id.au header.s=k1 header.b=LD8drruR; spf=pass (aspmx1.migadu.com: domain of "bug-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="bug-guix-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=zancanaro.id.au (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1706701881; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=r83O6ubSTO0By1913BBCRhbw1fi5C9HJ8O0rVZb7/Jw=; b=NrXiMzU/X7nqtqDhPecEfKKPGsvS5EqUwfM+vltBiuxxdOLOQi348j9T0xu99hG1YXPTUE v/Z82hOUsWaoE5ss/iBS5kayalpfskcSMn0KeUcSr1NAe5QcGhC4wNsFMAlbiqJboto5fv b0lpv4H/WiahfB5uxZ7utsCAaJRvd89DEoxTBXMp+dhIp8MU4zl5QoF7CA6S/RO90tcdjX CoGFTcZ92W2lwa3vzjwB5Saqt+CDiPmAR/M7OofTP5FNKfDSvCbp0umIPK1c0WH7Qg0e2x sfsdhuEnazmxdsE8lu1CyEr4vwhfrluQbjGDiTjMzEsPF+ps4hZcLLPOJhF+Hg== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=zancanaro.id.au header.s=k1 header.b=LD8drruR; spf=pass (aspmx1.migadu.com: domain of "bug-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="bug-guix-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=zancanaro.id.au (policy=none) ARC-Seal: i=1; s=key1; d=yhetil.org; t=1706701881; a=rsa-sha256; cv=none; b=Mzm4ltcKlsQTPRe4vXYZcSOjV2cXJFXuxf0jXLEfAgkzt+lC9O3TDLwgZHSsOjfNlEavt+ Gvt66DV9TbsJKbJjKFwiFxmFvPnQ1Ff+X8bxT9zOMcem1lsJfPcEKlRc16MoNBjWfYmO7e ulIQNKR67ycbuhBDBQo3//vJP2w8P18g5UZLWUZwBuCM+zCXEdmrYJwVntyof9kTeBf5NI Ns1IMUZPydJVtQRPNif/cuO8r7m+EnURfFbv5507jo5/RFhvB2c6II6Lqj8fonK0xuPbaV dv0i/mz5kSl5jUNpDRPe+nnlgj2rggk1RXsTAIndfeuE8qkEdaH8/vVvB/garw== Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 520D5161D0 for ; Wed, 31 Jan 2024 12:51:21 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rV97P-000570-5F; Wed, 31 Jan 2024 06:51:03 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rV97H-0004q3-E0 for bug-guix@gnu.org; Wed, 31 Jan 2024 06:50:55 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rV97G-00033g-O1 for bug-guix@gnu.org; Wed, 31 Jan 2024 06:50:54 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rV97Q-0004mJ-59 for bug-guix@gnu.org; Wed, 31 Jan 2024 06:51:04 -0500 X-Loop: help-debbugs@gnu.org Subject: bug#46961: [PATCH v3 4/4] services: certbot: Add one-shot service to renew certificates. Resent-From: Carlo Zancanaro Original-Sender: "Debbugs-submit" Resent-CC: bug-guix@gnu.org Resent-Date: Wed, 31 Jan 2024 11:51:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 46961 X-GNU-PR-Package: guix X-GNU-PR-Keywords: To: 46961@debbugs.gnu.org Cc: clement@lassieur.org Received: via spool by 46961-submit@debbugs.gnu.org id=B46961.170670184218306 (code B ref 46961); Wed, 31 Jan 2024 11:51:04 +0000 Received: (at 46961) by debbugs.gnu.org; 31 Jan 2024 11:50:42 +0000 Received: from localhost ([127.0.0.1]:37583 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rV973-0004l6-Q6 for submit@debbugs.gnu.org; Wed, 31 Jan 2024 06:50:42 -0500 Received: from voltorb.zancanaro.id.au ([45.77.50.64]:46898) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rV96z-0004k6-Do for 46961@debbugs.gnu.org; Wed, 31 Jan 2024 06:50:38 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=k1; bh=r83O6ubSTO0By19 13BBCRhbw1fi5C9HJ8O0rVZb7/Jw=; h=references:in-reply-to:date:subject: cc:to:from; d=zancanaro.id.au; b=LD8drruRbdlUu6h5P/mvrlqbUkguSR70FFEIH HxbQHlZFl6rT7gpRIjdprh1rQKT3WiY3fNYohaKhNtak+lD01+I5JK36zNHyHeX9aA3vVz t3ZoMUAiE46PVOlHCzb9Wmfzx/aubkcYl7yf62hzY2I6K/kRZzVBRiZ4y9QFFcPE= Received: by voltorb.zancanaro.id.au (OpenSMTPD) with ESMTPSA id 77e12bd2 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 31 Jan 2024 11:50:03 +0000 (UTC) From: Carlo Zancanaro Date: Wed, 31 Jan 2024 11:46:25 +0000 Message-ID: <4674088538cb55d20978f5cff9fe8820e9171bf1.1706701585.git.carlo@zancanaro.id.au> X-Mailer: git-send-email 2.41.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-guix@gnu.org List-Id: Bug reports for GNU Guix List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guix-bounces+larch=yhetil.org@gnu.org Sender: bug-guix-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Spam-Score: 3.84 X-Migadu-Scanner: mx13.migadu.com X-Spam-Score: 3.84 X-Migadu-Queue-Id: 520D5161D0 X-TUID: EO4BC/2eoFE2 * gnu/services/certbot.scm (certbot-renewal-one-shot): New procedure. (certbot-service-type)[extensions]: Add it to shepherd-root extension. (certbot-command): Make connection errors return a different exit code. (certbot-activation): Remove message with certificate renewal instructions. Change-Id: I614ac6214a753dba0396e2385a75926c8355caa1 --- I've added some more logging here, and removed the comments that implied that we expected the length of time for the retries to be bounded. gnu/services/certbot.scm | 89 +++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/gnu/services/certbot.scm b/gnu/services/certbot.scm index cb1be0c0e9..f287c8367f 100644 --- a/gnu/services/certbot.scm +++ b/gnu/services/certbot.scm @@ -180,15 +180,45 @@ (define certbot-command (program-file "certbot-command" #~(begin - (use-modules (ice-9 match)) - (let ((code 0)) + (use-modules (ice-9 match) + (ice-9 textual-ports)) + + (define (log format-string . args) + (apply format #t format-string args) + (force-output)) + + (define (file-contains? file string) + (string-contains (call-with-input-file file + get-string-all) + string)) + + (define (connection-error?) + ;; Certbot errors are always exit code 1, so we need to look at + ;; the log file to see if there was a connection error. + (file-contains? "/var/log/letsencrypt/letsencrypt.log" + "Failed to establish a new connection")) + + (let ((script-code 0)) (for-each (match-lambda ((name . command) - (begin - (format #t "Acquiring or renewing certificate: ~a~%" name) - (set! code (or (apply system* command) code))))) - '#$commands) code))))))) + (log "Acquiring or renewing certificate: ~a~%" name) + (cond + ((zero? (status:exit-val (apply system* command))) + (log "Certificate successfully acquired: ~a~%" name)) + ((connection-error?) + ;; If we have a connection error, then bail early with + ;; exit code 2. We don't expect this to resolve within the + ;; timespan of this script. + (log "Connection error - bailing out~%") + (exit 2)) + (else + ;; If we have any other type of error, then continue but + ;; exit with a failing status code in the end. + (log "Error: ~a - continuing with other domains~%" name) + (set! script-code 1))))) + '#$commands) + (exit script-code)))))))) (define (certbot-renewal-jobs config) (list @@ -197,6 +227,40 @@ (define (certbot-renewal-jobs config) #~(job '(next-minute-from (next-hour '(0 12)) (list (random 60))) #$(certbot-command config)))) +(define (certbot-renewal-one-shot config) + (list + ;; Renew certificates when the system first starts. This is a one-shot + ;; service, because the mcron configuration will take care of running this + ;; periodically. This is most useful the very first time the system starts, + ;; to overwrite our self-signed certificates as soon as possible without + ;; user intervention. + (shepherd-service + (provision '(renew-certbot-certificates)) + (requirement '(nginx)) + (one-shot? #t) + (start #~(lambda _ + ;; This needs the network, but there's no reliable way to know + ;; if the network is up other than trying. If we fail due to a + ;; connection error we retry a number of times in the hope that + ;; the network comes up soon. + (let loop ((attempt 0)) + (let ((code (status:exit-val + (system* #$(certbot-command config))))) + (cond + ((and (= code 2) ; Exit code 2 means connection error + (< attempt 12)) ; Arbitrarily chosen max attempts + (sleep 10) ; Arbitrarily chosen retry delay + (loop (1+ attempt))) + ((zero? code) + ;; Success! + #t) + (else + ;; Failure. + #f)))))) + (auto-start? #t) + (documentation "Call certbot to renew certificates.") + (actions (list (shepherd-configuration-action (certbot-command config))))))) + (define (generate-certificate-gexp certbot-cert-directory rsa-key-size) (match-lambda (($ name (primary-domain other-domains ...) @@ -240,9 +304,7 @@ (define (generate-certificate-gexp certbot-cert-directory rsa-key-size) (define (certbot-activation config) (let* ((certbot-directory "/var/lib/certbot") - (certbot-cert-directory "/etc/letsencrypt/live") - (script (in-vicinity certbot-directory "renew-certificates")) - (message (format #f (G_ "~a may need to be run~%") script))) + (certbot-cert-directory "/etc/letsencrypt/live")) (match config (($ package webroot certificates email server rsa-key-size default-location) @@ -258,10 +320,7 @@ (define (certbot-activation config) (map (generate-certificate-gexp certbot-cert-directory rsa-key-size) (filter certificate-configuration-start-self-signed? - certificates))) - - (copy-file #$(certbot-command config) #$script) - (display #$message))))))) + certificates))))))))) (define certbot-nginx-server-configurations (match-lambda @@ -294,7 +353,9 @@ (define certbot-service-type (service-extension activation-service-type certbot-activation) (service-extension mcron-service-type - certbot-renewal-jobs))) + certbot-renewal-jobs) + (service-extension shepherd-root-service-type + certbot-renewal-one-shot))) (compose concatenate) (extend (lambda (config additional-certificates) (certbot-configuration -- 2.41.0