From 4d17c93ca6ccafce2e2e0ff2623dcc16f3f46ff8 Mon Sep 17 00:00:00 2001 From: lodzen Date: Mon, 24 Jun 2024 16:24:43 +0200 Subject: [PATCH] Added dns challenge authentication for ipv64, Updated script to work behind NAT --- settings.sh | 10 +++ setup-nextcloud-hpb.sh | 81 ++++++++++++++++++++++++ src/setup-certbot.sh | 136 +++++++++++++++++++++++++++++++---------- src/setup-signaling.sh | 18 ++++-- 4 files changed, 206 insertions(+), 39 deletions(-) diff --git a/settings.sh b/settings.sh index 58f2317..692be8b 100644 --- a/settings.sh +++ b/settings.sh @@ -28,6 +28,11 @@ UNATTENDED_INSTALL=false #SSL_CHAIN_PATH_ECDSA="" #DHPARAM_PATH="" +# If you are running the script behind a NAT you need to specify it with true +# make sure that the webserver are reachable from the internet via +# port (80 only if http cert auth method is used), 443 & 5349 (TCP & UDP) +BEHIND_NAT="" + # Collabora (Gets asked anyway, except unattended install.) SHOULD_INSTALL_COLLABORA=true @@ -40,6 +45,11 @@ SHOULD_INSTALL_CERTBOT=true SHOULD_INSTALL_UNATTENDEDUPGRADES=true SHOULD_INSTALL_MSMTP=true +#Select between http and ipv64 DNS Challenage +CERTBOT_AUTH_METHOD="" +#Becomes mandatory if Certbot Auth method ipv64 is specified +IPV64_API_KEY="" + # Logfile get created if UNATTENDED_INSTALL is true. # Leave empty, if you wish that the user will be asked about this. LOGFILE_PATH="./setup-nextcloud-hpb-$(date +%Y-%m-%dT%H:%M:%SZ).log" diff --git a/setup-nextcloud-hpb.sh b/setup-nextcloud-hpb.sh index 8ed6711..9bae89d 100755 --- a/setup-nextcloud-hpb.sh +++ b/setup-nextcloud-hpb.sh @@ -7,7 +7,9 @@ set -eo pipefail # See settings.sh DRY_RUN=false UNATTENDED_INSTALL=false +BEHIND_NAT="" # Ask user NEXTCLOUD_SERVER_FQDNS="" # Ask user +CERTBOT_AUTH_METHOD="" # Ask user SERVER_FQDN="" # Ask user SSL_CERT_PATH_RSA="" # Will be auto filled, if not overriden by settings file. SSL_CERT_KEY_PATH_RSA="" # Will be auto filled, if not overriden by settings file. @@ -65,6 +67,85 @@ function show_dialogs() { fi log "Using '$DRY_RUN' for DRY_RUN". + if [ "$BEHIND_NAT" = "" ]; then + if [ "$UNATTENDED_INSTALL" = true ]; then + log "Can't continue since this is a non-interactive installation and I'm missing BEHIND_NAT!" + exit 1 + fi + + if whiptail --title "Are you behind a NAT?" --yesno "Are you running the server $( + )behind a NAT? Make sure that the ports (80 only if http cert auth method is used), 443 and 5349 (TCP & UDP) $( + )are opened in the Firewall." 10 65 --defaultno; then + BEHIND_NAT=true + else + BEHIND_NAT=false + fi + fi + log "BEHIND_NAT '$BEHIND_NAT' selected.". + + if [ "$CERTBOT_AUTH_METHOD" = "" ]; then + CHOICES=$(whiptail --title "Select Certbot Authentication Method" \ + --menu "Use the space bar key to select/deselect the AUTH Method $( + )you want to use." 15 90 2 \ + "1" "Use HTTP Challenge" \ + "2" "Use IPv64.net DNS Challenge" \ + 3>&1 1>&2 2>&3 || true) + + if [ -z "$CHOICES" ]; then + log "No AUTH Method was selected (user hit Cancel or unselected all options) Exiting…" + exit 0 + else + for CHOICE in $CHOICES; do + case "$CHOICE" in + "1") + CERTBOT_AUTH_METHOD="http" + ;; + "2") + CERTBOT_AUTH_METHOD="ipv64" + ;; + *) + log "Unsupported service $CHOICE!" >&2 + exit 1 + ;; + esac + done + fi + fi + log "Using '$CERTBOT_AUTH_METHOD' for CERTBOT_AUTH_METHOD". + + IPV64_API_KEY_FILE="./credentials.ini" + if [ "$CERTBOT_AUTH_METHOD" = "ipv64" ]; then + if [ "$IPV64_API_KEY" = "" ]; then + if [ "$UNATTENDED_INSTALL" = true ]; then + log "Can't continue since this is a non-interactive installation and I'm" \ + "missing IPV64_API_KEY!" + exit 1 + fi + + IPV64_API_KEY_Old="123456789abcdefg123456789abcdefg" + if [ -e "$IPV64_API_KEY_FILE" ]; then + # Rebuilding dhparam file. + IPV64_API_KEY_Old=$(sed -r "s#dns_ipv64_bearer_token = ?##gi" credentials.ini) + fi + IPV64_API_KEY=$( + whiptail --title "IPV64.de API Key" \ + --inputbox "Please enter your IPV64.de API Key here. $( + )" 12 65 \ + "$IPV64_API_KEY_Old" 3>&1 1>&2 2>&3 + ) + fi + + if [ -e "$IPV64_API_KEY_FILE" ]; then + # Rebuilding dhparam file. + log "Removing old Credential file at '$IPV64_API_KEY_FILE'." + rm -fv "$IPV64_API_KEY_FILE/credentials.ini" 2>&1 | tee -a "$LOGFILE_PATH" + fi + + touch credentials.ini + echo "dns_ipv64_bearer_token = $IPV64_API_KEY" > "credentials.ini" + log "Created credentials.ini at $IPV64_API_KEY_FILE" + fi + if [ "$NEXTCLOUD_SERVER_FQDNS" = "" ]; then if [ "$UNATTENDED_INSTALL" = true ]; then log "Can't continue since this is a non-interactive installation and I'm" \ diff --git a/src/setup-certbot.sh b/src/setup-certbot.sh index f90a5ff..ecd0f36 100644 --- a/src/setup-certbot.sh +++ b/src/setup-certbot.sh @@ -32,11 +32,30 @@ function run_certbot_command() { error_title_ratelimited="LetsEncrypt rate limit reached!" # RSA certificate - certbot_args=(certonly --nginx $arg_staging $arg_interactive $arg_dry_run - --key-path "$SSL_CERT_KEY_PATH_RSA" --domains "$SERVER_FQDN" - --fullchain-path "$SSL_CERT_PATH_RSA" --email "$EMAIL_USER_ADDRESS" - --rsa-key-size 4096 --cert-name "$SERVER_FQDN"-rsa - --chain-path "$SSL_CHAIN_PATH_RSA") + case "$CERTBOT_AUTH_METHOD" in + "http") + certbot_args=(certonly --nginx $arg_staging $arg_interactive $arg_dry_run + --key-path "$SSL_CERT_KEY_PATH_RSA" --domains "$SERVER_FQDN" + --fullchain-path "$SSL_CERT_PATH_RSA" --email "$EMAIL_USER_ADDRESS" + --rsa-key-size 4096 --cert-name "$SERVER_FQDN"-rsa + --chain-path "$SSL_CHAIN_PATH_RSA") + ;; + "ipv64") + certbot_args=(certonly $arg_staging $arg_interactive $arg_dry_run + --key-path "$SSL_CERT_KEY_PATH_RSA" --domains "$SERVER_FQDN" + --fullchain-path "$SSL_CERT_PATH_RSA" --email "$EMAIL_USER_ADDRESS" + --rsa-key-size 4096 --cert-name "$SERVER_FQDN"-rsa + --chain-path "$SSL_CHAIN_PATH_RSA" + --authenticator dns-ipv64 + --dns-ipv64-credentials "credentials.ini" + --dns-ipv64-propagation-seconds 30) + ;; + *) + log "Unsupported AUTH Method $CERTBOT_AUTH_METHOD!" >&2 + exit 1 + ;; + esac + log "Executing Certbot using arguments: '${certbot_args[@]}'…" @@ -62,11 +81,29 @@ function run_certbot_command() { fi # ECDSA certificate - certbot_args=(certonly --nginx $arg_staging $arg_interactive $arg_dry_run - --key-path "$SSL_CERT_KEY_PATH_ECDSA" --domains "$SERVER_FQDN" - --fullchain-path "$SSL_CERT_PATH_ECDSA" --email "$EMAIL_USER_ADDRESS" - --key-type ecdsa --cert-name "$SERVER_FQDN"-ecdsa - --chain-path "$SSL_CHAIN_PATH_ECDSA") + case "$CERTBOT_AUTH_METHOD" in + "http") + certbot_args=(certonly --nginx $arg_staging $arg_interactive $arg_dry_run + --key-path "$SSL_CERT_KEY_PATH_ECDSA" --domains "$SERVER_FQDN" + --fullchain-path "$SSL_CERT_PATH_ECDSA" --email "$EMAIL_USER_ADDRESS" + --key-type ecdsa --cert-name "$SERVER_FQDN"-ecdsa + --chain-path "$SSL_CHAIN_PATH_ECDSA") + ;; + "ipv64") + certbot_args=(certonly $arg_staging $arg_interactive $arg_dry_run + --key-path "$SSL_CERT_KEY_PATH_ECDSA" --domains "$SERVER_FQDN" + --fullchain-path "$SSL_CERT_PATH_ECDSA" --email "$EMAIL_USER_ADDRESS" + --key-type ecdsa --cert-name "$SERVER_FQDN"-ecdsa + --chain-path "$SSL_CHAIN_PATH_ECDSA" + --authenticator dns-ipv64 + --dns-ipv64-credentials "credentials.ini" + --dns-ipv64-propagation-seconds 30) + ;; + *) + log "Unsupported AUTH Method $CERTBOT_AUTH_METHOD!" >&2 + exit 1 + ;; + esac log "Executing Certbot using arguments: '${certbot_args[@]}'…" @@ -92,30 +129,30 @@ function run_certbot_command() { fi # Force renewal of certificates - certbot_args=(renew --force-renewal $arg_staging $arg_interactive $arg_dry_run) + # certbot_args=(renew --force-renewal $arg_staging $arg_interactive $arg_dry_run) - log "Executing Certbot using arguments: '${certbot_args[@]}'…" + # log "Executing Certbot using arguments: '${certbot_args[@]}'…" - if certbot "${certbot_args[@]}" |& tee -a $LOGFILE_PATH; then - return 0 - else - # Checking if Certbot reported rate limit error - # Let the user decide if they want staging certificates (for testing - # purposes for example). - error_ratelimited="$(tail $LOGFILE_PATH | grep 'too many certificates (5) already issued for this exact set of domains in the last 168 hours')" - if [ -n "$error_ratelimited" ]; then - if [ "$UNATTENDED_INSTALL" != true ]; then - if whiptail --title "$error_title_ratelimited" --defaultno \ - --yesno "$error_message_ratelimited $error_message_ratelimited_extra" 16 65 3>&1 1>&2 2>&3; then - # Recursively call this function - run_certbot_command "true" - return 0 - fi - else - log "$error_message_ratelimited" - fi - fi - fi + # if certbot "${certbot_args[@]}" |& tee -a $LOGFILE_PATH; then + # return 0 + # else + # # Checking if Certbot reported rate limit error + # # Let the user decide if they want staging certificates (for testing + # # purposes for example). + # error_ratelimited="$(tail $LOGFILE_PATH | grep 'too many certificates (5) already issued for this exact set of domains in the last 168 hours')" + # if [ -n "$error_ratelimited" ]; then + # if [ "$UNATTENDED_INSTALL" != true ]; then + # if whiptail --title "$error_title_ratelimited" --defaultno \ + # --yesno "$error_message_ratelimited $error_message_ratelimited_extra" 16 65 3>&1 1>&2 2>&3; then + # # Recursively call this function + # run_certbot_command "true" + # return 0 + # fi + # else + # log "$error_message_ratelimited" + # fi + # fi + # fi } function install_certbot() { @@ -130,7 +167,27 @@ function install_certbot() { function certbot_step1() { log "\nStep 1: Installing Certbot packages" - packages_to_install=(python3-certbot-nginx certbot ssl-cert) + if [ "$CERTBOT_AUTH_METHOD" = "" ]; then + if [ "$UNATTENDED_INSTALL" = true ]; then + log "Can't continue since this is a non-interactive installation and I'm" \ + "missing CERTBOT_AUTH_METHOD!" + exit 1 + fi + fi + + case "$CERTBOT_AUTH_METHOD" in + "http") + packages_to_install=(python3-certbot-nginx certbot ssl-cert) + ;; + "ipv64") + packages_to_install=(git python3-setuptools python3-certbot-nginx certbot ssl-cert) + ;; + *) + log "Unsupported Certbot AUTH method: $CERTBOT_AUTH_METHOD!" >&2 + exit 1 + ;; + esac + if ! is_dry_run; then if [ "$UNATTENDED_INSTALL" == true ]; then log "Trying unattended install for Certbot." @@ -139,6 +196,19 @@ function certbot_step1() { else apt-get install -y "${packages_to_install[@]}" 2>&1 | tee -a $LOGFILE_PATH fi + if [ "$CERTBOT_AUTH_METHOD" = "ipv64" ]; then + CERTBOT_PLUGIN_DIR="./certbot-dns-ipv64" + if [ -e "$CERTBOT_PLUGIN_DIR" ]; then + log "Deleted contents of '$CERTBOT_PLUGIN_DIR'." + rm -vrf "$CERTBOT_PLUGIN_DIR" 2>&1 | tee -a $LOGFILE_PATH || true + fi + git clone https://github.com/lodzen/certbot-dns-ipv64.git 2>&1 | tee -a $LOGFILE_PATH + cd certbot-dns-ipv64 + git checkout fix-dns-zone 2>&1 | tee -a $LOGFILE_PATH + python3 ./setup.py build 2>&1 | tee -a $LOGFILE_PATH + python3 ./setup.py install 2>&1 | tee -a $LOGFILE_PATH + cd ../ + fi else log "Would have installed '${packages_to_install[@]}' via APT now." fi diff --git a/src/setup-signaling.sh b/src/setup-signaling.sh index 3a08979..ef8af87 100644 --- a/src/setup-signaling.sh +++ b/src/setup-signaling.sh @@ -550,13 +550,19 @@ function signaling_step4() { log "Replacing '' with '$DHPARAM_PATH'…" sed -i "s||$DHPARAM_PATH|g" "$TMP_DIR_PATH"/signaling/* - EXTERN_IPv4=$(wget -4 ident.me -O - -o /dev/null || true) - log "Replacing '' with '$EXTERN_IPv4'…" - sed -i "s||$EXTERN_IPv4|g" "$TMP_DIR_PATH"/signaling/* + if [ "$BEHIND_NAT" = true ]; then + log "Running behind NAT, commenting out external IP's for TURN" + sed -i "//,//s/^/#/" "$TMP_DIR_PATH"/signaling/* + sed -i "s|listening-ip=127.0.0.1|listening-ip=0.0.0.0|g" "$TMP_DIR_PATH"/signaling/* + else + EXTERN_IPv4=$(wget -4 ident.me -O - -o /dev/null || true) + log "Replacing '' with '$EXTERN_IPv4'…" + sed -i "s||$EXTERN_IPv4|g" "$TMP_DIR_PATH"/signaling/* - EXTERN_IPv6=$(wget -6 ident.me -O - -o /dev/null || true) - log "Replacing '' with '$EXTERN_IPv6'…" - sed -i "s||$EXTERN_IPv6|g" "$TMP_DIR_PATH"/signaling/* + EXTERN_IPv6=$(wget -6 ident.me -O - -o /dev/null || true) + log "Replacing '' with '$EXTERN_IPv6'…" + sed -i "s||$EXTERN_IPv6|g" "$TMP_DIR_PATH"/signaling/* + fi } function signaling_step5() {