mirror of
https://github.com/opnsense/plugins.git
synced 2026-05-28 04:34:15 -04:00
net/haproxy: add support for built-in OCSP update feature
This commit is contained in:
parent
13ab16cd96
commit
ac824e3d02
12 changed files with 124 additions and 112 deletions
|
|
@ -6,12 +6,19 @@ very high loads while needing persistence or Layer7 processing.
|
|||
Plugin Changelog
|
||||
================
|
||||
|
||||
Added:
|
||||
* add support for built-in OCSP update feature
|
||||
|
||||
Fixed:
|
||||
* fix typo in cert sync script
|
||||
|
||||
Changed:
|
||||
* move OCSP settings from "Service" to "Global" section
|
||||
* replace bundled haproxyctl library with haproxy-cli
|
||||
|
||||
Removed:
|
||||
* remove OSCP update cron job
|
||||
|
||||
4.1
|
||||
|
||||
Fixed:
|
||||
|
|
|
|||
|
|
@ -33,12 +33,6 @@
|
|||
<type>checkbox</type>
|
||||
<help><![CDATA[HAProxy will handle service restarts in a way that no connections are dropped. This is the best restart mode, because it has no impact on user experience. That being said, there might be edge cases where seamless reloads lead to unexpected behaviour.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>haproxy.general.storeOcsp</id>
|
||||
<label>Store OCSP responses</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Retrieve OCSP data everytime when starting or restarting HAProxy. For every certificate, the OCSP response will be fetched and stored in filesystem, and automatically picked-up by HAProxy on startup. However, depending on the number of certificates and other circumstances, this may noticeably increase the time required to start/restart the HAProxy service. Note that this only updates the OCSP responses once during start/restart, you need to setup a cron job to periodically update this data too.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>haproxy.general.showIntro</id>
|
||||
<label>Show introduction pages</label>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,28 @@
|
|||
<help><![CDATA[These lines will be added to the global settings of to the HAProxy configuration file.<br/><div class="text-info"><b>NOTE:</b> The syntax will not be checked, use at your own risk!</div>]]></help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<label>SSL settings</label>
|
||||
<type>header</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>haproxy.general.tuning.ocspUpdateEnabled</id>
|
||||
<label>Automatic OCSP updates</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable automatic OCSP response updates. Each OCSP response will be updated at least once an hour, and even more frequently if a given OCSP response has an expire date earlier than this one hour limit.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>haproxy.general.tuning.ocspUpdateMinDelay</id>
|
||||
<label>Minimum OCSP Interval</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Sets the minimum interval (in seconds) between two automatic updates of the same OCSP response.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>haproxy.general.tuning.ocspUpdateMaxDelay</id>
|
||||
<label>Maximum OCSP Interval</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Sets the maximum interval (in seconds) between two automatic updates of the same OCSP response.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>SSL default settings</label>
|
||||
<type>header</type>
|
||||
|
|
|
|||
|
|
@ -10,17 +10,6 @@
|
|||
<type>checkbox</type>
|
||||
<help><![CDATA[Periodically sync SSL certificate changes into the running HAProxy service. This is most useful when using short-lived Let's Encrypt certificates, but changes to other certificates will also be synced. Note that when using the Let's Encrypt plugin, it is also possible to use an <a target="_blank" href="/ui/acmeclient/actions">Automation</a> instead of this cron job.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Update OCSP data for SSL certificates</label>
|
||||
<type>header</type>
|
||||
<style>table_cron table_cron_updateOcsp</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>haproxy.maintenance.cronjobs.updateOcsp</id>
|
||||
<label>Enable</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Periodically fetch OCSP data for all configured SSL certificates. Note that OCSP support needs to be enabled in <a target="_blank" href="/ui/haproxy#general-settings">HAProxy service settings</a>.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Reload HAProxy service</label>
|
||||
<type>header</type>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<model>
|
||||
<mount>//OPNsense/HAProxy</mount>
|
||||
<version>4.0.0</version>
|
||||
<version>4.1.0</version>
|
||||
<description>the HAProxy load balancer</description>
|
||||
<items>
|
||||
<general>
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</seamlessReload>
|
||||
<!-- XXX: old value, required for model migration to 4.1.0 -->
|
||||
<storeOcsp type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>N</Required>
|
||||
|
|
@ -128,6 +129,24 @@
|
|||
<customOptions type="TextField">
|
||||
<Required>N</Required>
|
||||
</customOptions>
|
||||
<ocspUpdateEnabled type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</ocspUpdateEnabled>
|
||||
<ocspUpdateMinDelay type="IntegerField">
|
||||
<default>300</default>
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>86400</MaximumValue>
|
||||
<ValidationMessage>Please specify a value between 1 and 86400.</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
</ocspUpdateMinDelay>
|
||||
<ocspUpdateMaxDelay type="IntegerField">
|
||||
<default>3600</default>
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>86400</MaximumValue>
|
||||
<ValidationMessage>Please specify a value between 1 and 86400.</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
</ocspUpdateMaxDelay>
|
||||
<ssl_defaultsEnabled type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
|
|
@ -3027,6 +3046,7 @@
|
|||
<ValidationMessage>Related cron not found.</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
</syncCertsCron>
|
||||
<!-- XXX: old value, required for model migration to 4.1.0 -->
|
||||
<updateOcsp type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>N</Required>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2023 Frank Wall
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OPNsense\HAProxy\Migrations;
|
||||
|
||||
use OPNsense\Base\BaseModelMigration;
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Cron\Cron;
|
||||
|
||||
class M4_1_0 extends BaseModelMigration
|
||||
{
|
||||
public function run($model)
|
||||
{
|
||||
// Get old OCSP config item and map to new value
|
||||
$old_ocsp = (string)$model->general->storeOcsp;
|
||||
$model->general->tuning->ocspUpdateEnabled = $old_ocsp;
|
||||
|
||||
// Remove obsolete OCSP cron job
|
||||
if ((string)$model->maintenance->cronjobs->updateOcspCron != "") {
|
||||
$cron_uuid = (string)$model->maintenance->cronjobs->updateOcspCron;
|
||||
$model->maintenance->cronjobs->updateOcspCron = "";
|
||||
|
||||
// Delete the cronjob item
|
||||
$mdlCron = new Cron();
|
||||
if ($mdlCron->jobs->job->del($cron_uuid)) {
|
||||
$mdlCron->serializeToConfig();
|
||||
$model->serializeToConfig($validateFullModel = false, $disable_validation = true);
|
||||
Config::getInstance()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +95,12 @@ foreach ($configNodes as $key => $value) {
|
|||
file_put_contents($output_pem_filename, $pem_content);
|
||||
chmod($output_pem_filename, 0600);
|
||||
echo "exported $type to " . $output_pem_filename . "\n";
|
||||
$crtlist[] = $output_pem_filename;
|
||||
// Check if automatic OCSP updates are enabled.
|
||||
if (isset($configObj->OPNsense->HAProxy->general->tuning->ocspUpdateEnabled) and ($configObj->OPNsense->HAProxy->general->tuning->ocspUpdateEnabled == '1')) {
|
||||
$crtlist[] = $output_pem_filename . " ocsp-update on";
|
||||
} else {
|
||||
$crtlist[] = $output_pem_filename;
|
||||
}
|
||||
} else {
|
||||
// In contrast to certificates, CA/CRL content needs to be put in a single file.
|
||||
// A list of individual files is not supported by HAproxy.
|
||||
|
|
|
|||
|
|
@ -22,11 +22,6 @@ 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)
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
#!/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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
HAPROXY_DIR="/tmp/haproxy/ssl"
|
||||
HAPROXY_SOCKET="/var/run/haproxy.socket"
|
||||
|
||||
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}"
|
||||
else
|
||||
_update="$(openssl enc -base64 -A -in "${_ocsp}")"
|
||||
if ! echo "set ssl ocsp-response ${_update}" | socat stdio $HAPROXY_SOCKET; then
|
||||
echo "Updating haproxy OCSP stapling via socket failed"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
|
@ -126,10 +126,3 @@ command:/usr/bin/diff -Naur /usr/local/etc/haproxy.conf /usr/local/etc/haproxy.c
|
|||
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
|
||||
|
|
|
|||
|
|
@ -982,6 +982,15 @@ global
|
|||
{% if helpers.exists('OPNsense.HAProxy.general.tuning.maxConnections') %}
|
||||
maxconn {{OPNsense.HAProxy.general.tuning.maxConnections}}
|
||||
{% endif %}
|
||||
{# # check if OCSP is enabled #}
|
||||
{% if OPNsense.HAProxy.general.tuning.ocspUpdateEnabled|default('') == '1' %}
|
||||
{% if helpers.exists('OPNsense.HAProxy.general.tuning.ocspUpdateMinDelay') %}
|
||||
tune.ssl.ocsp-update.mindelay {{OPNsense.HAProxy.general.tuning.ocspUpdateMinDelay}}
|
||||
{% endif %}
|
||||
{% if helpers.exists('OPNsense.HAProxy.general.tuning.ocspUpdateMaxDelay') %}
|
||||
tune.ssl.ocsp-update.maxdelay {{OPNsense.HAProxy.general.tuning.ocspUpdateMaxDelay}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if helpers.exists('OPNsense.HAProxy.general.tuning.maxDHSize') %}
|
||||
tune.ssl.default-dh-param {{OPNsense.HAProxy.general.tuning.maxDHSize}}
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,6 @@ haproxy_enable=YES
|
|||
haproxy_setup="/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 %}
|
||||
|
|
|
|||
Loading…
Reference in a new issue