diff --git a/manifest.jps b/manifest.jps index 2bdf9082..a4d20b2e 100644 --- a/manifest.jps +++ b/manifest.jps @@ -104,7 +104,8 @@ onInstall: - setGlobals: nodeId: ${settings.nodeId:} nodeGroup: ${targetNodes.nodeGroup:} - withExtIp: ${settings.withExtIp:true} + withExtIp: ${settings.withExtIp:} + withIntSSL: ${settings.withIntSSL:true} webroot: ${settings.webroot:} webrootPath: ${settings.webrootPath:} fallbackToX1: ${settings.fallbackToX1:} @@ -167,6 +168,8 @@ onUninstall: - removeExecutedEnvFile: nodeGroup: ${targetNodes.nodeGroup} app_id: ${globals.app_id} + - callScript: + action: uninstall - delete onBeforeDelete: delete @@ -192,6 +195,7 @@ actions: undeployHook: ${globals.undeployHook} undeployHookType: ${globals.undeployHookType} withExtIp: ${globals.withExtIp} + withIntSSL: ${globals.withIntSSL} webroot: ${globals.webroot} webrootPath: ${globals.webrootPath} fallbackToX1: ${globals.fallbackToX1} @@ -266,6 +270,7 @@ actions: deployHookType: ${globals.deployHookType} undeployHookType: ${globals.undeployHookType} withExtIp: ${globals.withExtIp} + withIntSSL: ${globals.withIntSSL} webroot: ${globals.webroot} webrootPath: ${globals.webrootPath} fallbackToX1: ${globals.fallbackToX1} diff --git a/scripts/auto-update-ssl-cert.sh b/scripts/auto-update-ssl-cert.sh index 803801a5..f3a8589c 100755 --- a/scripts/auto-update-ssl-cert.sh +++ b/scripts/auto-update-ssl-cert.sh @@ -9,6 +9,7 @@ SED=$(which sed) GIT=$(which git); BASE_REPO_URL="https://github.com/jelastic-jps/lets-encrypt" RAW_REPO_SCRIPS_URL="https://raw.githubusercontent.com/jelastic-jps/lets-encrypt/master/scripts/" +SETTINGS_CUSTOM="/var/lib/jelastic/keys/letsencrypt/settings-custom" [[ -z "$WGET" || -z "$OPENSSL" || -z "$GREP" || -z "$SED" || -z "$GIT" ]] && { echo "PATH not set with neccessary commands"; exit 3 ; } @@ -39,6 +40,7 @@ function updateScripts(){ updateScripts [ -f "${DIR}/opt/letsencrypt/settings" ] && source "${DIR}/opt/letsencrypt/settings" || { echo "No settings available" ; exit 3 ; } +[ -f "${DIR}${SETTINGS_CUSTOM}" ] && source "${DIR}${SETTINGS_CUSTOM}" [ -f "${DIR}/root/validation.sh" ] && source "${DIR}/root/validation.sh" || { echo "No validation library available" ; exit 3 ; } validateExtIP diff --git a/scripts/create-installation-script.js b/scripts/create-installation-script.js index 40f0ddc9..4fa574cf 100644 --- a/scripts/create-installation-script.js +++ b/scripts/create-installation-script.js @@ -11,8 +11,9 @@ var baseDir = getParam("baseDir", "/"), undeployHook = getParam("undeployHook", ""), undeployHookType = getParam("undeployHookType", ""), withExtIp = getParam("withExtIp", ""), + withIntSSL = getParam("withIntSSL", ""), webroot = getParam("webroot", ""), - webrootPath = getParam("webrootPath", ""), + webrootPath = getParam("webrootPath", ""), appId = getParam("appId", "letsencrypt-ssl-addon"), fallbackToX1 = getParam("fallbackToX1", ""), test = getParam("test", ""), @@ -34,6 +35,7 @@ function run() { undeployHook : replace(undeployHook), undeployHookType : replace(undeployHookType), withExtIp : replace(withExtIp) || "", + withIntSSL : replace(withIntSSL) || "", fallbackToX1 : replace(fallbackToX1) || "", webroot : replace(webroot) || "", webrootPath : replace(webrootPath) || "", diff --git a/scripts/generate-ssl-cert.sh b/scripts/generate-ssl-cert.sh index 9e69c687..c22af26f 100644 --- a/scripts/generate-ssl-cert.sh +++ b/scripts/generate-ssl-cert.sh @@ -1,6 +1,6 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.."; -LOG_FILE=$DIR/var/log/letsencrypt/letsencrypt.log-$(date '+%s') +DEFAULT_LOG_FILE=$DIR/var/log/letsencrypt/letsencrypt.log-$(date '+%s') KEYS_DIR="$DIR/var/lib/jelastic/keys/" SETTINGS="$DIR/opt/letsencrypt/settings" DOMAIN_SEP=" -d " @@ -51,18 +51,27 @@ mkdir -p $DIR/var/log/letsencrypt [[ "$webroot" == "false" ]] && { service tinyproxy start || { echo "Failed to start proxy server" ; exit 3 ; } + if grep -a 'AlmaLinux' /etc/system-release ; then + /usr/sbin/nft insert rule ip filter INPUT tcp dport ${PROXY_PORT} counter accept comment "LE" + /usr/sbin/nft insert rule ip filter INPUT tcp dport ${LE_PORT} counter accept comment "LE" + /usr/sbin/nft insert rule ip6 filter INPUT tcp dport ${LE_PORT} counter accept comment "LE" + /usr/sbin/nft insert rule ip nat PREROUTING ip saddr != 127.0.0.1 tcp dport 80 counter redirect to ${PROXY_PORT} comment "LE" + /usr/sbin/nft insert rule ip6 nat PREROUTING ip6 saddr ::0 ip6 daddr ::0 tcp dport 80 counter redirect to ${LE_PORT} comment "LE" || \ + /usr/sbin/nft insert rule ip6 filter INPUT tcp dport 80 counter drop comment "LE" + else iptables -I INPUT -p tcp -m tcp --dport ${PROXY_PORT} -j ACCEPT iptables -I INPUT -p tcp -m tcp --dport ${LE_PORT} -j ACCEPT ip6tables -I INPUT -p tcp -m tcp --dport ${LE_PORT} -j ACCEPT iptables -t nat -I PREROUTING -p tcp -m tcp ! -s 127.0.0.1/32 --dport 80 -j REDIRECT --to-ports ${PROXY_PORT} ip6tables -t nat -I PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports ${LE_PORT} || ip6tables -I INPUT -p tcp -m tcp --dport 80 -j DROP + fi } result_code=$GENERAL_RESULT_ERROR; while [ "$result_code" != "0" ] do [[ -z $domain ]] && break; - LOG_FILE=$LOG_FILE"-"$counter + LOG_FILE=$DEFAULT_LOG_FILE"-"$counter resp=$($DIR/opt/letsencrypt/acme.sh --issue $params $test_params --listen-v6 --domain $domain --nocron -f --log-level 2 --log $LOG_FILE 2>&1) @@ -113,8 +122,7 @@ do all_invalid_domains_errors+=$error";" all_invalid_domains+=$invalid_domain" " - domain=$(echo $domain | sed 's/'${invalid_domain}'\(\s-d\s\)\?//') - domain=$(echo $domain | sed "s/\s-d$//") + domain=$(echo $domain | sed 's/^'${invalid_domain}'\s-d\s//' | sed 's/\s-d\s'${invalid_domain}'\s-d\s//' | sed 's/\s-d\s'${invalid_domain}'$//') } counter=$((counter + 1)) done @@ -129,12 +137,21 @@ domain=$(echo $domain | sed -r "s/\s-d//g"); sed -i "s|^domain=.*|domain='${domain}'|g" ${SETTINGS}; [[ "$webroot" == "false" ]] && { + if grep -a 'AlmaLinux' /etc/system-release ; then + for _family in ip ip6; do + for _table in 'filter INPUT' 'nat PREROUTING'; do + for handle in $(nft -a list table $_family ${_table/ *} | grep 'comment \"LE\"'| sed -r 's/.*#\s+handle\s+([0-9]+)/\1/g' 2>/dev/null); do + /usr/sbin/nft delete rule $_family $_table handle $handle; + done + done + done + else iptables -t nat -D PREROUTING -p tcp -m tcp ! -s 127.0.0.1/32 --dport 80 -j REDIRECT --to-ports ${PROXY_PORT} ip6tables -t nat -D PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports ${LE_PORT} || ip6tables -I INPUT -p tcp -m tcp --dport 80 -j ACCEPT iptables -D INPUT -p tcp -m tcp --dport ${PROXY_PORT} -j ACCEPT iptables -D INPUT -p tcp -m tcp --dport ${LE_PORT} -j ACCEPT ip6tables -D INPUT -p tcp -m tcp --dport ${LE_PORT} -j ACCEPT - + fi service tinyproxy stop || echo "Failed to stop proxy server" chkconfig tinyproxy off } diff --git a/scripts/install-le.sh b/scripts/install-le.sh index f872b59a..dc0b7a11 100644 --- a/scripts/install-le.sh +++ b/scripts/install-le.sh @@ -27,10 +27,17 @@ echo "Installing required packages" } } } - yum-config-manager --save --setopt=\*.retries=5 --setopt=\*.skip_if_unavailable=true --setopt=\*.timeout=5 - yum -y install epel-release git bc nss; - yum -y install tinyproxy socat --enablerepo='epel'; - + if grep -a 'AlmaLinux' /etc/system-release ; then + microdnf -y install epel-release; microdnf install -y git bc nss socat --enablerepo='epel'; + wget http://repository.jelastic.com/pub/tinyproxy-1.8.3-2.el9.x86_64.rpm -O /tmp/tinyproxy-1.8.3-2.el9.x86_64.rpm + dnf install -y /tmp/tinyproxy-1.8.3-2.el9.x86_64.rpm --disablerepo=* ; rm -f /tmp/tinyproxy-1.8.3-2.el9.x86_64.rpm + else + + yum-config-manager --save --setopt=\*.retries=5 --setopt=\*.skip_if_unavailable=true --setopt=\*.timeout=5 + yum -y install epel-release git bc nss; + yum -y install tinyproxy socat --enablerepo='epel'; + fi + mkdir -p ${DIR}/opt; [[ -z $CLIENT_VERSION ]] && { diff --git a/scripts/install-ssl.js b/scripts/install-ssl.js index 3f3da1dd..8ab971ac 100644 --- a/scripts/install-ssl.js +++ b/scripts/install-ssl.js @@ -32,6 +32,7 @@ function run() { undeployHook : "${undeployHook}", undeployHookType : "${undeployHookType}", withExtIp : "${withExtIp}", + withIntSSL : "${withIntSSL}", webroot : "${webroot}", webrootPath : "${webrootPath}", fallbackToX1 : "${fallbackToX1}", diff --git a/scripts/ssl-manager.js b/scripts/ssl-manager.js index 4f9d9ef7..22cb1c0a 100644 --- a/scripts/ssl-manager.js +++ b/scripts/ssl-manager.js @@ -24,6 +24,7 @@ function SSLManager(config) { * [undeployHook] : {String} * [undeployHookType] : {String} * [withExtIp] : {Boolean} + * [withIntSSL] : {Boolean} * [webroot] : {Boolean} * [webrootPath] : {String} * [test] : {Boolean} @@ -131,6 +132,7 @@ function SSLManager(config) { var resp = me.exec([ [ me.initCustomConfigs ], [ me.initAddOnExtIp, config.withExtIp ], + [ me.initIntSSL, config.withIntSSL ], [ me.initWebrootMethod, config.webroot ], [ me.initFalbackToFake, config.fallbackToX1 ], [ me.initEntryPoint ], @@ -325,6 +327,7 @@ function SSLManager(config) { webroot : config.webroot || "", webrootPath : config.webrootPath || "", withExtIp : config.withExtIp, + withIntSSL : config.withIntSSL, customDomains : me.getCustomDomains(), nodeGroup : config.nodeGroup || "", deployHook : config.deployHook || "", @@ -595,9 +598,12 @@ function SSLManager(config) { }; me.createScriptAndInstall = function createInstallationScript() { - var resp = me.exec([ - [ me.initCustomConfigs ], + var resp = me.initCustomConfigs(); + if (resp.result != 0) return resp; + + resp = me.exec([ [ me.initAddOnExtIp, config.withExtIp ], + [ me.initIntSSL, config.withIntSSL ], [ me.initWebrootMethod, config.webroot ], [ me.initFalbackToFake, config.fallbackToX1 ], [ me.applyCustomDomains, config.customDomains ], @@ -716,6 +722,12 @@ function SSLManager(config) { return { result: 0 }; }; + me.initIntSSL = function initIntSSL(withIntSSL) { + withIntSSL = String(withIntSSL) || false; + config.withIntSSL = me.initBoolValue(withIntSSL); + return { result: 0 }; + }; + me.initAddOnExtIp = function initAddOnExtIp(withExtIp) { var resp; @@ -1083,7 +1095,7 @@ function SSLManager(config) { withExtIp : config.withExtIp, webroot : config.webroot, webrootPath : config.webrootPath || "", - skipped : config.skippedDomains || "", + skipped : me.getSkippedDomains().join(DOMAINS_SEP), updateDecreased: !!config.updateDecreased, updateDisabled: !!config.updateDisabled }), @@ -1330,14 +1342,38 @@ function SSLManager(config) { //managing certificate challenge validation by routing all requests to master node with let's encrypt engine me.manageDnat = function manageDnat(action) { - return nodeManager.cmd( - "ip a | grep -q '%(nodeIp)' || { iptables -t nat %(action) PREROUTING -p tcp --dport 80 -j DNAT --to-destination %(nodeIp):80; iptables %(action) FORWARD -p tcp -j ACCEPT; iptables -t nat %(action) POSTROUTING -d %(nodeIp) -j MASQUERADE; }", - { - nodeGroup : config.nodeGroup, - nodeIp : config.nodeIp, - action : action == 'add' ? '-I' : '-D' - } - ); + var GREP_IP = "ip a | grep -q '%(nodeIp)'", + GREP_ALMA = "grep -q 'AlmaLinux' /etc/system-release", + CENTOS_IPTABLES = "iptables -t nat %(action) PREROUTING -p tcp --dport 80 -j DNAT --to-destination %(nodeIp):80; iptables %(action) FORWARD -p tcp -j ACCEPT; iptables -t nat %(action) POSTROUTING -d %(nodeIp) -j MASQUERADE;", + ALMA_LINUX_ADD_RULES = "/usr/sbin/nft insert rule ip nat PREROUTING tcp dport 80 counter dnat to %(nodeIp):80 comment \"LEmasq\"; /usr/sbin/nft insert rule ip filter FORWARD meta l4proto tcp counter accept comment \"LEmasq\"; /usr/sbin/nft insert rule ip nat POSTROUTING ip daddr %(nodeIp) counter masquerade comment \"LEmasq\"; ", + ALMA_LINUX_REMOVE_RULES = "for _table in 'filter FORWARD' 'nat PREROUTING' 'nat POSTROUTING'; do for handle in $(nft -a list chain ip $_table | grep 'comment \"LEmasq\"' | sed -rn 's|.*#\shandle\s([0-9])|\1|p'); do /usr/sbin/nft delete rule ip $_table handle $handle; done; done;", + resp; + + if (action == 'add'){ + resp = nodeManager.cmd( + GREP_ALMA + " && { " + GREP_IP + " || { %(almaLinux) } } || { " + GREP_IP + " || { %(centOS) } }", + { + almaLinux : ALMA_LINUX_ADD_RULES, + centOS : CENTOS_IPTABLES, + action : '-I', + nodeGroup : config.nodeGroup, + nodeIp : config.nodeIp + } + ); + }else{ + resp = nodeManager.cmd( + GREP_ALMA + " && { " + GREP_IP + " || { %(almaLinux) } } || { " + GREP_IP + " || { %(centOS) } }", + { + action : '-D', + almaLinux : ALMA_LINUX_REMOVE_RULES, + centOS : CENTOS_IPTABLES, + nodeGroup : config.nodeGroup, + nodeIp : config.nodeIp + } + ); + } + + return resp; }; me.checkEnvSsl = function checkEnvSsl() { @@ -1488,7 +1524,12 @@ function SSLManager(config) { cert: cert.body, interm: chain.body }); + me.exec(me.bindSSLCerts); + + if (config.withIntSSL && nodeManager.checkCustomSSL()) { + me.exec(me.bindSSLOnExtraNode, cert_key.body, cert.body, chain.body); + } } } else { resp = error(Response.ERROR_UNKNOWN, "Can't read SSL certificate: key=%(key) cert=%(cert) chain=%(chain)", {