From d533d93e3fea9c6182aa8a4327925a10b00cc417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Sun, 23 Oct 2022 12:13:03 +0200 Subject: [PATCH 01/10] Add ssl.ca-file directive to lighttp config Turns out that it is expected by some clients (for example, wget expects it, while Chrome does just fine without). --- lighttpd_custom.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/lighttpd_custom.conf b/lighttpd_custom.conf index 72e216a..492167d 100644 --- a/lighttpd_custom.conf +++ b/lighttpd_custom.conf @@ -26,5 +26,6 @@ $SERVER["socket"] == ":443" { ssl.engine = "enable" } $SERVER["socket"] == "[::]:443" { ssl.engine = "enable" } ssl.privkey = "/etc/lighttpd/certs/domain.example.com/domain.example.com.key" ssl.pemfile = "/etc/lighttpd/certs/domain.example.com/domain.example.com.cer" +ssl.ca-file = "/etc/lighttpd/certs/domain.example.com/fullchain.cer" ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.3") ssl.openssl.ssl-conf-cmd += ("Options" => "-ServerPreference") From 946c5a8ac5526751219c4876bf201df56bdd77ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 24 Oct 2022 14:37:56 +0200 Subject: [PATCH 02/10] Fix set-default-ca invocation for acme.sh Turns out that "install" and "set-default-ca" are separate actions and that only one can be performed per acme.sh invocation (I missed this because acme.sh was already installed when testing). --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b16b8d..078ee92 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ external storage on a Turris device, but you can install wherever you'd like. opkg install socat git clone https://github.com/acmesh-official/acme.sh -b [VERSION] /srv/acme.sh cd /srv/acme.sh - ./acme.sh --install --home /srv/.acme.sh --nocron --email [YOUREMAIL] --set-default-ca --server letsencrypt + ./acme.sh --install --home /srv/.acme.sh --nocron --email [YOUREMAIL] + ./acme.sh --set-default-ca --home /srv/.acme.sh --server letsencrypt 1. Disable the existing SSL configuration by removing the `lighttpd-https-cert` package: From d7e16852e303545b400f2149a6935ecfe4ab369c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Sun, 23 Oct 2022 12:51:38 +0200 Subject: [PATCH 03/10] Switch from standalone to webroot Using the webroot support in acme.sh means that it is not necessary to stop lighttpd from listening on port 80, which simplifies the configuration. --- README.md | 34 +++++++++-------------- cert-issue.sh | 5 +++- lighttpd_custom.conf => lighttpd_tls.conf | 13 ++++----- lighttpd_webroot.conf | 6 ++++ var/.gitignore | 1 + var/webroot/.gitignore | 1 + 6 files changed, 31 insertions(+), 29 deletions(-) rename lighttpd_custom.conf => lighttpd_tls.conf (69%) create mode 100644 lighttpd_webroot.conf create mode 100644 var/.gitignore create mode 100644 var/webroot/.gitignore diff --git a/README.md b/README.md index 078ee92..380e503 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,9 @@ using lighttpd. * Restarts lighttpd to deploy certificates * Configures lighttpd for TLSv1.3 only following the [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/). -* Disables lighttpd from running insecurely on port 80 - - * HSTS handles the odd case where you forget or are too lazy to type in the - `https://` at the start. Just load the `https://` URL once and your browser - will remember for you forever. +* Configures lighttpd to upgrade unencrypted connections. +* Configures the [HSTS +header](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security). ## Installation @@ -64,34 +62,28 @@ external storage on a Turris device, but you can install wherever you'd like. opkg install lighttpd-mod-openssl -1. Lighttpd needs to stop listening on port 80 so modify - `/etc/lighttpd/conf.d/90-turris-root.conf` to comment out these lines: +1. Reconfigure lighttpd to support the `acme` webroot, taking care to replace + the %TOT_BASEDIR% placeholder inside the template file: - $SERVER["socket"] == "*:80" { } - $SERVER["socket"] == "[::]:80" { } + sed -e "s|%TOT_BASEDIR%|/srv/turris-omnia-tls|g" /srv/turris-omnia-tls/lighttpd_webroot.conf > /etc/lighttpd/conf.d/39-acme-webroot.conf -1. Stop lighttpd; we will enable it again shortly: +1. Restart `lighttpd`: - /etc/init.d/lighttpd stop + /etc/init.d/lighttpd restart 1. Issue the certificate, taking care to specify your FQDN in place of `[YOUR.DOMAIN.COM]`: /srv/turris-omnia-tls/cert-issue.sh [YOUR.DOMAIN.COM] -1. Reconfigure lighttpd with the supplied custom configuration: - - cp /srv/turris-omnia-tls/lighttpd_custom.conf /etc/lighttpd/conf.d/40-ssl-acme-enable.conf +1. Reconfigure lighttpd to enable TLS and to use the new certificates, taking + care to replace the %TOT_FQDN% placeholder inside the template file: - Inside this file, replace the `domain.example.com` placeholders with your - FQDN. You can do this automatically by running the following command, - again taking care to specify your FQDN in place of `[YOUR.DOMAIN.COM]`: + sed -e "s|%TOT_FQDN%|turris.example.com|g" /srv/turris-omnia-tls/lighttpd_tls.conf > /etc/lighttpd/conf.d/40-acme-tls.conf - sed -i 's/domain.example.com/[YOUR.DOMAIN.COM]/g' /etc/lighttpd/conf.d/40-ssl-acme-enable.conf - -1. Restart `lighttpd`: +1. Restart `lighttpd` again: - /etc/init.d/lighttpd start + /etc/init.d/lighttpd restart 1. Add crontab entry for renewal; pick a random minute and hour: diff --git a/cert-issue.sh b/cert-issue.sh index 198f820..37d38e8 100755 --- a/cert-issue.sh +++ b/cert-issue.sh @@ -1,13 +1,16 @@ #!/bin/sh certhome="/etc/lighttpd/certs" ca_path="/etc/ssl/certs" +webroot="/src/turris-omnia-tls/var/webroot" domain="$1" mkdir -p "$certhome" +mkdir -p "$webroot" + /srv/.acme.sh/acme.sh \ --home "/srv/.acme.sh" \ --issue \ - --standalone \ + --webroot "$webroot" \ --domain "$domain" \ --keylength 4096 \ --certhome "$certhome" \ diff --git a/lighttpd_custom.conf b/lighttpd_tls.conf similarity index 69% rename from lighttpd_custom.conf rename to lighttpd_tls.conf index 492167d..1f2d54f 100644 --- a/lighttpd_custom.conf +++ b/lighttpd_tls.conf @@ -2,11 +2,10 @@ # https://ssl-config.mozilla.org/ # Last verified: 22 October 2022 -server.port = 443 - -# Port 80 is disabled, but this doesn't hurt... $HTTP["scheme"] == "http" { - url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") + $HTTP["url"] !~ "^/.well-known/acme-challenge/" { + url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") + } } $HTTP["scheme"] == "https" { @@ -24,8 +23,8 @@ $HTTP["scheme"] == "https" { # (to avoid having to repeat ssl.* directives in both ":443" and "[::]:443") $SERVER["socket"] == ":443" { ssl.engine = "enable" } $SERVER["socket"] == "[::]:443" { ssl.engine = "enable" } -ssl.privkey = "/etc/lighttpd/certs/domain.example.com/domain.example.com.key" -ssl.pemfile = "/etc/lighttpd/certs/domain.example.com/domain.example.com.cer" -ssl.ca-file = "/etc/lighttpd/certs/domain.example.com/fullchain.cer" +ssl.privkey = "/etc/lighttpd/certs/%TOT_FQDN%/%TOT_FQDN%.key" +ssl.pemfile = "/etc/lighttpd/certs/%TOT_FQDN%/%TOT_FQDN%.cer" +ssl.ca-file = "/etc/lighttpd/certs/%TOT_FQDN%/fullchain.cer" ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.3") ssl.openssl.ssl-conf-cmd += ("Options" => "-ServerPreference") diff --git a/lighttpd_webroot.conf b/lighttpd_webroot.conf new file mode 100644 index 0000000..53f2075 --- /dev/null +++ b/lighttpd_webroot.conf @@ -0,0 +1,6 @@ +# Handle the acme.sh webroot + +alias.url = ( + "/.well-known/acme-challenge" => + "%TOT_BASEDIR%/var/webroot/.well-known/acme-challenge" +) diff --git a/var/.gitignore b/var/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/var/.gitignore @@ -0,0 +1 @@ +* diff --git a/var/webroot/.gitignore b/var/webroot/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/var/webroot/.gitignore @@ -0,0 +1 @@ +* From 28f590fe2fc0e6731af4e6cb960e0dd91625bcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Sun, 23 Oct 2022 13:24:21 +0200 Subject: [PATCH 04/10] Add support for short hostnames Automatically redirect e.g. "turris" -> "turris.example.com". Also simplify the README by merging two steps. --- README.md | 12 ++++++++---- lighttpd_tls.conf | 4 +++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 380e503..d08b512 100644 --- a/README.md +++ b/README.md @@ -72,14 +72,18 @@ external storage on a Turris device, but you can install wherever you'd like. /etc/init.d/lighttpd restart 1. Issue the certificate, taking care to specify your FQDN in place of - `[YOUR.DOMAIN.COM]`: + `[HOSTNAME.DOMAIN.COM]`: - /srv/turris-omnia-tls/cert-issue.sh [YOUR.DOMAIN.COM] + /srv/turris-omnia-tls/cert-issue.sh [HOSTNAME.DOMAIN.COM] 1. Reconfigure lighttpd to enable TLS and to use the new certificates, taking - care to replace the %TOT_FQDN% placeholder inside the template file: + care to replace the %TOT_FQDN% and %TOT_HOSTNAME% placeholders inside the + template file: - sed -e "s|%TOT_FQDN%|turris.example.com|g" /srv/turris-omnia-tls/lighttpd_tls.conf > /etc/lighttpd/conf.d/40-acme-tls.conf + sed \ + -e "s|%TOT_FQDN%|turris.example.com|g" \ + -e "s|%TOT_HOSTNAME%|turris|g" \ + /srv/turris-omnia-tls/lighttpd_tls.conf > /etc/lighttpd/conf.d/40-acme-tls.conf 1. Restart `lighttpd` again: diff --git a/lighttpd_tls.conf b/lighttpd_tls.conf index 1f2d54f..0a0e4f5 100644 --- a/lighttpd_tls.conf +++ b/lighttpd_tls.conf @@ -3,7 +3,9 @@ # Last verified: 22 October 2022 $HTTP["scheme"] == "http" { - $HTTP["url"] !~ "^/.well-known/acme-challenge/" { + $HTTP["host"] == "%TOT_HOSTNAME%" { + url.redirect = ("" => "http://%TOT_FQDN%${url.path}${qsa}") + } else $HTTP["url"] !~ "^/.well-known/acme-challenge/" { url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") } } From af7cd415fa1ce9cd4a811b54684e4b1405cbc0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Sun, 23 Oct 2022 13:53:13 +0200 Subject: [PATCH 05/10] Add acme.sh submodule This makes the installation process simpler. --- .gitmodules | 3 +++ README.md | 30 +++++++++++++----------------- acme.sh | 1 + 3 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 .gitmodules create mode 160000 acme.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ce82a11 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "acme.sh"] + path = acme.sh + url = https://github.com/acmesh-official/acme.sh diff --git a/README.md b/README.md index d08b512..45c2418 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ using lighttpd. ## Key features -* Uses [Acme.sh](https://github.com/acmesh-official/acme.sh) client for free TLS certificates from [Let's Encrypt](https://letsencrypt.org/) +* Uses the [acme.sh](https://github.com/acmesh-official/acme.sh) client to + obtain free TLS certificates from [Let's Encrypt](https://letsencrypt.org/) * Uses hook scripts to simplify issue and renewal process * Opportunistically opens and closes firewall port 80 * Restarts lighttpd to deploy certificates @@ -29,22 +30,16 @@ header](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security). This installs the project and files in `/srv`, which is the default path for external storage on a Turris device, but you can install wherever you'd like. -1. Download this project: +1. Download this project, including the `acme.sh` submodule: opkg install git-http - git clone https://github.com/davidjb/turris-omnia-tls.git /srv/turris-omnia-tls + git clone --recurse-submodules https://github.com/davidjb/turris-omnia-tls.git /srv/turris-omnia-tls -1. Determine the latest version of `acme.sh` by checking - https://github.com/acmesh-official/acme.sh/releases. Note the release - version (which is the tag name); you'll use it in the next step, - substituting for `[VERSION]`. - -1. Install `acme.sh` client and its dependency, `socat`; taking care to - substitute `[VERSION]` and `[YOUREMAIL]` with correct values: +1. Install the `acme.sh` client and its dependency, `socat`; taking care to + substitute `[YOUREMAIL]` with correct values: opkg install socat - git clone https://github.com/acmesh-official/acme.sh -b [VERSION] /srv/acme.sh - cd /srv/acme.sh + cd /srv/turris-omnia-tls/acme.sh ./acme.sh --install --home /srv/.acme.sh --nocron --email [YOUREMAIL] ./acme.sh --set-default-ca --home /srv/.acme.sh --server letsencrypt @@ -108,13 +103,14 @@ inside `cert-issue.sh` before you run it the first time or go and modify the con that `acme.sh` generates in `/etc/lighttpd/certs/extra.example.com/extra.example.com.conf`, where `extra.example.com` is the name of your domain. -## Upgrading acme.sh +## Upgrading turris-omnia-tls and acme.sh -Run the following; after `fetch`ing, you'll see the latest version tag: +Run the following: - cd /srv/acme.sh - git fetch - git checkout [VERSION] + cd /srv/turris-omnia-tls + git pull + git submodule update --remote acme.sh + cd acme.sh ./acme.sh --install --home /srv/.acme.sh --nocron ## License diff --git a/acme.sh b/acme.sh new file mode 160000 index 0000000..e6959f0 --- /dev/null +++ b/acme.sh @@ -0,0 +1 @@ +Subproject commit e6959f093c4e147b4a206f0b5d027ff3d0a59b80 From 3a8bbba846450124280fb1a8d8750fb9cbe4cd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 24 Oct 2022 08:20:43 +0200 Subject: [PATCH 06/10] Add --no-profile to acme.sh installation command Not messing with files under /root seems to be a saner default. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45c2418..535eb76 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ external storage on a Turris device, but you can install wherever you'd like. opkg install socat cd /srv/turris-omnia-tls/acme.sh - ./acme.sh --install --home /srv/.acme.sh --nocron --email [YOUREMAIL] + ./acme.sh --install --home /srv/.acme.sh --no-profile --nocron --email [YOUREMAIL] ./acme.sh --set-default-ca --home /srv/.acme.sh --server letsencrypt 1. Disable the existing SSL configuration by removing the @@ -111,7 +111,7 @@ Run the following: git pull git submodule update --remote acme.sh cd acme.sh - ./acme.sh --install --home /srv/.acme.sh --nocron + ./acme.sh --install --home /srv/.acme.sh --no-profile --nocron ## License From 29d181fac4ec161f99a90ef82efde58e93a80738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 24 Oct 2022 08:33:03 +0200 Subject: [PATCH 07/10] Move default acme installation below the turris-omnia-tls directory This makes the turris-omnia-tls directory self-contained and reduces the clutter below /srv. --- README.md | 4 ++-- cert-issue.sh | 24 +++++++++++++----------- cert-renew.sh | 11 +++++++---- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 535eb76..39a9122 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ external storage on a Turris device, but you can install wherever you'd like. opkg install socat cd /srv/turris-omnia-tls/acme.sh - ./acme.sh --install --home /srv/.acme.sh --no-profile --nocron --email [YOUREMAIL] + ./acme.sh --install --home /srv/turris-omnia-tls/var/acme --no-profile --nocron --email [YOUREMAIL] ./acme.sh --set-default-ca --home /srv/.acme.sh --server letsencrypt 1. Disable the existing SSL configuration by removing the @@ -111,7 +111,7 @@ Run the following: git pull git submodule update --remote acme.sh cd acme.sh - ./acme.sh --install --home /srv/.acme.sh --no-profile --nocron + ./acme.sh --install --home /srv/turris-omnia-tls/var/acme --no-profile --nocron ## License diff --git a/cert-issue.sh b/cert-issue.sh index 37d38e8..174d46c 100755 --- a/cert-issue.sh +++ b/cert-issue.sh @@ -1,21 +1,23 @@ #!/bin/sh certhome="/etc/lighttpd/certs" +tothome="/srv/turris-omnia-tls" +acmehome="${tothome}/var/acme" ca_path="/etc/ssl/certs" -webroot="/src/turris-omnia-tls/var/webroot" +webroot="${tothome}/var/webroot" domain="$1" mkdir -p "$certhome" mkdir -p "$webroot" -/srv/.acme.sh/acme.sh \ - --home "/srv/.acme.sh" \ +"${acmehome}/acme.sh" \ + --home "${acmehome}" \ --issue \ - --webroot "$webroot" \ - --domain "$domain" \ + --webroot "${webroot}" \ + --domain "${domain}" \ --keylength 4096 \ - --certhome "$certhome" \ - --ca-path "$ca_path" \ - --pre-hook "/srv/turris-omnia-tls/pre-hook.sh '$domain'" \ - --post-hook "/srv/turris-omnia-tls/post-hook.sh '$domain'" \ - --renew-hook "/srv/turris-omnia-tls/renew-hook.sh '$domain'" \ - --reloadcmd "/srv/turris-omnia-tls/reloadcmd.sh '$domain'" + --certhome "${certhome}" \ + --ca-path "${ca_path}" \ + --pre-hook "${tothome}/pre-hook.sh '$domain'" \ + --post-hook "${tothome}/post-hook.sh '$domain'" \ + --renew-hook "${tothome}/renew-hook.sh '$domain'" \ + --reloadcmd "${tothome}/reloadcmd.sh '$domain'" diff --git a/cert-renew.sh b/cert-renew.sh index 75d4380..60fc86c 100755 --- a/cert-renew.sh +++ b/cert-renew.sh @@ -1,8 +1,11 @@ #!/bin/sh certhome="/etc/lighttpd/certs" +tothome="/srv/turris-omnia-tls" +acmehome="${tothome}/var/acme" ca_path="/etc/ssl/certs" -/srv/.acme.sh/acme.sh \ - --home "/srv/.acme.sh" \ + +"${acmehome}/acme.sh" \ + --home "${tothome}" \ --cron \ - --certhome "$certhome" \ - --ca-path "$ca_path" + --certhome "${certhome}" \ + --ca-path "${ca_path}" From 81a400a47e5b5b46fde53a683fedc0747f0ca74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 24 Oct 2022 10:52:58 +0200 Subject: [PATCH 08/10] Add installation script The README.md instructions are fine....automation is even better :D --- README.md | 66 +++------------------- cert-issue.sh | 15 ++++- cert-renew.sh | 16 +++++- install.sh | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 61 deletions(-) create mode 100755 install.sh diff --git a/README.md b/README.md index 39a9122..f54b606 100644 --- a/README.md +++ b/README.md @@ -35,61 +35,15 @@ external storage on a Turris device, but you can install wherever you'd like. opkg install git-http git clone --recurse-submodules https://github.com/davidjb/turris-omnia-tls.git /srv/turris-omnia-tls -1. Install the `acme.sh` client and its dependency, `socat`; taking care to - substitute `[YOUREMAIL]` with correct values: +1. Run the `install.sh` script and answer the questions: - opkg install socat - cd /srv/turris-omnia-tls/acme.sh - ./acme.sh --install --home /srv/turris-omnia-tls/var/acme --no-profile --nocron --email [YOUREMAIL] - ./acme.sh --set-default-ca --home /srv/.acme.sh --server letsencrypt + /srv/turris-omnia-tls/install.sh -1. Disable the existing SSL configuration by removing the - `lighttpd-https-cert` package: +1. Alternatively, the answer to the questions can be provided via environment + variables for non-interactive/scripted use (check the source of `install.sh` + for a current list of supported variables): - opkg remove lighttpd-https-cert - -1. Stop `updater` from automatically reinstalling the `lighttpd-https-cert` - package: - - cp /srv/turris-omnia-tls/updater_custom.lua /etc/updater/conf.d/no-upstream-ssl.lua - -1. Make sure the `lighttpd-mod-openssl` package is installed: - - opkg install lighttpd-mod-openssl - -1. Reconfigure lighttpd to support the `acme` webroot, taking care to replace - the %TOT_BASEDIR% placeholder inside the template file: - - sed -e "s|%TOT_BASEDIR%|/srv/turris-omnia-tls|g" /srv/turris-omnia-tls/lighttpd_webroot.conf > /etc/lighttpd/conf.d/39-acme-webroot.conf - -1. Restart `lighttpd`: - - /etc/init.d/lighttpd restart - -1. Issue the certificate, taking care to specify your FQDN in place of - `[HOSTNAME.DOMAIN.COM]`: - - /srv/turris-omnia-tls/cert-issue.sh [HOSTNAME.DOMAIN.COM] - -1. Reconfigure lighttpd to enable TLS and to use the new certificates, taking - care to replace the %TOT_FQDN% and %TOT_HOSTNAME% placeholders inside the - template file: - - sed \ - -e "s|%TOT_FQDN%|turris.example.com|g" \ - -e "s|%TOT_HOSTNAME%|turris|g" \ - /srv/turris-omnia-tls/lighttpd_tls.conf > /etc/lighttpd/conf.d/40-acme-tls.conf - -1. Restart `lighttpd` again: - - /etc/init.d/lighttpd restart - -1. Add crontab entry for renewal; pick a random minute and hour: - - echo '34 0 * * * /srv/turris-omnia-tls/cert-renew.sh > /dev/null' >> /etc/crontabs/root - - The renewal process will automatically re-use the settings for certificates - that were issued. + TOT_EMAIL="foo@example.com" TOT_FQDN="turris.example.com" /srv/turris-omnia-tls/install.sh ## Issuing more certificates @@ -108,11 +62,9 @@ where `extra.example.com` is the name of your domain. Run the following: cd /srv/turris-omnia-tls - git pull - git submodule update --remote acme.sh - cd acme.sh - ./acme.sh --install --home /srv/turris-omnia-tls/var/acme --no-profile --nocron - + git pull --recurse-submodules + ./install.sh + ## License MIT. See LICENSE.txt. diff --git a/cert-issue.sh b/cert-issue.sh index 174d46c..f0dc65d 100755 --- a/cert-issue.sh +++ b/cert-issue.sh @@ -1,6 +1,17 @@ -#!/bin/sh +#!/usr/bin/env bash +# +# Copyright (C) 2018-2022 David Beitey +# Copyright (C) 2022 David Härdeman +# +# SPDX-License-Identifier: MIT +# +# This script is used once for the initial issuance of a certificate. + +set -o nounset -o pipefail -o errexit -o errtrace + +cd "${0%/*}" +tothome="$(pwd)" certhome="/etc/lighttpd/certs" -tothome="/srv/turris-omnia-tls" acmehome="${tothome}/var/acme" ca_path="/etc/ssl/certs" webroot="${tothome}/var/webroot" diff --git a/cert-renew.sh b/cert-renew.sh index 60fc86c..98e743f 100755 --- a/cert-renew.sh +++ b/cert-renew.sh @@ -1,6 +1,18 @@ -#!/bin/sh +#!/usr/bin/env bash +# +# Copyright (C) 2018-2022 David Beitey +# Copyright (C) 2022 David Härdeman +# +# SPDX-License-Identifier: MIT +# +# This script renews already issued certs and is meant to be executed +# periodically via e.g. cron. + +set -o nounset -o pipefail -o errexit -o errtrace + +cd "${0%/*}" +tothome="$(pwd)" certhome="/etc/lighttpd/certs" -tothome="/srv/turris-omnia-tls" acmehome="${tothome}/var/acme" ca_path="/etc/ssl/certs" diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..da28a98 --- /dev/null +++ b/install.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2022 David Härdeman +# +# SPDX-License-Identifier: MIT +# +# This script automates the installation of the Turris Omnia TLS project +# on a Turris Omnia router by asking a few questions (or obtaining them +# from environment variables). + +set -o nounset -o pipefail -o errexit -o errtrace + +cd "${0%/*}" + +TOT_SCRIPT="$(basename "${0}")" +readonly TOT_SCRIPT +TOT_BASEDIR="$(pwd)" +readonly TOT_BASEDIR +readonly TOT_ACMEDIR="${TOT_BASEDIR}/acme.sh" +readonly TOT_ACMEHOME="${TOT_BASEDIR}/var/acme" + +# Supported environment variables +TOT_EMAIL="${TOT_EMAIL:-}" +TOT_FQDN="${TOT_FQDN:-}" +TOT_HOSTNAME="${TOT_HOSTNAME:-}" + +log_message() { + # Display a log message if the script is used interactively, otherwise + # write the log message to syslog. + local msg="${1:-}" + + if [ -n "${msg}" ]; then + if [ -t 0 ]; then + echo "${TOT_SCRIPT}: ${msg}" 1>&2 + else + if type logger > /dev/null 2>&1; then + logger -t "${TOT_SCRIPT}[${PID}]" "${msg}" + fi + fi + fi +} + +template_install() { + # Install a template file to a given location, replacing variables + # formatted as %VARIABLE% with the proper value + local src="${1:-}" + local dst="${2:-}" + + if [ -n "${dst}" ] && [ -n "${src}" ]; then + sed \ + -e "s|%TOT_EMAIL%|${TOT_EMAIL}|g" \ + -e "s|%TOT_FQDN%|${TOT_FQDN}|g" \ + -e "s|%TOT_HOSTNAME%|${TOT_HOSTNAME}|g" \ + -e "s|%TOT_BASEDIR%|${TOT_BASEDIR}|g" \ + "${src}" > "${dst}" + fi +} + +add_crontab() { + local crontab="${1:-}" + local cmd="${TOT_BASEDIR}/cert-renew.sh" + + if [ -n "${crontab}" ]; then + if ! grep -q "^[[:space:]]*[^#].*${cmd}" "${crontab}"; then + echo "$(( RANDOM % 60 )) $(( RANDOM % 24 )) * * * ${cmd} > /dev/null" >> "${crontab}" + fi + fi +} + +prompt_input() { + # Ask the user for some input, unless a given variable is + # already defined (e.g. via environment variables) + local varname="${1:-}" + local msg="${2:-}" + local value="" + + if [ -n "${varname}" ] && [ -z "${!varname}" ] && [ -n "${msg}" ]; then + if [ ! -t 0 ]; then + log_message "non-interactive mode failed, missing options" + exit 1 + fi + + read -r -p "${msg}: " value + + if [ -z "${value}" ]; then + log_message "missing value for $varname" + exit 1 + fi + declare -g "${varname}"="${value}" + fi +} + +prompt_input "TOT_EMAIL" "Enter your email address" +prompt_input "TOT_FQDN" "Enter the FQDN of your router" +if [ -n "${TOT_FQDN}" ] && [ -z "${TOT_HOSTNAME}" ]; then + TOT_HOSTNAME="$(echo "${TOT_FQDN}" | cut -d '.' -f1)" +fi + +log_message "Installing the socat package" +opkg install socat > /dev/null + +log_message "Installing the acme.sh script" +mkdir -p "${TOT_ACMEHOME}" +# Note that acme.sh fails to perform the installation if we don't chdir +cd "${TOT_ACMEDIR}" + +./acme.sh \ + --home "${TOT_ACMEHOME}" \ + --install \ + --no-profile \ + --nocron \ + --email "${TOT_EMAIL}" + +log_message "Setting the default CA" +./acme.sh \ + --home "${TOT_ACMEHOME}" \ + --set-default-ca \ + --server letsencrypt + +cd "${TOT_BASEDIR}" + +log_message "Removing the lighttpd-https-cert package" +opkg remove lighttpd-https-cert > /dev/null + +log_message "Stop updater from automatically reinstalling lighttpd-https-cert" +cp updater_custom.lua /etc/updater/conf.d/no-upstream-ssl.lua + +log_message "Installing the lighttpd-mod-openssl package" +opkg install lighttpd-mod-openssl > /dev/null + +log_message "Installing custom lighttp webroot configuration" +template_install "lighttpd_webroot.conf" "/etc/lighttpd/conf.d/39-acme-webroot.conf" + +log_message "Restarting lighttpd" +/etc/init.d/lighttpd restart +sleep 3 + +log_message "Issuing certificate" +./cert-issue.sh "${TOT_FQDN}" + +log_message "Installing custom lighttp TLS configuration" +template_install "lighttpd_tls.conf" "/etc/lighttpd/conf.d/40-acme-tls.conf" + +log_message "Restarting lighttpd again" +/etc/init.d/lighttpd restart +sleep 3 + +log_message "Adding a crontab entry for certificate renewal" +add_crontab "/etc/crontabs/root" From a8bf9467d604179b65c5850a8144aaf9c47a87dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 24 Oct 2022 11:58:44 +0200 Subject: [PATCH 09/10] Use a custom crontab Using a custom crontab instead of messing with root's crontab makes installation/uninstallation easier. --- install.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/install.sh b/install.sh index da28a98..c4c2ce2 100755 --- a/install.sh +++ b/install.sh @@ -61,9 +61,8 @@ add_crontab() { local cmd="${TOT_BASEDIR}/cert-renew.sh" if [ -n "${crontab}" ]; then - if ! grep -q "^[[:space:]]*[^#].*${cmd}" "${crontab}"; then - echo "$(( RANDOM % 60 )) $(( RANDOM % 24 )) * * * ${cmd} > /dev/null" >> "${crontab}" - fi + echo 'MAILTO=""' > "${crontab}" + echo "$(( RANDOM % 60 )) $(( RANDOM % 24 )) * * * root ${cmd} > /dev/null" >> "${crontab}" fi } @@ -145,5 +144,5 @@ log_message "Restarting lighttpd again" /etc/init.d/lighttpd restart sleep 3 -log_message "Adding a crontab entry for certificate renewal" -add_crontab "/etc/crontabs/root" +log_message "Adding a cron job for certificate renewal" +add_crontab "/etc/cron.d/turris-omnia-tls" From 1958ea9ed3777c9beaecab6a33987b0ad9462da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 24 Oct 2022 12:05:36 +0200 Subject: [PATCH 10/10] Add an uninstallation script --- README.md | 11 +++++++++++ uninstall.sh | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100755 uninstall.sh diff --git a/README.md b/README.md index f54b606..f734123 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,17 @@ external storage on a Turris device, but you can install wherever you'd like. TOT_EMAIL="foo@example.com" TOT_FQDN="turris.example.com" /srv/turris-omnia-tls/install.sh +## Uninstallation + +Note that this will not touch issued certificates, which will be left in place +under `/etc/lighttpd/certs`. Also, `acme.sh` related state information will be +left untouched under the `/srv/turris-omnia-tls/var/` hierarchy. + +1. Run the `uninstall.sh` script to uninstall modifications performed by the + `install.sh` script: + + /srv/turris-omnia-tls/uninstall.sh + ## Issuing more certificates Run the following: diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..24fd1a7 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2022 David Härdeman +# +# SPDX-License-Identifier: MIT +# +# This script automates the uninstallation of the Turris Omnia TLS project +# on a Turris Omnia router. Certificates will not be deleted from the +# file system. + +set -o nounset -o pipefail -o errexit -o errtrace + +log_message() { + # Display a log message if the script is used interactively, otherwise + # write the log message to syslog. + local msg="${1:-}" + + if [ -n "${msg}" ]; then + if [ -t 0 ]; then + echo "${TOT_SCRIPT}: ${msg}" 1>&2 + else + if type logger > /dev/null 2>&1; then + logger -t "${TOT_SCRIPT}[${PID}]" "${msg}" + fi + fi + fi +} + +log_message "Removing cron job for certificate renewal" +rm -f "/etc/cron.d/turris-omnia-tls" + +log_message "Removing custom lighttp webroot configuration" +rm -f "/etc/lighttpd/conf.d/39-acme-webroot.conf" + +log_message "Removing custom lighttp TLS configuration" +rm -f "/etc/lighttpd/conf.d/40-acme-tls.conf" + +log_message "Removing updater configuration" +rm -f "/etc/updater/conf.d/no-upstream-ssl.lua" + +log_message "Reinstalling the lighttpd-https-cert package" +opkg install lighttpd-https-cert > /dev/null + +log_message "Restarting lighttpd" +/etc/init.d/lighttpd restart