Skip to content

Commit

Permalink
refactor!: mutator renamed to unifier (#375)
Browse files Browse the repository at this point in the history
  • Loading branch information
dadrus authored Dec 13, 2022
1 parent f20bc37 commit 785b956
Show file tree
Hide file tree
Showing 51 changed files with 618 additions and 633 deletions.
12 changes: 6 additions & 6 deletions DockerHub-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pipeline:
authenticators:
- id: anonymous_authenticator
type: anonymous
mutators:
unifiers:
- id: create_jwt
type: jwt

Expand All @@ -35,7 +35,7 @@ rules:
- POST
execute:
- authenticator: anonymous_authenticator
- mutator: create_jwt
- unifier: create_jwt
```
Start heimdall:
Expand Down Expand Up @@ -103,7 +103,7 @@ pipeline:
type: deny
- id: allow_all_requests
type: allow
mutators:
unifiers:
- id: create_jwt
type: jwt

Expand All @@ -115,7 +115,7 @@ rules:
execute:
- authenticator: anonymous_authenticator
- authorizer: deny_all_requests
- mutator: create_jwt
- unifier: create_jwt

providers:
file_system:
Expand Down Expand Up @@ -206,8 +206,8 @@ X-Forwarded-For: 172.22.0.1
What did you actually do? ;)
* You've created a very simple configuration with a default rule, with preconfigured defaults. The used authenticator instructs heimdall to create an anonymous subject for every request on every URL for the HTTP methods GET and POST. The default authenticator rejects any request and the default mutator creates a JWT from the subject mentioned above.
* You've created a very simple rule, which reuses the default authenticator and mutator and configures an authorizer, which allows any request to pass through.
* You've created a very simple configuration with a default rule, with preconfigured defaults. The used authenticator instructs heimdall to create an anonymous subject for every request on every URL for the HTTP methods GET and POST. The default authenticator rejects any request and the default unifier creates a JWT from the subject mentioned above.
* You've created a very simple rule, which reuses the default authenticator and unifier and configures an authorizer, which allows any request to pass through.
* You've created and started a docker compose environment with heimdall operated in proxy mode and a "upstream" service, which responds with everything it receives.
* And sent an HTTP GET request to an imaginary `foobar` endpoint.
* Heimdall run the request through its pipeline and forwarded the enriched (`Authorization` header) request to the "upstream" service, which just returned all it has received to the caller.
Expand Down
6 changes: 3 additions & 3 deletions charts/heimdall/templates/demo/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ data:
type: deny
- id: allow_all_requests
type: allow
mutators:
unifiers:
- id: create_jwt
type: jwt
- id: noop_mutator
- id: noop_unifier
type: noop
default:
Expand All @@ -36,7 +36,7 @@ data:
execute:
- authenticator: anonymous_authenticator
- authorizer: deny_all_requests
- mutator: create_jwt
- unifier: create_jwt
providers:
kubernetes: {}
Expand Down
2 changes: 1 addition & 1 deletion charts/heimdall/templates/demo/test-rule.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ spec:
execute:
- authenticator: noop_authenticator
- authorizer: allow_all_requests
- mutator: noop_mutator
- unifier: noop_unifier
- id: anonymous-access
url: http://<**>/anonymous
upstream: http://{{ include "heimdall.demo.fullname" . }}.heimdall-demo.svc.cluster.local:8080
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ menu:
parent: "Configuration"
---

Some link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/mutators.adoc" >}}[Mutators], which finalize the successful execution of the pipeline, can generated signed objects, like a JWT, to be forwarded to the upstream services. In such cases Heimdall acts as an issuer of such objects and needs at least corresponding key material.
Some link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers], which finalize the successful execution of the pipeline, can generated signed objects, like a JWT, to be forwarded to the upstream services. In such cases Heimdall acts as an issuer of such objects and needs at least corresponding key material.

== Configuration

Expand Down
4 changes: 2 additions & 2 deletions docs/content/docs/configuration/reference/reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ rules:
headers:
foo: bar
mutators:
unifiers:
- id: jwt
type: jwt
config:
Expand Down Expand Up @@ -286,7 +286,7 @@ rules:
- POST
execute:
- authenticator: anonymous_authenticator
- mutator: jwt
- unifier: jwt
on_error:
- error_handler: authenticate_with_kratos
Expand Down
16 changes: 8 additions & 8 deletions docs/content/docs/configuration/rules/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ execute:
- authenticator: foo
- authorizer: bar
- contextualizer: foo
- mutator: zab
- unifier: zab
on_error:
- error_handler: foobar
----
Expand Down Expand Up @@ -89,13 +89,13 @@ Heimdall uses https://github.com/dlclark/regexp2[dlclark/regexp2] and https://gi

=== Regular Pipeline

As described in the link:{{< relref "/docs/getting_started/concepts.adoc" >}}[Concepts] section, heimdall's decision pipeline consists of multiple mechanisms - at least consisting of link:{{< relref "pipeline_mechanisms/authenticators.adoc" >}}[authenticators] and link:{{< relref "pipeline_mechanisms/mutators.adoc" >}}[mutators]. The definition of such a pipeline happens as a list of required mechanisms (previously link:{{< relref "pipeline_mechanisms/overview.adoc" >}}[configured]) with the corresponding ids in the following order:
As described in the link:{{< relref "/docs/getting_started/concepts.adoc" >}}[Concepts] section, heimdall's decision pipeline consists of multiple mechanisms - at least consisting of link:{{< relref "pipeline_mechanisms/authenticators.adoc" >}}[authenticators] and link:{{< relref "pipeline_mechanisms/unifiers.adoc" >}}[unifiers]. The definition of such a pipeline happens as a list of required mechanisms (previously link:{{< relref "pipeline_mechanisms/overview.adoc" >}}[configured]) with the corresponding ids in the following order:

* List of link:{{< relref "pipeline_mechanisms/authenticators.adoc" >}}[authenticators] using `authenticator` as key, followed by the required authenticator `id`. Authenticators following the first defined in the list are used by heimdall as fallback. That is, if first authenticator fails due to missing authentication data, second is executed, etc. By default, fallback is not used if an authenticator fails due to validation errors of the given authentication data. E.g. if an authenticator fails to validate the signature of a JWT token, the next authenticator in the list will not be executed. Instead, the entire pipeline will fail and lead to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is mandatory if no link:{{< relref "default.adoc" >}}[default rule] is configured.
+
NOTE: Some authenticators use the same sources to get subject authentication object from. E.g. the `jwt` and the `oauth2_introspection` authenticators can retrieve tokens from the same places in the request. If such authenticators are used in the same pipeline, you should configure the more specific ones before the more general ones to have working default fallbacks. To stay with the above example, the `jwt` authenticator is more specific compared to `oauth2_introspection`, as it will be only executed, if the token is in a JWT format. In contrast to this, the `oauth2_introspection` authenticator is more general and does not care about the token format, thus will feel responsible for the request as soon as it finds a bearer token. You can however also make use of the `allow_fallback_on_error` configuration property and set it to `true`. This will allow a fallback even if the verification of the credentials fail.
* List of link:({{< relref "pipeline_mechanisms/contextualizers.adoc" >}}[contextualizers] and link:({{< relref "pipeline_mechanisms/authorizers.adoc" >}}[authorizers] in any order (optional). Can also be mixed. As with authenticators, the list definition happens using either `contextualizer` or `authorizer` as key, followed by the required `id`. All mechanisms in this list are executed in the order, they are defined. If any of these fails, the entire pipeline fails, which leads to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is optional.
* List of link:{{< relref "pipeline_mechanisms/mutators.adoc" >}}[mutators] using `mutator` as key, followed by the required mutator `id`. All mutators in this list are executed in the order, they are defined. If any of these fails, the entire pipeline fails, which leads to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is mandatory if no link:{{< relref "default.adoc" >}}[default rule] is configured.
* List of link:{{< relref "pipeline_mechanisms/unifiers.adoc" >}}[unifiers] using `unifiers` as key, followed by the required unifier `id`. All unifiers in this list are executed in the order, they are defined. If any of these fails, the entire pipeline fails, which leads to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is mandatory if no link:{{< relref "default.adoc" >}}[default rule] is configured.

In all cases, the used mechanism can be partially reconfigured if supported by the corresponding type. These reconfigurations are always local to the given rule. With other words, you can adjust your rule specific pipeline as you want without any side effects.

Expand Down Expand Up @@ -124,20 +124,20 @@ In all cases, the used mechanism can be partially reconfigured if supported by t
// some expression logic deviating from the
// definition in the pipeline configuration.
# ... any further required authorizer or contextualizer
# list of mutators
- mutator: foo
- mutator: bar
# list of unifiers
- unifier: foo
- unifier: bar
config:
headers:
- X-User-ID: {{ quote .ID }}
# ... any further required mutators
# ... any further required unifiers
----
This example uses
* two authenticators, with authenticator named `bar` being the fallback for the authenticator named `foo`. This fallback authenticator is obviously of type link:{{< relref "pipeline_mechanisms/authenticators.adoc#_anonymous" >}}[anonymous] as it reconfigures the referenced prototype to use `anon` for subject id.
* multiple contextualizers and authorizers, with first contextualizer having its cache disabled (`cache_ttl` set to 0s) and the last authorizer being of type link:{{< relref "pipeline_mechanisms/authorizers.adoc#_local_cel" >}}[cel] as it reconfigures the referenced prototype to use a different authorization script.
* two mutators, with the second one being obviously of type link:{{< relref "pipeline_mechanisms/mutators.adoc#_header" >}}[header], as it defines a `X-User-ID` header set to the value of the subject id to be forwarded to the upstream service.
* two unifiers, with the second one being obviously of type link:{{< relref "pipeline_mechanisms/unifiers.adoc#_header" >}}[header], as it defines a `X-User-ID` header set to the value of the subject id to be forwarded to the upstream service.
====

=== Error Handler Pipeline
Expand Down
8 changes: 4 additions & 4 deletions docs/content/docs/configuration/rules/default.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Which HTTP methods (`GET`, `POST`, `PATCH`, etc) are allowed. Defaults to an emp

* *`execute`*: _link:{{< relref "configuration.adoc#_regular_pipeline" >}}[Regular Pipeline]_ (mandatory)
+
Which mechanisms to use for authentication, authorization, hydration (enrich) and mutation of the request and the subject. At least one link:{{< relref "./pipeline_mechanisms/authenticators.adoc" >}}[authenticator] and one link:{{< relref "./pipeline_mechanisms/mutators.adoc" >}}[mutator] must be defined. A specific rule (see also link:{{< relref "configuration.adoc" >}}[Rule]) can omit the definition of authenticators, if it wants to reuse the authenticators defined in the default rule. Same is true for other mechanisms. Exception are link:{{< relref "./pipeline_mechanisms/authorizers.adoc" >}}[authorizers] and link:{{< relref "./pipeline_mechanisms/contextualizers.adoc" >}}[contextualizers]. As soon, as a specific rule defines at least one authorizer or contextualizer, those authorizers and contextualizers (defined in the default rule) are not considered anymore.
Which mechanisms to use for authentication, authorization, hydration (enrich) and mutation of the request and the subject. At least one link:{{< relref "./pipeline_mechanisms/authenticators.adoc" >}}[authenticator] and one link:{{< relref "./pipeline_mechanisms/unifiers.adoc" >}}[unifier] must be defined. A specific rule (see also link:{{< relref "configuration.adoc" >}}[Rule]) can omit the definition of authenticators, if it wants to reuse the authenticators defined in the default rule. Same is true for other mechanisms. Exception are link:{{< relref "./pipeline_mechanisms/authorizers.adoc" >}}[authorizers] and link:{{< relref "./pipeline_mechanisms/contextualizers.adoc" >}}[contextualizers]. As soon, as a specific rule defines at least one authorizer or contextualizer, those authorizers and contextualizers (defined in the default rule) are not considered anymore.

* *`on_error`*: _link:{{< relref "configuration.adoc#_error_handler_pipeline" >}}[Error Handler Pipeline]_ (mandatory)
+
Expand All @@ -40,12 +40,12 @@ rules:
- authenticator: session_cookie_from_kratos_authn
- authenticator: oauth2_introspect_token_from_keycloak_authn
- authorizer: deny_all_requests_authz
- mutator: jwt_mut
- unifier: jwt_unifier
on_error:
- error_handler: authenticate_with_kratos_eh
----
This example defines a default rule, which allows HTTP `GET` and `PATCH` requests on any URL (will respond with `405 Method Not Allowed` for any other HTTP method used by a client). The regular pipeline consists of two authenticators, with `session_cookie_from_kratos_authn` being the first and `oauth2_introspect_token_from_keycloak_authn` being the fallback (if the first one fails), a `deny_all_requests_authz` authorizer and the `jwt_mut` mutator. The error pipeline is configured to execute only the `authenticate_with_kratos_eh` error handler.
This example defines a default rule, which allows HTTP `GET` and `PATCH` requests on any URL (will respond with `405 Method Not Allowed` for any other HTTP method used by a client). The regular pipeline consists of two authenticators, with `session_cookie_from_kratos_authn` being the first and `oauth2_introspect_token_from_keycloak_authn` being the fallback (if the first one fails), a `deny_all_requests_authz` authorizer and the `jwt_unifier` unifier. The error pipeline is configured to execute only the `authenticate_with_kratos_eh` error handler.
Obviously, the regular pipeline (defined in the `execute` property) of this default rule will always result in an error due to `deny_all_requests_authz`. This way it is thought to provide secure defaults and let the upstream specific rules override at least the part dealing with authorization. Such an upstream specific rule could then look like follows:
Expand All @@ -57,6 +57,6 @@ execute:
- authorizer: allow_all_requests_authz
----
Take a look at how `methods`, `on_error`, as well as the authenticators and mutators from the `execute` definition of the default rule are reused. Easy, no?
Take a look at how `methods`, `on_error`, as well as the authenticators and unifiers from the `execute` definition of the default rule are reused. Easy, no?
====

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ menu:
parent: "Pipeline Mechanisms"
---

Error Handlers are responsible for execution of logic if any of the link:{{< relref "authenticators.adoc" >}}[authenticators], link:{{< relref "authorizers.adoc" >}}[authorizers], link:{{< relref "contextualizers.adoc" >}}[contextualizers] or link:{{< relref "mutators.adoc" >}}[mutators] fails. The error handler mechanisms range from a simple error response to the client which sent the request to sophisticated ones, supporting complex logic and redirects.
Error Handlers are responsible for execution of logic if any of the link:{{< relref "authenticators.adoc" >}}[authenticators], link:{{< relref "authorizers.adoc" >}}[authorizers], link:{{< relref "contextualizers.adoc" >}}[contextualizers] or link:{{< relref "unifiers.adoc" >}}[unifiers] fails. The error handler mechanisms range from a simple error response to the client which sent the request to sophisticated ones, supporting complex logic and redirects.

== Error Handler Types

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ All mechanisms supported by heimdall fall into following categories:
* link:{{< relref "authenticators.adoc">}}[Authenticators], which inspect HTTP requests for presence of authentication objects, like e.g. the presence of a specific cookie. If such objects exist, authenticators verify the related authentication status and obtain information about the corresponding subject. A subject, could be a user who tries to use particular functionality of the upstream service, a machine (if you have machine-2-machine interaction), or something different. Authenticators ensure the subject is authenticated and the information available about it is valid.
* link:{{< relref "authorizers.adoc">}}[Authorizers], which ensure that the subject obtained via an authenticator has the required permissions to submit the given HTTP request and thus to execute the corresponding logic in the upstream service. E.g. a specific endpoint of the upstream service might only be accessible to a "user" from the "admin" group, or to an HTTP request if a specific HTTP header is set.
* link:{{< relref "contextualizers.adoc">}}[Contextualizers], which enrich the information about the subject obtained via an authenticator with further contextual information, required either by the upstream service itself or an authorizer. This can be handy if the actual authentication system doesn't have all information about the subject (which is usually the case in microservice architectures), or if dynamic information about the subject, like the current location based on the IP address, is required.
* link:{{< relref "mutators.adoc">}}[Mutators], which finalize the successful execution of the pipeline and transform the available information about the subject into a format expected, respectively required by the upstream service. This ranges from adding a query parameter, to a structured JWT in a specific header.
* link:{{< relref "unifiers.adoc">}}[Unifiers], which finalize the successful execution of the pipeline and unify the available information about the subject by transforming it into a format expected, respectively required by the upstream service. This ranges from adding a query parameter, to a structured JWT in a specific header.
* link:{{< relref "error_handlers.adoc">}}[Error Handlers], which are responsible for execution of logic if any of the mechanisms described above fail. These range from a simple error response to the client, which sent the request, to sophisticated ones, supporting complex logic and redirects.

== General Configuration
Expand All @@ -31,8 +31,8 @@ rules:
<list of authorizers>
contextualizers:
<list of contextualizers>
mutators:
<list of mutators>
unifiers:
<list of unifiers>
error_handlers:
<list of error handlers>
----
Expand Down Expand Up @@ -108,8 +108,8 @@ rules:
forward_headers:
- Authorization
cache_ttl: 1m
mutators:
- id: jwt_mut
unifiers:
- id: jwt_unifier
type: jwt
config:
ttl: 5m
Expand Down
Loading

0 comments on commit 785b956

Please sign in to comment.