Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: Rules are loaded into a radix trie instead of a list #1358

Merged
merged 77 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
8fcb57c
new string utils function to find a common prefix length of two strings
dadrus Apr 12, 2024
7700693
initial implementation based on work from @davidspek
dadrus Apr 12, 2024
23deeaa
find method ensures unnamed wildcards are not included in the result
dadrus Apr 13, 2024
ecd178b
linter warnings resolved
dadrus Apr 13, 2024
55de764
first working version
dadrus Apr 16, 2024
e47a724
ruleset version updated to 1alpha4 respectively to v1alpha4 for kuber…
dadrus Apr 16, 2024
c467a90
ruleset version in helm chart updated
dadrus Apr 16, 2024
7a3787e
validation command test data updated
dadrus Apr 16, 2024
be24aa1
first updates to examples
dadrus Apr 16, 2024
109c95d
first changes to the docs
dadrus Apr 16, 2024
1256454
some linter warnings resolved
dadrus Apr 16, 2024
d6d6c8f
Merge branch 'main' into feat/radix_trie
dadrus Apr 17, 2024
3c6590f
some errors fixed, enhanced internal apis and linter warnings resolved
dadrus Apr 20, 2024
77312a0
some code reformatting
dadrus Apr 20, 2024
655c590
rule repository updated to cover additional new cases, implementation…
dadrus Apr 21, 2024
8ee0a96
more code comments
dadrus Apr 21, 2024
fc537cc
indextree simplifications and refactorings
dadrus Apr 21, 2024
c6f5790
repository impl updated to comply with the updated indextree api
dadrus Apr 21, 2024
672c4db
package indextree renamed to radixtree
dadrus Apr 21, 2024
4dad2ce
radixtree package move to x
dadrus Apr 21, 2024
4f89a3e
further renamings
dadrus Apr 21, 2024
0abc474
only rules from the same rule set can added to the same node
dadrus Apr 21, 2024
effbc98
better error handling and less dependencies in radix tree impl
dadrus Apr 22, 2024
55d7c23
lookup of requests with escaped parts in URL fixed
dadrus Apr 22, 2024
a94d5a2
useless test removed
dadrus Apr 22, 2024
6cd57a3
code simplifications
dadrus Apr 22, 2024
df558eb
proper handling of encoded slashes
dadrus Apr 22, 2024
12ce84d
new mock
dadrus Apr 22, 2024
c9a47d9
more tests and some fixes for found issues
dadrus Apr 22, 2024
18499b6
some code simplifications
dadrus Apr 22, 2024
aeecd3d
new mutex to ensure multiple providers can manage rules in parallel
dadrus Apr 22, 2024
bd29116
making updating rules index atomic, provider have access to the rule …
dadrus Apr 23, 2024
c225199
benchmark tests used for orientation only removed
dadrus Apr 23, 2024
3b3d992
linter earnings resolved
dadrus Apr 23, 2024
99d5e47
package comment moved
dadrus Apr 23, 2024
3b86421
more tests for radix tree
dadrus Apr 23, 2024
371bd44
radix tree update won't work as implemented - removed
dadrus Apr 23, 2024
2fa845e
linter warnings resolved
dadrus Apr 23, 2024
97d9c79
repository impl updated
dadrus Apr 23, 2024
d522eda
path prefix check removed as it doesn't make sense any more
dadrus Apr 23, 2024
c4c9705
the actual config for prefix checks removed
dadrus Apr 23, 2024
03291a9
backtracking test fixed
dadrus Apr 24, 2024
e7f476d
made backtracking configurable in the radix tree implementation
dadrus Apr 24, 2024
b74f31e
rule config updated to implement the new matching config api. More us…
dadrus Apr 24, 2024
a9b79c2
examle rule updated
dadrus Apr 24, 2024
bc3ef95
helm chart updated
dadrus Apr 24, 2024
00eea4f
rules in examples updated to use the new config api
dadrus Apr 24, 2024
f4ef1b4
implementing the config api described in the PR
dadrus Apr 27, 2024
d4a94b9
helm chart updated
dadrus Apr 27, 2024
a162f60
examples updated
dadrus Apr 27, 2024
57df03f
example rule and config updated
dadrus Apr 27, 2024
5a685b9
admission controller settings in helm chart updated to use the proper…
dadrus Apr 28, 2024
ef65689
version string updated in fortgotten places
dadrus Apr 28, 2024
f590945
DockerHub readme updated
dadrus Apr 28, 2024
9d4bbe7
docs updated; to be continued
dadrus Apr 28, 2024
e70c988
more docs updates
dadrus Apr 29, 2024
dc3f1bf
json schema updated - suport for rule_path_match_prefix dropped
dadrus Apr 29, 2024
18ade03
description of rule_path_match_prefix removed from the documentation …
dadrus Apr 29, 2024
da6787e
config reference updated to reflect the changes introduced in this PR
dadrus Apr 29, 2024
212865e
more descriptions about rule matching and backtracking
dadrus Apr 29, 2024
5c248ef
json schema updated - backtracking_enabled added to the default_rule
dadrus Apr 29, 2024
127d4df
radixtree implementation updated to allow switching on or off backtrc…
dadrus Apr 29, 2024
eab6827
CRD updated to allow usage of the new backtracking_enabled property
dadrus Apr 29, 2024
115b96e
default rule impl updated to support the new property
dadrus Apr 29, 2024
07ec621
upstream rule config impl updated to allow usage of the new property
dadrus Apr 29, 2024
b371752
making use of the new backtracking_enabled property in rule implement…
dadrus Apr 29, 2024
da82458
configs used for validation tests updated
dadrus Apr 29, 2024
a8a6cba
example config updated
dadrus Apr 29, 2024
e0e21c9
docker compose quickstarts heimdall config updated
dadrus Apr 29, 2024
767f8ef
made configs better readable by adding empty lines; metallb config up…
dadrus Apr 29, 2024
b0d0d3d
notes in examples readme added
dadrus Apr 29, 2024
7bd03a3
support for and documentation of the respond.with.method_error removed
dadrus Apr 30, 2024
8622ea2
more docu
dadrus Apr 30, 2024
8b33ec7
made backtracking_enabled configurable together with additional condi…
dadrus Apr 30, 2024
2fd38b0
documentation updated
dadrus Apr 30, 2024
92b368b
example rule updated
dadrus Apr 30, 2024
6147096
better config validation converade in tests
dadrus Apr 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 57 additions & 38 deletions charts/heimdall/crds/ruleset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ spec:
singular: ruleset
listKind: RuleSetList
versions:
- name: v1alpha3
- name: v1alpha4
served: true
storage: true
schema:
Expand Down Expand Up @@ -75,20 +75,66 @@ spec:
description: How to match the rule
type: object
required:
- url
- path
- methods
properties:
url:
description: The url to match
scheme:
description: The HTTP scheme, which should be matched. If not set, http and https are matched
type: string
maxLength: 5
host_glob:
description: Glob expression to match the host if required. If not set, all hosts are matched. Mutually exclusive with 'host_regex'.
type: string
maxLength: 512
strategy:
description: Strategy to match the url. Can either be regex or glob.
host_regex:
description: Regular expression to match the host if required. If not set, all hosts are matched. Mutually exclusive with 'host_glob'.
type: string
maxLength: 5
default: glob
enum:
- regex
- glob
maxLength: 512
path:
description: The path to match
type: object
required:
- expression
properties:
expression:
description: The actual path expression to match. Simple and free (named) wildcards can be used
type: string
maxLength: 256
glob:
description: Additional glob expression the matched path should be matched against. Mutual exclusive with 'regex'.
type: string
maxLength: 256
regex:
description: Additional regular expression the matched path should be matched against. Mutual exclusive with 'glob'
type: string
maxLength: 256
methods:
description: The HTTP methods to match
type: array
minItems: 1
items:
type: string
maxLength: 16
enum:
- "CONNECT"
- "!CONNECT"
- "DELETE"
- "!DELETE"
- "GET"
- "!GET"
- "HEAD"
- "!HEAD"
- "OPTIONS"
- "!OPTIONS"
- "PATCH"
- "!PATCH"
- "POST"
- "!POST"
- "PUT"
- "!PUT"
- "TRACE"
- "!TRACE"
- "ALL"
forward_to:
description: Where to forward the request to. Required only if heimdall is used in proxy operation mode.
type: object
Expand Down Expand Up @@ -125,33 +171,6 @@ spec:
items:
type: string
maxLength: 128
methods:
description: The allowed HTTP methods
type: array
minItems: 1
items:
type: string
maxLength: 16
enum:
- "CONNECT"
- "!CONNECT"
- "DELETE"
- "!DELETE"
- "GET"
- "!GET"
- "HEAD"
- "!HEAD"
- "OPTIONS"
- "!OPTIONS"
- "PATCH"
- "!PATCH"
- "POST"
- "!POST"
- "PUT"
- "!PUT"
- "TRACE"
- "!TRACE"
- "ALL"
execute:
description: The pipeline mechanisms to execute
type: array
Expand Down
8 changes: 5 additions & 3 deletions charts/heimdall/templates/demo/test-rule.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# SPDX-License-Identifier: Apache-2.0

