From d17f14a58990d004e969c2f370548d4dfdefade0 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 10 Sep 2019 20:17:04 -0300 Subject: [PATCH 01/11] certbot --- Dockerfile | 19 +++++++++++++++++++ certbot.sh | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ monit.conf | 17 +++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 certbot.sh create mode 100644 monit.conf diff --git a/Dockerfile b/Dockerfile index 59c5898..2cec2a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,2 +1,21 @@ FROM sutty/monit:latest MAINTAINER "f " + +# Install requisites +RUN apk add --no-cache certbot jq wget + +# Run certbot +COPY ./monit.conf /etc/monit.d/certbot.conf +# Get more output +RUN echo "set limits { programoutput: 1 MB }" >> /etc/monit.d/limits.conf + +# Install certbot's script +COPY ./certbot.sh /usr/local/bin/certbot +RUN chmod +x /usr/local/bin/certbot + +# Check monit's config +RUN monit -t + +# Access to certificates and challenges +VOLUME /etc/letsencrypt +VOLUME /var/lib/letsencrypt diff --git a/certbot.sh b/certbot.sh new file mode 100644 index 0000000..6b03373 --- /dev/null +++ b/certbot.sh @@ -0,0 +1,48 @@ +#!/bin/sh +set -e + +case $1 in + # Renew certificates, trust in certbot's algorithms + renew) /usr/bin/certbot renew --quit --agree-tos ;; + bootstrap) + test -d "/etc/letsencrypt/live/api.${SUTTY}" && exit 0 + + # Get the certificate for the domain, the webserver will need + # access to this directory + /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ + --webroot \ + --agree-tos \ + --webroot-path /var/lib/letsencrypt \ + -d "api.${SUTTY}" ;; + # Generate certificates + *) + # Save headers here + headers=/tmp/headers + # Gets ETag from previous headers + test -f "${headers}" \ + && etag="$(grep "^ Etag: " "${headers}" | cut -d : -f 2)" + + # Get site list from the API and transform to a list. Save headers + # for next run. Use ETag to avoid running when nothing changed + wget --user="${HTTP_BASIC_USER}" --password="${HTTP_BASIC_PASSWORD}" \ + --header="If-None-Match:${etag}" -qSO - \ + "https://api.${SUTTY}/v1/sites.json" \ + 2>"${headers}" \ + | jq --raw-output .[] \ + | while read name; do + # If the site name doesn't end with a dot, it's a subdomain + domain="$(echo "${name}" | sed "s/[^\.]$/&${SUTTY}/")" + domain="${domain%.}" + + # Skip already existing domains + test -d "/etc/letsencrypt/live/${domain}" && continue + + # Get the certificate for the domain, the webserver will need + # access to this directory + /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ + --webroot \ + --agree-tos \ + --webroot-path /var/lib/letsencrypt \ + -d "${domain}" + done +esac diff --git a/monit.conf b/monit.conf new file mode 100644 index 0000000..7d1eb88 --- /dev/null +++ b/monit.conf @@ -0,0 +1,17 @@ +# Get first certificate! +check program certbot_bootstrap + with path "/usr/local/bin/certbot bootstrap" + every 1 cycle + if status = 0 then unmonitor + +# Renew certificates once a week +check program certbot_renew + with path "/usr/local/bin/certbot renew" + every "13 5 * * *" + if status != 0 then alert + +# Get missing certificates for every cycle. +check program certbot + with path "/usr/local/bin/certbot" + every 1 cycle + if status != 0 then alert From 44ba4c78def1fd56f6243b54fc9fc901680f5b7a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 13 Sep 2019 16:19:04 -0300 Subject: [PATCH 02/11] add ssl group --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2cec2a3..863bb75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,13 +6,14 @@ RUN apk add --no-cache certbot jq wget # Run certbot COPY ./monit.conf /etc/monit.d/certbot.conf -# Get more output -RUN echo "set limits { programoutput: 1 MB }" >> /etc/monit.d/limits.conf # Install certbot's script COPY ./certbot.sh /usr/local/bin/certbot RUN chmod +x /usr/local/bin/certbot +# Add ssl group +RUN addgroup -S -g 777 ssl + # Check monit's config RUN monit -t From 5df18ce97c1e09724e71012a52ba18e232bb093c Mon Sep 17 00:00:00 2001 From: f Date: Fri, 13 Sep 2019 17:10:50 -0300 Subject: [PATCH 03/11] fix permissions and domains --- certbot.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/certbot.sh b/certbot.sh index 6b03373..729e2ed 100644 --- a/certbot.sh +++ b/certbot.sh @@ -31,7 +31,7 @@ case $1 in | jq --raw-output .[] \ | while read name; do # If the site name doesn't end with a dot, it's a subdomain - domain="$(echo "${name}" | sed "s/[^\.]$/&${SUTTY}/")" + domain="$(echo "${name}" | sed "s/[^\.]$/&.${SUTTY}/")" domain="${domain%.}" # Skip already existing domains @@ -45,4 +45,9 @@ case $1 in --webroot-path /var/lib/letsencrypt \ -d "${domain}" done + + # Fix permissions, users in group ssl have read access + find /etc/letsencrypt -type d | xargs -r chmod 2750 + find /etc/letsencrypt -type f | xargs -r chmod 640 + chgrp -R ssl /etc/letsencrypt esac From 5d3d7ce80ed00740724b7b0b39eecb0624fda80c Mon Sep 17 00:00:00 2001 From: f Date: Fri, 13 Sep 2019 18:33:46 -0300 Subject: [PATCH 04/11] bootstrap main site also --- certbot.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/certbot.sh b/certbot.sh index 729e2ed..175ff1b 100644 --- a/certbot.sh +++ b/certbot.sh @@ -5,15 +5,17 @@ case $1 in # Renew certificates, trust in certbot's algorithms renew) /usr/bin/certbot renew --quit --agree-tos ;; bootstrap) - test -d "/etc/letsencrypt/live/api.${SUTTY}" && exit 0 + for site in ${SUTTY} api.${SUTTY}; do + test -d "/etc/letsencrypt/live/${site}" && exit 0 - # Get the certificate for the domain, the webserver will need - # access to this directory - /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ - --webroot \ - --agree-tos \ - --webroot-path /var/lib/letsencrypt \ - -d "api.${SUTTY}" ;; + # Get the certificate for the domain, the webserver will need + # access to this directory + /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ + --webroot \ + --agree-tos \ + --webroot-path /var/lib/letsencrypt \ + -d "${site}" + done ;; # Generate certificates *) # Save headers here From dc5856cb03c8492616bdfe651c3e5428c673202f Mon Sep 17 00:00:00 2001 From: f Date: Tue, 1 Oct 2019 15:28:14 -0300 Subject: [PATCH 05/11] www --- certbot.sh | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/certbot.sh b/certbot.sh index 175ff1b..a296938 100644 --- a/certbot.sh +++ b/certbot.sh @@ -36,16 +36,19 @@ case $1 in domain="$(echo "${name}" | sed "s/[^\.]$/&.${SUTTY}/")" domain="${domain%.}" - # Skip already existing domains - test -d "/etc/letsencrypt/live/${domain}" && continue + # Generate a certificate for www also + for d in ${domain} www.${domain}; do + # Skip already existing domains + test -d "/etc/letsencrypt/live/${d}" && continue - # Get the certificate for the domain, the webserver will need - # access to this directory - /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ - --webroot \ - --agree-tos \ - --webroot-path /var/lib/letsencrypt \ - -d "${domain}" + # Get the certificate for the domain, the webserver will need + # access to this directory + /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ + --webroot \ + --agree-tos \ + --webroot-path /var/lib/letsencrypt \ + -d "${d}" + done done # Fix permissions, users in group ssl have read access From 7d7c88a70b6925650a7ce16e6d99cf61be87db88 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 7 Oct 2019 15:57:11 -0300 Subject: [PATCH 06/11] symlink to default server --- certbot.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certbot.sh b/certbot.sh index a296938..9da0054 100644 --- a/certbot.sh +++ b/certbot.sh @@ -15,6 +15,9 @@ case $1 in --agree-tos \ --webroot-path /var/lib/letsencrypt \ -d "${site}" + + cd /etc/letsencrypt/live + ln -s ${SUTTY} default done ;; # Generate certificates *) From 2f483b96771b8fcd991c2ce63f8823cb3a140ead Mon Sep 17 00:00:00 2001 From: f Date: Fri, 11 Oct 2019 12:55:05 -0300 Subject: [PATCH 07/11] typo --- certbot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot.sh b/certbot.sh index 9da0054..a382ef8 100644 --- a/certbot.sh +++ b/certbot.sh @@ -3,7 +3,7 @@ set -e case $1 in # Renew certificates, trust in certbot's algorithms - renew) /usr/bin/certbot renew --quit --agree-tos ;; + renew) /usr/bin/certbot renew --quiet --agree-tos ;; bootstrap) for site in ${SUTTY} api.${SUTTY}; do test -d "/etc/letsencrypt/live/${site}" && exit 0 From c14f785672c4aa1229af3346f6c5126b853ec62b Mon Sep 17 00:00:00 2001 From: f Date: Mon, 7 Sep 2020 18:06:50 -0300 Subject: [PATCH 08/11] push certificates and skip non-local domains --- certbot.sh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/certbot.sh b/certbot.sh index a382ef8..be8e570 100644 --- a/certbot.sh +++ b/certbot.sh @@ -44,6 +44,9 @@ case $1 in # Skip already existing domains test -d "/etc/letsencrypt/live/${d}" && continue + # Ignore non local domains + nslookup "${d}" 8.8.8.8 | grep -q "${SUTTY_ADDRESS}" || continue + # Get the certificate for the domain, the webserver will need # access to this directory /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ @@ -53,9 +56,16 @@ case $1 in -d "${d}" done done - - # Fix permissions, users in group ssl have read access - find /etc/letsencrypt -type d | xargs -r chmod 2750 - find /etc/letsencrypt -type f | xargs -r chmod 640 - chgrp -R ssl /etc/letsencrypt esac + +# Fix permissions, users in group ssl have read access +find /etc/letsencrypt -type d | xargs -r chmod 2750 +find /etc/letsencrypt -type f | xargs -r chmod 640 +chgrp -R ssl /etc/letsencrypt + +# Push certificates to nodes, we use SSH as a secure transport +# but this means we're synchronizing from container to host which is +# awkward. +for NODE in ${NODES}; do + rsync -avHAX --delete-after /etc/letsencrypt/ ${NODE}:/srv/sutty/etc/letsencrypt/ +done From bab4a36ce4c9d1d7381f12c80f45197c178c898c Mon Sep 17 00:00:00 2001 From: f Date: Mon, 7 Sep 2020 20:16:49 -0300 Subject: [PATCH 09/11] distribute certificates to other nodes --- Dockerfile | 5 +++-- certbot.sh | 5 +++-- ssh_config | 6 ++++++ 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 ssh_config diff --git a/Dockerfile b/Dockerfile index 863bb75..b8489ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,8 +14,9 @@ RUN chmod +x /usr/local/bin/certbot # Add ssl group RUN addgroup -S -g 777 ssl -# Check monit's config -RUN monit -t +RUN apk add --no-cache openssh-client rsync +RUN install -dm 2750 -o root -g root /root/.ssh +COPY ./ssh_config /root/.ssh/config # Access to certificates and challenges VOLUME /etc/letsencrypt diff --git a/certbot.sh b/certbot.sh index be8e570..05fc399 100644 --- a/certbot.sh +++ b/certbot.sh @@ -65,7 +65,8 @@ chgrp -R ssl /etc/letsencrypt # Push certificates to nodes, we use SSH as a secure transport # but this means we're synchronizing from container to host which is -# awkward. +# awkward. A restricted rsync treats / as the remote location for the +# certificates. for NODE in ${NODES}; do - rsync -avHAX --delete-after /etc/letsencrypt/ ${NODE}:/srv/sutty/etc/letsencrypt/ + rsync -avHAX --delete-after /etc/letsencrypt/ ${NODE}:/ done diff --git a/ssh_config b/ssh_config new file mode 100644 index 0000000..fd417ed --- /dev/null +++ b/ssh_config @@ -0,0 +1,6 @@ +Host * + Protocol 2 + IdentityFile /root/certbot + VerifyHostKeyDNS yes + HashKnownHosts yes + StrictHostKeyChecking yes From e82961aafcfaf688b33fd295e4e4eef021e56cb2 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 2 Feb 2021 20:30:08 -0300 Subject: [PATCH 10/11] continue after failure --- certbot.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/certbot.sh b/certbot.sh index 05fc399..e5fae77 100644 --- a/certbot.sh +++ b/certbot.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -e case $1 in # Renew certificates, trust in certbot's algorithms From 03ff181219eb7904371de2ad5be972f087c8b01e Mon Sep 17 00:00:00 2001 From: f Date: Sun, 8 Aug 2021 22:18:24 -0300 Subject: [PATCH 11/11] sutty sends domains, no need to do conversion https://0xacab.org/sutty/sutty/-/merge_requests/50 --- certbot.sh | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/certbot.sh b/certbot.sh index e5fae77..6f1b905 100644 --- a/certbot.sh +++ b/certbot.sh @@ -33,27 +33,20 @@ case $1 in "https://api.${SUTTY}/v1/sites.json" \ 2>"${headers}" \ | jq --raw-output .[] \ - | while read name; do - # If the site name doesn't end with a dot, it's a subdomain - domain="$(echo "${name}" | sed "s/[^\.]$/&.${SUTTY}/")" - domain="${domain%.}" + | while read domain; do + # Skip already existing domains + test -d "/etc/letsencrypt/live/${domain}" && continue - # Generate a certificate for www also - for d in ${domain} www.${domain}; do - # Skip already existing domains - test -d "/etc/letsencrypt/live/${d}" && continue + # Ignore non local domains + nslookup "${domain}" 8.8.8.8 | grep -q "${SUTTY_ADDRESS}" || continue - # Ignore non local domains - nslookup "${d}" 8.8.8.8 | grep -q "${SUTTY_ADDRESS}" || continue - - # Get the certificate for the domain, the webserver will need - # access to this directory - /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ - --webroot \ - --agree-tos \ - --webroot-path /var/lib/letsencrypt \ - -d "${d}" - done + # Get the certificate for the domain, the webserver will need + # access to this directory + /usr/bin/certbot certonly --email "certbot@${SUTTY}" \ + --webroot \ + --agree-tos \ + --webroot-path /var/lib/letsencrypt \ + -d "${domain}" done esac