From d5b7a679b86f9af1e46bf6920c37a38aa15d0ec9 Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Mon, 15 Feb 2021 23:44:28 +0100 Subject: [PATCH] net/haproxy: add basic OCSP stapling support, closes #1430 --- net/haproxy/pkg-descr | 2 + .../HAProxy/forms/generalSettings.xml | 6 ++ .../app/models/OPNsense/HAProxy/HAProxy.xml | 4 ++ .../scripts/OPNsense/HAProxy/exportCerts.php | 6 ++ .../scripts/OPNsense/HAProxy/setup.sh | 9 +++ .../scripts/OPNsense/HAProxy/updateOcsp.sh | 70 +++++++++++++++++++ .../conf/actions.d/actions_haproxy.conf | 9 +++ .../templates/OPNsense/HAProxy/rc.conf.d | 5 ++ 8 files changed, 111 insertions(+) create mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/updateOcsp.sh diff --git a/net/haproxy/pkg-descr b/net/haproxy/pkg-descr index 511582ebe..3c0d71c5f 100644 --- a/net/haproxy/pkg-descr +++ b/net/haproxy/pkg-descr @@ -16,6 +16,7 @@ Added: * add config export (#2035) * add config diff * guard against broken config by using a staging config file +* add basic OCSP stapling support (#1430) Fixed: * fix maintenance page (python error: 'list' object has no attribute 'strip') @@ -31,6 +32,7 @@ Changed: * use new "http-check send" command for HTTP health checks * change default for spreadChecks from 0 to 2 * no longer overwrite live config file when running a syntax check +* make restart/reload commands usable in cron jobs 2.26 diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalSettings.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalSettings.xml index 78d7ce4b2..5869a62e6 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalSettings.xml +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalSettings.xml @@ -21,6 +21,12 @@ checkbox + + haproxy.general.storeOcsp + + checkbox + + haproxy.general.showIntro diff --git a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml index 3cb8e5b2e..89d711a03 100644 --- a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml +++ b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml @@ -16,6 +16,10 @@ 0 Y + + 0 + N + 1 diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php index ea4c086f5..7bfa26819 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php @@ -80,7 +80,13 @@ foreach ($configNodes as $key => $value) { if (!empty((string)$cert->caref)) { $cert = (array)$cert; $ca = ca_chain($cert); + // append the CA to the certificate data $pem_content .= "\n" . $ca; + // additionally export CA to it's own file, + // not required for HAProxy, but makes OCSP handling easier + $output_ca_filename = $export_path . $cert_refid . ".issuer"; + file_put_contents($output_ca_filename, $ca); + chmod($output_ca_filename, 0600); } } // generate pem file for individual certs diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh index ca8cd48dc..8dc393461 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh @@ -1,5 +1,9 @@ #!/bin/sh +if [ -f /etc/rc.conf.d/haproxy ]; then +. /etc/rc.conf.d/haproxy +fi + # NOTE: Keep /var/haproxy on this list, see GH issue opnsense/plugins #39. HAPROXY_DIRS="/var/haproxy /var/haproxy/var/run /tmp/haproxy /tmp/haproxy/ssl /tmp/haproxy/lua /tmp/haproxy/errorfiles /tmp/haproxy/mapfiles" @@ -18,6 +22,11 @@ find /var/haproxy -type d -exec chmod 550 {} \; /usr/local/opnsense/scripts/OPNsense/HAProxy/exportErrorFiles.php > /dev/null 2>&1 /usr/local/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php > /dev/null 2>&1 +# update OCSP data +if [ "${haproxy_ocsp}" == "YES" ]; then + /usr/local/opnsense/scripts/OPNsense/HAProxy/updateOcsp.sh > /dev/null 2>&1 +fi + # deploy new config case "$1" in deploy) diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/updateOcsp.sh b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/updateOcsp.sh new file mode 100755 index 000000000..12c4c8724 --- /dev/null +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/updateOcsp.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# This file is based on: +# https://github.com/acmesh-official/acme.sh/blob/master/deploy/haproxy.sh +# +# Copyright (C) 2021 Neil Pang +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +HAPROXY_DIR="/tmp/haproxy/ssl" + +for _pem in "$HAPROXY_DIR"/*.pem; do + cert_file="$(basename "$_pem")" + _issuer="${HAPROXY_DIR}/${cert_file%.pem}.issuer" + _ocsp="${_pem}.ocsp" + cert_cn="$(openssl x509 -in "$_pem" -noout -text | sed -nE 's/.*Subject:.*CN = ([^,]*)(,.*)?$/\1/p')" + + if [ ! -f "$_issuer" ]; then + continue + fi + + if [ -r "${_issuer}" ]; then + _ocsp_url="$(openssl x509 -noout -ocsp_uri -in "$_pem")" + if [ -n "$_ocsp_url" ]; then + _ocsp_host="$(echo "$_ocsp_url" | cut -d/ -f3)" + subjectdn="$(openssl x509 -in "$_issuer" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)" + issuerdn="$(openssl x509 -in "$_issuer" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)" + if [ "$subjectdn" = "$issuerdn" ]; then + _cafile_argument="-CAfile \"${_issuer}\"" + else + _cafile_argument="" + fi + _openssl_version=$(openssl version | cut -d' ' -f2) + _openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1) + _openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2) + if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then + _header_sep="=" + else + _header_sep=" " + fi + + _openssl_ocsp_cmd="openssl ocsp \ + -issuer \"${_issuer}\" \ + -cert \"${_pem}\" \ + -url \"${_ocsp_url}\" \ + -header Host${_header_sep}\"${_ocsp_host}\" \ + -respout \"${_ocsp}\" \ + -verify_other \"${_issuer}\" \ + ${_cafile_argument} \ + | grep -q \"${_pem}: good\"" + + eval "${_openssl_ocsp_cmd}" + _ret=$? + + if [ "${_ret}" != "0" ]; then + echo "Updating OCSP stapling failed with return code ${_ret}" + fi + fi + fi +done diff --git a/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf b/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf index 07341474e..1e45bc954 100644 --- a/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf +++ b/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf @@ -20,12 +20,14 @@ message:stopping haproxy command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh deploy; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh restart parameters: type:script +description:Restart HAProxy service message:restarting haproxy [reload] command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh deploy; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh reload || /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh restart parameters: type:script +description:Reload HAProxy service message:reloading haproxy [configtest] @@ -119,3 +121,10 @@ parameters: type:script_output message:diff haproxy config +[update_ocsp] +command:/usr/local/opnsense/scripts/OPNsense/HAProxy/updateOcsp.sh +parameters: +type:script_output +description:Update HAProxy OCSP data +message:update haproxy ocsp data + diff --git a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d index 50cee173c..261881284 100644 --- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d +++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d @@ -3,6 +3,11 @@ haproxy_enable=YES haproxy_var_script="/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh" haproxy_pidfile="/var/run/haproxy.pid" haproxy_config="/usr/local/etc/haproxy.conf" +{% if helpers.exists('OPNsense.HAProxy.general.storeOcsp') and OPNsense.HAProxy.general.storeOcsp|default("0") == "1" %} +haproxy_ocsp=YES +{% else %} +haproxy_ocsp=NO +{% endif %} {% if helpers.exists('OPNsense.HAProxy.general.gracefulStop') and OPNsense.HAProxy.general.gracefulStop|default("0") == "1" %} haproxy_hardstop=NO {% else %}