{{- if .Values.demo.enabled }}
apiVersion: heimdall.dadrus.github.com/v1alpha3
apiVersion: heimdall.dadrus.github.com/v1alpha4
kind: RuleSet
metadata:
name: {{ include "heimdall.demo.fullname" . }}-test-rule
Expand All @@ -26,7 +26,8 @@ spec:
rules:
- id: public-access
match:
url: http://<**>/pub/<**>
path:
expression: /pub/**
forward_to:
host: {{ include "heimdall.demo.fullname" . }}.heimdall-demo.svc.cluster.local:8080
execute:
Expand All @@ -35,7 +36,8 @@ spec:
- finalizer: noop_finalizer
- id: anonymous-access
match:
url: http://<**>/anon/<**>
path:
expression: /anon/**
forward_to:
host: {{ include "heimdall.demo.fullname" . }}.heimdall-demo.svc.cluster.local:8080
execute:
Expand Down
10 changes: 4 additions & 6 deletions cmd/validate/test_data/invalid-ruleset-for-proxy-usage.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
version: "1alpha3"
version: "1alpha4"
name: test-rule-set
rules:
- id: rule:foo
match:
url: http://foo.bar/<**>
strategy: glob
# methods: # reuses default
# - GET
# - POST
scheme: http
host_glob: foo.bar
path: /**
execute:
- authenticator: unauthorized_authenticator
- authenticator: jwt_authenticator1
Expand Down
10 changes: 4 additions & 6 deletions cmd/validate/test_data/valid-ruleset.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
version: "1alpha3"
version: "1alpha4"
name: test-rule-set
rules:
- id: rule:foo
match:
url: http://foo.bar/<**>
strategy: glob
scheme: http
path: /**
host_glob: foo.bar
forward_to:
host: bar.foo
rewrite:
strip_path_prefix: /foo
add_path_prefix: /baz
strip_query_parameters: [boo]
# methods: # reuses default
# - GET
# - POST
execute:
- authenticator: unauthorized_authenticator
- authenticator: jwt_authenticator1
Expand Down
7 changes: 5 additions & 2 deletions docs/content/_index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ Use declarative techniques you are already familiar with

[source, yaml]
----
apiVersion: heimdall.dadrus.github.com/v1alpha3
apiVersion: heimdall.dadrus.github.com/v1alpha4
kind: RuleSet
metadata:
name: My awesome service
spec:
rules:
- id: my_api_rule
match:
url: http://127.0.0.1:9090/api/<**>
scheme: http
host_glob: 127.0.0.1:9090
path:
expression: /api/**
execute:
- authenticator: keycloak
- authorizer: opa
Expand Down
56 changes: 30 additions & 26 deletions docs/content/docs/rules/regular_rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,39 @@ The unique identifier of a rule. It must be unique across all rules loaded by th
+
Defines how to match a rule and supports the following properties:

** *`url`*: _string_ (mandatory)
** *`scheme`*: _string_ (optional)
+
Glob or Regex pattern of the endpoints of your upstream service, which this rule should apply to. Query parameters are ignored.
Which HTTP scheme is allowed. If not specified, both http and https are accepted.

** *`strategy`*: _string_ (optional)
** *`host_glob`*: _string_ (optional)
+
Which strategy to use for matching of the value, provided in the `url` property. Can be one of:
Glob expression to match the host. Used after the rule is matched with the `path` definition (see below). Mutually exclusive with `host_regex`.
+
Head over to https://github.com/gobwas/glob[gobwas/glob] to get more insights about possible options.

*** `regex` - to match `url` expressions by making use of regular expressions. Internally, heimdall makes use of Heimdall uses https://github.com/dlclark/regexp2[dlclark/regexp2] to implement this strategy. Head over to linked resource to get more insights about possible options.
** *`host_regex`*: _string_ (optional)
+
.Regular expressions patterns
====
* `\https://mydomain.com/` matches `\https://mydomain.com/` and doesn't match `\https://mydomain.com/foo` or `\https://mydomain.com`.
* `<https|http>://mydomain.com/<.*>` matches `\https://mydomain.com/` and `\http://mydomain.com/foo`. Doesn't match `\https://other-domain.com/` or `\https://mydomain.com`.
* `\http://mydomain.com/<[[:digit:]]+>` matches `\http://mydomain.com/123`, but doesn't match `\http://mydomain/abc`.
* `\http://mydomain.com/<(?!protected).*>` matches `\http://mydomain.com/resource`, but doesn't match `\http://mydomain.com/protected`.
====
Regular expression to match the host. Used after the rule is matched with the `path` definition (see below). Mutually exclusive with `host_glob`.

*** `glob` - to match `url` expressions by making use of glob expressions. Internally, heimdall makes use of Heimdall uses https://github.com/gobwas/glob[gobwas/glob] to implement this strategy. Head over to linked resource to get more insights about possible options.
** *`path`*: _PathExpression_ (mandatory)
+
.Glob patterns
====
* `\https://mydomain.com/<m?n>` matches `\https://mydomain.com/man` and does not match `\http://mydomain.com/foo`.
* `\https://mydomain.com/<{foo*,bar*}>` matches `\https://mydomain.com/foo` or `\https://mydomain.com/bar` and doesn't match `\https://mydomain.com/any`.
====
Definitions on how to match the path.

* *`allow_encoded_slashes`*: _string_ (optional)
*** *`expression`*: _string_ (mandatory)
+
Defines how to handle url-encoded slashes in url paths while matching and forwarding the requests. Can be set to the one of the following values, defaulting to `off`:
The actual matching expression. Simple and free (named and unnamed) wildcards can be used

** *`off`* - Reject requests containing encoded slashes. Means, if the request URL contains an url-encoded slash (`%2F`), the rule will not match it.
** *`on`* - Accept requests using encoded slashes, decoding them and making it transparent for the rules and the upstream url. That is, the `%2F` becomes a `/` and will be treated as such in all places.
** *`no_decode`* - Accept requests using encoded slashes, but not touching them and showing them to the rules and the upstream. That is, the `%2F` just remains as is.
*** *`glob`*: _string_ (optional)
+
An additional glob expression, which should be satisfied after the request has been matched by the `expression` value. Mutually exclusive with `regex`.

*** *`regex`*: _string_ (optional)
+
CAUTION: Since the proxy integrating with heimdall, heimdall by itself, and the upstream service, all may treat the url-encoded slashes differently, accepting requests with url-encoded slashes can, depending on your rules, lead to https://cwe.mitre.org/data/definitions/436.html[Interpretation Conflict] vulnerabilities resulting in privilege escalations.
An additional regular expression, which should be satisfied after the request has been matched by the `expression` value. Mutually exclusive with `glob`.

* *`methods`*: _string array_ (optional)
** *`methods`*: _string array_ (optional)
+
Which HTTP methods (`GET`, `POST`, `PATCH`, etc) are allowed for the matched URL. If not specified, every request to that URL will result in `405 Method Not Allowed` response from heimdall. If all methods should be allowed, one can use a special `ALL` placeholder. If all, except some specific methods should be allowed, one can specify `ALL` and remove specific methods by adding the `!` sign to the to be removed method. In that case you have to specify the value in braces. See also examples below.
Which HTTP methods (`GET`, `POST`, `PATCH`, etc) are allowed for the matched URL. If not specified, no rule will feel responsible resulting in `404 Not Found` response from heimdall. If all methods should be allowed, one can use a special `ALL` placeholder. If all, except some specific methods should be allowed, one can specify `ALL` and remove specific methods by adding the `!` sign to the to be removed method. In that case you have to specify the value in braces. See also examples below.
+
.Methods list which effectively expands to all HTTP methods
====
Expand All @@ -87,6 +80,17 @@ methods:
----
====

* *`allow_encoded_slashes`*: _string_ (optional)
+
Defines how to handle url-encoded slashes in url paths while matching and forwarding the requests. Can be set to the one of the following values, defaulting to `off`:

** *`off`* - Reject requests containing encoded slashes. Means, if the request URL contains an url-encoded slash (`%2F`), the rule will not match it.
** *`on`* - Accept requests using encoded slashes, decoding them and making it transparent for the rules and the upstream url. That is, the `%2F` becomes a `/` and will be treated as such in all places.
** *`no_decode`* - Accept requests using encoded slashes, but not touching them and showing them to the rules and the upstream. That is, the `%2F` just remains as is.

+
CAUTION: Since the proxy integrating with heimdall, heimdall by itself, and the upstream service, all may treat the url-encoded slashes differently, accepting requests with url-encoded slashes can, depending on your rules, lead to https://cwe.mitre.org/data/definitions/436.html[Interpretation Conflict] vulnerabilities resulting in privilege escalations.

* *`forward_to`*: _RequestForwarder_ (mandatory in Proxy operation mode)
+
Defines where to forward the proxied request to. Used only when heimdall is operated in the Proxy operation mode and supports the following properties:
Expand Down
21 changes: 14 additions & 7 deletions docs/content/docs/rules/rule_sets.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,23 @@ An imaginary rule set file defining two rules could look like shown below.

[source, yaml]
----
version: "1alpha3"
version: "1alpha4"
name: my-rule-set
rules:
- id: rule:1
match:
url: https://my-service1.local/<**>
methods: [ "GET" ]
scheme: https
host_glob: my-service1.local
path: /**
methods: [ "GET" ]
execute:
- authorizer: foobar
- id: rule:2
match:
url: https://my-service2.local/<**>
methods: [ "GET" ]
scheme: https
host_glob: my-service2.local
path: /**
methods: [ "GET" ]
execute:
- authorizer: barfoo
----
Expand Down Expand Up @@ -108,7 +112,7 @@ $ kubectl apply -f https://raw.githubusercontent.com/dadrus/heimdall/main/charts
====
[source, yaml]
----
apiVersion: heimdall.dadrus.github.com/v1alpha3
apiVersion: heimdall.dadrus.github.com/v1alpha4
kind: RuleSet
metadata:
name: "<some name>"
Expand All @@ -117,7 +121,10 @@ spec:
rules:
- id: "<identifier of a rule 1>"
match:
url: http://127.0.0.1:9090/foo/<**>
scheme: https
host_glob: 127.0.0.1:9090
path:
expression: /foo/**
execute:
- authenticator: foo
- authorizer: bar
Expand Down
Loading
Loading