From 7fa9bacd55f24141ba030cce6140c0423c9a3ed6 Mon Sep 17 00:00:00 2001 From: PiBa-NL Date: Sun, 24 May 2015 17:50:51 +0200 Subject: haproxy-devel, new functionality SSL OCSP stapling for haproxy -fix server dns resolving in case a CNAME is used. --- config/haproxy-devel/pkg/haproxy.inc | 185 ++++++++++++++++++++- config/haproxy-devel/pkg/haproxy_utils.inc | 2 +- .../haproxy-devel/www/haproxy_listeners_edit.php | 8 +- 3 files changed, 186 insertions(+), 9 deletions(-) (limited to 'config') diff --git a/config/haproxy-devel/pkg/haproxy.inc b/config/haproxy-devel/pkg/haproxy.inc index 1e0b28f4..0c8ae4d6 100644 --- a/config/haproxy-devel/pkg/haproxy.inc +++ b/config/haproxy-devel/pkg/haproxy.inc @@ -346,9 +346,11 @@ function haproxy_custom_php_deinstall_command() { $static_output .= "HAProxy, deleting haproxy webgui\n"; update_output_window($static_output); exec("rm /usr/local/etc/rc.d/haproxy.sh"); + exec("rm /etc/rc.haproxy_ocsp.sh"); $static_output .= "HAProxy, installing cron job if needed\n"; update_output_window($static_output); haproxy_install_cron(false); + haproxy_install_cronjob(false, '/etc/rc.haproxy_ocsp.sh'); $static_output .= "HAProxy, running haproxy_custom_php_deinstall_command() DONE\n"; update_output_window($static_output); } @@ -433,6 +435,31 @@ EOD; fclose($fd); exec("chmod a+rx /usr/local/etc/rc.d/haproxy.sh"); + $haproxy_ocsp = << + +EOD; + // removing the \r prevents the "No input file specified." error.. + $haproxy_ocsp = str_replace("\r\n","\n", $haproxy_ocsp); + $fd = fopen("/etc/rc.haproxy_ocsp.sh", "w"); + fwrite($fd, $haproxy_ocsp); + fclose($fd); + exec("chmod a+rx /etc/rc.haproxy_ocsp.sh"); + $static_output .= "HAProxy, update configuration\n"; update_output_window($static_output); @@ -453,6 +480,51 @@ EOD; update_output_window($static_output); } +function haproxy_install_cronjob($should_install, $script, $interval = 60, $parameters = "") { + global $config, $g; + if($g['booting']==true) + return; + $is_installed = false; + if(!$config['cron']['item']) + return; + $x=0; + foreach($config['cron']['item'] as $item) { + if(strstr($item['command'], $script)) { + $is_installed = true; + break; + } + $x++; + } + switch($should_install) { + case true: + if(!$is_installed) { + $cron_item = array(); + $cron_item['minute'] = "*/{$interval}"; + $cron_item['hour'] = "*"; + $cron_item['mday'] = "*"; + $cron_item['month'] = "*"; + $cron_item['wday'] = "*"; + $cron_item['who'] = "root"; + $cron_item['command'] = "$script $parameters"; + $config['cron']['item'][] = $cron_item; + parse_config(true); + write_config("haproxy, install cron job"); + configure_cron(); + } + break; + case false: + if($is_installed == true) { + if($x > 0) { + unset($config['cron']['item'][$x]); + parse_config(true); + write_config("haproxy, remove cron job"); + } + configure_cron(); + } + break; + } +} + function haproxy_install_cron($should_install) { global $config, $g; if($g['booting']==true) @@ -903,6 +975,85 @@ function haproxy_write_certificate_fullchain($filename, $certid, $append = false unset($cert); } +function haproxy_write_certificate_issuer($filename, $certid) { + $cert = haproxy_lookup_cert($certid); + $certchaincontent = ca_chain($cert); + if ($certchaincontent != "") { + $certcontent .= "\r\n" . $certchaincontent; + } + unset($certchaincontent); + file_put_contents($filename, $certcontent, 0); + unset($certcontent); + unset($cert); +} + +function haproxy_uses_ocsp() { + global $config; + $a_frontends = &$config['installedpackages']['haproxy']['ha_backends']['item']; + if (!is_array($a_frontends)) + return false; + + $configpath = "{$g['varetc_path']}/haproxy"; + foreach ($a_frontends as $frontend) { + if ($frontend['sslocsp'] == 'yes') { + return true; + } + } + return false; +} + +function haproxy_getocspurl($filename) { + return exec("openssl x509 -noout -ocsp_uri -in $filename", $output, $err); +} + +function haproxy_updateocsp_one($socketupdate, $filename, $name) { + if (file_exists("{$filename}.ocsp")) { + // If the .ocsp file exists we want to use ocsp + syslog(LOG_NOTICE, "HAProxy Retrieving OCSP for frontend {$name}.. "); + $ocsp_url = haproxy_getocspurl($filename); + $ocsp_host = parse_url($ocsp_url, PHP_URL_HOST); + if (empty($ocsp_url)) { + // If cert does not have a ocsp_uri, it cannot be updated.. + syslog(LOG_ERR, "HAProxy OCSP ERROR Cert does not have a ocsp_uri"); + } else { + $retval = exec("openssl ocsp -issuer {$filename}.issuer -verify_other {$filename}.issuer -cert {$filename} -url {$ocsp_url} -header Host {$ocsp_host} -respout {$filename}.ocsp 2>&1", $output, $err); + if ($socketupdate) { + $ocspresponse = base64_encode(file_get_contents("{$filename}.ocsp")); + $r = haproxy_socket_command("set ssl ocsp-response $ocspresponse"); + if ($r[0] == "OCSP Response updated!\n") + syslog(LOG_NOTICE, "HAProxy OCSP socket update successful for frontend {$name}..result: ".$retval); + else { + syslog(LOG_ERR, "HAProxy OCSP ERROR while performing haproxy socket update OCSP response for: {$name}"); + } + } else { + syslog(LOG_NOTICE, "HAProxy Retrieving OCSP for frontend {$name}..result: ".$retval); + } + } + } +} + +function haproxy_updateocsp($socketupdate = true) { + global $config, $g; + $a_frontends = &$config['installedpackages']['haproxy']['ha_backends']['item']; + if (!is_array($a_frontends)) + return true; + + $configpath = "{$g['varetc_path']}/haproxy"; + foreach ($a_frontends as $frontend) { + $filename = "$configpath/{$frontend['name']}.pem"; + haproxy_updateocsp_one($socketupdate, $filename, $frontend['name']); + + $subfolder = "$configpath/{$frontend['name']}"; + $certs = $frontend['ha_certificates']['item']; + if (is_array($certs)){ + foreach($certs as $cert){ + $filename = "$subfolder/{$cert['ssl_certificate']}.pem"; + haproxy_updateocsp_one($socketupdate, $filename, $frontend['name']); + } + } + } +} + function haproxy_writeconf($configpath) { global $config; global $aliastable; @@ -999,14 +1150,29 @@ function haproxy_writeconf($configpath) { //ssl crt ./server.pem ca-file ./ca.crt verify optional crt-ignore-err all crl-file ./ca_crl.pem $filename = "$configpath/{$frontend['name']}.pem"; $ssl_crt = " crt $filename"; + haproxy_write_certificate_fullchain($filename, $frontend['ssloffloadcert']); + if ($frontend['sslocsp'] == 'yes') { + if (!empty(haproxy_getocspurl($filename))) { + haproxy_write_certificate_issuer($filename . ".issuer", $frontend['ssloffloadcert']); + touch($filename . ".ocsp"); + } + } + $subfolder = "$configpath/{$frontend['name']}"; $certs = $frontend['ha_certificates']['item']; if (is_array($certs)){ if (count($certs) > 0){ @mkdir($subfolder, 0755, true); foreach($certs as $cert){ - haproxy_write_certificate_fullchain("$subfolder/{$cert['ssl_certificate']}.pem", $cert['ssl_certificate']); + $filenamefoldercert = "$subfolder/{$cert['ssl_certificate']}.pem"; + haproxy_write_certificate_fullchain($filenamefoldercert, $cert['ssl_certificate']); + if ($frontend['sslocsp'] == 'yes') { + if (!empty(haproxy_getocspurl($filenamefoldercert))) { + haproxy_write_certificate_issuer($filenamefoldercert . ".issuer", $cert['ssl_certificate']); + touch($filenamefoldercert . ".ocsp"); + } + } } $ssl_crt .= " crt $subfolder"; } @@ -1350,11 +1516,6 @@ function haproxy_writeconf($configpath) { haproxy_do_xmlrpc_sync(); } } - - if (isset($a_global['carpdev'])) - haproxy_install_cron(true); - else - haproxy_install_cron(false); } function haproxy_is_running() { @@ -1566,8 +1727,18 @@ function haproxy_check_run($reload) { $a_global = &$config['installedpackages']['haproxy']; $configpath = "{$g['varetc_path']}/haproxy"; - if ($reload) + if ($reload) { haproxy_writeconf($configpath); + haproxy_updateocsp(false); + + if (isset($a_global['carpdev'])) + haproxy_install_cron(true); + else + haproxy_install_cron(false); + + $useocsp = haproxy_uses_ocsp(); + haproxy_install_cronjob($useocsp, '/etc/rc.haproxy_ocsp.sh', 120); + } if(isset($a_global['enable'])) { if (isset($a_global['carpdev'])) { diff --git a/config/haproxy-devel/pkg/haproxy_utils.inc b/config/haproxy-devel/pkg/haproxy_utils.inc index d8c4faf4..08065abc 100644 --- a/config/haproxy-devel/pkg/haproxy_utils.inc +++ b/config/haproxy-devel/pkg/haproxy_utils.inc @@ -48,7 +48,7 @@ class haproxy_utils { if (haproxy_utils::$pf_version < '2.2') exec("/usr/bin/dig {$host_esc} $type @$dnsserver | /usr/bin/grep {$host_esc} | /usr/bin/grep -v ';' | /usr/bin/awk '{ print $5 }'", $resolved); else - exec("/usr/bin/drill {$host_esc} $type @$dnsserver | /usr/bin/grep {$host_esc} | /usr/bin/grep -v ';' | /usr/bin/awk '{ print $5 }'", $resolved); + exec("/usr/bin/drill {$host_esc} $type @$dnsserver | /usr/bin/awk '{ if($1!=\";;\" && $4==\"{$type}\") print $5 }'", $resolved); foreach($resolved as $item) { $newitem = array(); $newitem["typeid"] = $type; diff --git a/config/haproxy-devel/www/haproxy_listeners_edit.php b/config/haproxy-devel/www/haproxy_listeners_edit.php index d8841c33..5b726d08 100644 --- a/config/haproxy-devel/www/haproxy_listeners_edit.php +++ b/config/haproxy-devel/www/haproxy_listeners_edit.php @@ -71,7 +71,7 @@ uasort($a_pools, haproxy_compareByName); global $simplefields; $simplefields = array('name','desc','status','secondary','primary_frontend','type','forwardfor','httpclose','extaddr','backend_serverpool', 'max_connections','client_timeout','port','advanced_bind', - 'ssloffloadcert','dcertadv','ssloffload','ssloffloadacl','ssloffloadacladditional','sslclientcert-none','sslclientcert-invalid', + 'ssloffloadcert','dcertadv','ssloffload','ssloffloadacl','ssloffloadacladditional','sslclientcert-none','sslclientcert-invalid','sslocsp', 'socket-stats', 'dontlognull','dontlog-normal','log-separate-errors','log-detailed'); @@ -787,6 +787,12 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); onclick="updatevisibility();" />Add ACL for certificate CommonName. (host header matches the 'CN' of the certificate)
+ + OCSP + + onclick="updatevisibility();" />Load certificate ocsp responses for easy certificate validation by the client.
+ + Additional certificates -- cgit v1.2.3 From 4ce40c722b7271f431d24a41651cf1d834706367 Mon Sep 17 00:00:00 2001 From: PiBa-NL Date: Mon, 25 May 2015 14:08:08 +0200 Subject: haproxy-devel, use unlink_if_exists instead of exec(rm ..) --- config/haproxy-devel/pkg/haproxy.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'config') diff --git a/config/haproxy-devel/pkg/haproxy.inc b/config/haproxy-devel/pkg/haproxy.inc index 0c8ae4d6..f59fc59b 100644 --- a/config/haproxy-devel/pkg/haproxy.inc +++ b/config/haproxy-devel/pkg/haproxy.inc @@ -345,8 +345,8 @@ function haproxy_custom_php_deinstall_command() { update_output_window($static_output); $static_output .= "HAProxy, deleting haproxy webgui\n"; update_output_window($static_output); - exec("rm /usr/local/etc/rc.d/haproxy.sh"); - exec("rm /etc/rc.haproxy_ocsp.sh"); + unlink_if_exists("/usr/local/etc/rc.d/haproxy.sh"); + unlink_if_exists("/etc/rc.haproxy_ocsp.sh"); $static_output .= "HAProxy, installing cron job if needed\n"; update_output_window($static_output); haproxy_install_cron(false); -- cgit v1.2.3 From 73979c69ecf2680ab9fa76a56f9a26302593b793 Mon Sep 17 00:00:00 2001 From: PiBa-NL Date: Mon, 25 May 2015 14:57:36 +0200 Subject: haproxy-devel, replace exec(chmod..) by native php --- config/haproxy-devel/pkg/haproxy.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'config') diff --git a/config/haproxy-devel/pkg/haproxy.inc b/config/haproxy-devel/pkg/haproxy.inc index f59fc59b..6e07625f 100644 --- a/config/haproxy-devel/pkg/haproxy.inc +++ b/config/haproxy-devel/pkg/haproxy.inc @@ -433,7 +433,7 @@ EOD; $fd = fopen("/usr/local/etc/rc.d/haproxy.sh", "w"); fwrite($fd, $haproxy); fclose($fd); - exec("chmod a+rx /usr/local/etc/rc.d/haproxy.sh"); + chmod("/usr/local/etc/rc.d/haproxy.sh", 0755); $haproxy_ocsp = << Date: Mon, 25 May 2015 14:58:52 +0200 Subject: haprxy-devel, replace dig/drill by php native dns_get_record --- config/haproxy-devel/pkg/haproxy_utils.inc | 35 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'config') diff --git a/config/haproxy-devel/pkg/haproxy_utils.inc b/config/haproxy-devel/pkg/haproxy_utils.inc index 08065abc..1e5a23fc 100644 --- a/config/haproxy-devel/pkg/haproxy_utils.inc +++ b/config/haproxy-devel/pkg/haproxy_utils.inc @@ -36,26 +36,29 @@ require_once("config.inc"); class haproxy_utils { public static $pf_version; - public function query_dns($host, $querytype="A,AAAA", $dnsserver = "127.0.0.1") { + public function query_dns($host, $querytype="A,AAAA") { $result = array(); - $host = trim($host, " \t\n\r\0\x0B[];\"'"); - $host_esc = escapeshellarg($host); $types = explode(',',$querytype); + $recordtypes = 0; foreach($types as $type){ - $resolved = gethostbyname($host); - if($resolved) { - $resolved = array(); - if (haproxy_utils::$pf_version < '2.2') - exec("/usr/bin/dig {$host_esc} $type @$dnsserver | /usr/bin/grep {$host_esc} | /usr/bin/grep -v ';' | /usr/bin/awk '{ print $5 }'", $resolved); - else - exec("/usr/bin/drill {$host_esc} $type @$dnsserver | /usr/bin/awk '{ if($1!=\";;\" && $4==\"{$type}\") print $5 }'", $resolved); - foreach($resolved as $item) { - $newitem = array(); - $newitem["typeid"] = $type; - $newitem["data"] = $item; - $result[] = $newitem; - } + switch ($type) { + case 'A': $recordtypes += DNS_A; break; + case 'AAAA': $recordtypes += DNS_AAAA; break; + } + } + $dnsresult = dns_get_record($host, $recordtypes); + foreach($dnsresult as $item) { + $type = $item['type']; + $newitem["typeid"] = $type; + switch ($type) { + case 'A': + $newitem["data"] = $item['ip']; + break; + case 'AAAA': + $newitem["data"] = $item['ipv6']; + break; } + $result[] = $newitem; } return $result; } -- cgit v1.2.3 From 5c5fd7560c8fa5c01ae862af72a941746301227e Mon Sep 17 00:00:00 2001 From: PiBa-NL Date: Mon, 25 May 2015 15:55:23 +0200 Subject: haproxy-devel, code formatting & skip dns_get_record when nothing is requested. --- config/haproxy-devel/pkg/haproxy_utils.inc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'config') diff --git a/config/haproxy-devel/pkg/haproxy_utils.inc b/config/haproxy-devel/pkg/haproxy_utils.inc index 1e5a23fc..3d841a25 100644 --- a/config/haproxy-devel/pkg/haproxy_utils.inc +++ b/config/haproxy-devel/pkg/haproxy_utils.inc @@ -42,15 +42,21 @@ class haproxy_utils { $recordtypes = 0; foreach($types as $type){ switch ($type) { - case 'A': $recordtypes += DNS_A; break; - case 'AAAA': $recordtypes += DNS_AAAA; break; + case 'A': + $recordtypes += DNS_A; + break; + case 'AAAA': + $recordtypes += DNS_AAAA; + break; } } + if ($recordtypes == 0) + return $result; + $dnsresult = dns_get_record($host, $recordtypes); foreach($dnsresult as $item) { - $type = $item['type']; - $newitem["typeid"] = $type; - switch ($type) { + $newitem["typeid"] = $item['type']; + switch ($item['type']) { case 'A': $newitem["data"] = $item['ip']; break; -- cgit v1.2.3