Skip to content

Commit aec8a1a

Browse files
committed
more closely follow spec for haproxy-ingress-proxy for path and host rules
Signed-off-by: Travis Glenn Hansen <[email protected]>
1 parent 9c61fb6 commit aec8a1a

File tree

3 files changed

+78
-3
lines changed

3 files changed

+78
-3
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# v0.5.7
2+
3+
Released 2021-09-05
4+
5+
- support wildcard hosts in `haproxy-ingress-proxy`
6+
- support empty hosts in `haproxy-ingress-proxy`
7+
- more stringent acls in `haproxy-ingress-proxy` to follow spec more closely
8+
- support `pathType` in `haproxy-ingress-proxy`
9+
110
# v0.5.6
211

312
Released 2021-09-04

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ To achieve this goal, new 'shared' HAProxy frontends are created and attached to
105105
created frontend should also set an existing backend. Note that existing frontend(s)/backend(s) can be created manually
106106
or using the `haproxy-declarative` plugin.
107107

108-
When creating the parent frontend(s) please note that the selected type should be `http / https(offloading` to fully
108+
When creating the parent frontend(s) please note that the selected type should be `http / https(offloading)` to fully
109109
support the feature. If type `ssl / https(TCP mode)` is selected (`SSL Offloading` may be selected or not in the
110110
`External address` table) `sni` is used for routing logic and **CANNOT** support path-based logic which implies a 1:1
111111
mapping between `host` entries and backing `service`s. Type `tcp` will not work and any `Ingress` resources that would

src/KubernetesPfSenseController/Plugin/HAProxyIngressProxy.php

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ public function doAction()
231231
foreach ($item['spec']['rules'] as $ruleKey => $rule) {
232232
$aclName = $frontend['name'].'-rule-'.$ruleKey;
233233
$host = $rule['host'];
234+
//$host = "*.${host}"; // for testing purposes only
235+
//$host = ""; // for testing purposes only
234236
if (!$this->shouldCreateRule($rule)) {
235237
continue;
236238
}
@@ -258,12 +260,76 @@ public function doAction()
258260
// ssl_fc_sni (this can be used only with type http)
259261
switch ($sharedFrontend['type']) {
260262
case "http":
261-
$acl['value'] = "hdr(host) -i ${host} path_beg -i ${path}";
263+
// https://kubernetes.io/docs/concepts/services-networking/ingress/#hostname-wildcards
264+
// https://serverfault.com/questions/388937/how-do-i-match-a-wildcard-host-in-acl-lists-in-haproxy
265+
$hostACL = "";
266+
if (substr($host, 0, 2) == "*.") {
267+
// hdr(host) -m reg -i ^[^\.]+\.example\.org$
268+
// hdr(host) -m reg -i ^[^\.]+\.example\.org(:[0-9]+)?$
269+
$hostACL = "hdr(host) -m reg -i ^[^\.]+".str_replace(".", "\.", substr($host, 1))."(:[0-9]+)?$";
270+
} else {
271+
$hostACL = "hdr(host) -m reg -i ^".str_replace(".", "\.", $host)."(:[0-9]+)?$";
272+
}
273+
274+
// https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types
275+
// https://www.haproxy.com/documentation/hapee/latest/configuration/acls/syntax/
276+
$pathType = $path['pathType'] ?? null;
277+
$pathACL = "";
278+
switch($pathType) {
279+
case "Exact":
280+
/**
281+
* Matches the URL path exactly and with case sensitivity.
282+
*/
283+
$pathACL = "path -m str ${path}";
284+
break;
285+
case "Prefix":
286+
/**
287+
* Matches based on a URL path prefix split by /.
288+
* Matching is case sensitive and done on a path element by element basis.
289+
* A path element refers to the list of labels in the path split by the / separator.
290+
* A request is a match for path p if every p is an element-wise prefix of p of the request path.
291+
*/
292+
$pathACL = "path -m beg ${path}";
293+
break;
294+
case "ImplementationSpecific":
295+
/**
296+
* With this path type, matching is up to the IngressClass.
297+
* Implementations can treat this as a separate pathType or treat it identically to Prefix or Exact path types.
298+
*/
299+
$pathACL = "path -m beg ${path}";
300+
break;
301+
default:
302+
$pathACL = "path -m beg ${path}";
303+
break;
304+
}
305+
306+
if (empty($host)) {
307+
$hostACL = "";
308+
}
309+
$acl['value'] = trim("${hostACL} ${pathACL}");
262310
$frontend['ha_acls']['item'][] = $acl;
263311
break;
264312
case "https":
265313
$this->log("WARN unexpected behavior may occur when using a shared frontend of type https, path-based routing will not work");
266-
$acl['value'] = "req_ssl_sni -i ${host}";
314+
315+
// https://kubernetes.io/docs/concepts/services-networking/ingress/#hostname-wildcards
316+
// https://serverfault.com/questions/388937/how-do-i-match-a-wildcard-host-in-acl-lists-in-haproxy
317+
$hostACL = "";
318+
if (substr($host, 0, 2) == "*.") {
319+
// hdr(host) -m reg -i ^[^\.]+\.example\.org$
320+
// hdr(host) -m reg -i ^[^\.]+\.example\.org(:[0-9]+)?$
321+
// sni should never have the port on the end as the host header may have
322+
$hostACL = "req_ssl_sni -m reg -i ^[^\.]+".str_replace(".", "\.", substr($host, 1));
323+
} else {
324+
$hostACL = "req_ssl_sni -m str -i ${host}"; // exact match case-insensitive
325+
}
326+
327+
if (empty($host)) {
328+
$hostACL = "";
329+
$this->log("WARN cannot create rule for ${frontendName} because host is required for parent frontends of type: ".$sharedFrontend['type']);
330+
continue 3;
331+
}
332+
$acl['value'] = trim("${hostACL}");
267333
$frontend['ha_acls']['item'][] = $acl;
268334
break;
269335
default:

0 commit comments

Comments
 (0)