Skip to content

Commit

Permalink
more closely follow spec for haproxy-ingress-proxy for path and host …
Browse files Browse the repository at this point in the history
…rules

Signed-off-by: Travis Glenn Hansen <[email protected]>
  • Loading branch information
travisghansen committed Sep 6, 2021
1 parent 9c61fb6 commit aec8a1a
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 3 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# v0.5.7

Released 2021-09-05

- support wildcard hosts in `haproxy-ingress-proxy`
- support empty hosts in `haproxy-ingress-proxy`
- more stringent acls in `haproxy-ingress-proxy` to follow spec more closely
- support `pathType` in `haproxy-ingress-proxy`

# v0.5.6

Released 2021-09-04
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ To achieve this goal, new 'shared' HAProxy frontends are created and attached to
created frontend should also set an existing backend. Note that existing frontend(s)/backend(s) can be created manually
or using the `haproxy-declarative` plugin.

When creating the parent frontend(s) please note that the selected type should be `http / https(offloading` to fully
When creating the parent frontend(s) please note that the selected type should be `http / https(offloading)` to fully
support the feature. If type `ssl / https(TCP mode)` is selected (`SSL Offloading` may be selected or not in the
`External address` table) `sni` is used for routing logic and **CANNOT** support path-based logic which implies a 1:1
mapping between `host` entries and backing `service`s. Type `tcp` will not work and any `Ingress` resources that would
Expand Down
70 changes: 68 additions & 2 deletions src/KubernetesPfSenseController/Plugin/HAProxyIngressProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ public function doAction()
foreach ($item['spec']['rules'] as $ruleKey => $rule) {
$aclName = $frontend['name'].'-rule-'.$ruleKey;
$host = $rule['host'];
//$host = "*.${host}"; // for testing purposes only
//$host = ""; // for testing purposes only
if (!$this->shouldCreateRule($rule)) {
continue;
}
Expand Down Expand Up @@ -258,12 +260,76 @@ public function doAction()
// ssl_fc_sni (this can be used only with type http)
switch ($sharedFrontend['type']) {
case "http":
$acl['value'] = "hdr(host) -i ${host} path_beg -i ${path}";
// https://kubernetes.io/docs/concepts/services-networking/ingress/#hostname-wildcards
// https://serverfault.com/questions/388937/how-do-i-match-a-wildcard-host-in-acl-lists-in-haproxy
$hostACL = "";
if (substr($host, 0, 2) == "*.") {
// hdr(host) -m reg -i ^[^\.]+\.example\.org$
// hdr(host) -m reg -i ^[^\.]+\.example\.org(:[0-9]+)?$
$hostACL = "hdr(host) -m reg -i ^[^\.]+".str_replace(".", "\.", substr($host, 1))."(:[0-9]+)?$";
} else {
$hostACL = "hdr(host) -m reg -i ^".str_replace(".", "\.", $host)."(:[0-9]+)?$";
}

// https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types
// https://www.haproxy.com/documentation/hapee/latest/configuration/acls/syntax/
$pathType = $path['pathType'] ?? null;
$pathACL = "";
switch($pathType) {
case "Exact":
/**
* Matches the URL path exactly and with case sensitivity.
*/
$pathACL = "path -m str ${path}";
break;
case "Prefix":
/**
* Matches based on a URL path prefix split by /.
* Matching is case sensitive and done on a path element by element basis.
* A path element refers to the list of labels in the path split by the / separator.
* A request is a match for path p if every p is an element-wise prefix of p of the request path.
*/
$pathACL = "path -m beg ${path}";
break;
case "ImplementationSpecific":
/**
* With this path type, matching is up to the IngressClass.
* Implementations can treat this as a separate pathType or treat it identically to Prefix or Exact path types.
*/
$pathACL = "path -m beg ${path}";
break;
default:
$pathACL = "path -m beg ${path}";
break;
}

if (empty($host)) {
$hostACL = "";
}
$acl['value'] = trim("${hostACL} ${pathACL}");
$frontend['ha_acls']['item'][] = $acl;
break;
case "https":
$this->log("WARN unexpected behavior may occur when using a shared frontend of type https, path-based routing will not work");
$acl['value'] = "req_ssl_sni -i ${host}";

// https://kubernetes.io/docs/concepts/services-networking/ingress/#hostname-wildcards
// https://serverfault.com/questions/388937/how-do-i-match-a-wildcard-host-in-acl-lists-in-haproxy
$hostACL = "";
if (substr($host, 0, 2) == "*.") {
// hdr(host) -m reg -i ^[^\.]+\.example\.org$
// hdr(host) -m reg -i ^[^\.]+\.example\.org(:[0-9]+)?$
// sni should never have the port on the end as the host header may have
$hostACL = "req_ssl_sni -m reg -i ^[^\.]+".str_replace(".", "\.", substr($host, 1));
} else {
$hostACL = "req_ssl_sni -m str -i ${host}"; // exact match case-insensitive
}

if (empty($host)) {
$hostACL = "";
$this->log("WARN cannot create rule for ${frontendName} because host is required for parent frontends of type: ".$sharedFrontend['type']);
continue 3;
}
$acl['value'] = trim("${hostACL}");
$frontend['ha_acls']['item'][] = $acl;
break;
default:
Expand Down

0 comments on commit aec8a1a

Please sign in to comment.