log:
level: info (1)
serve:
decision:
trusted_proxies: (2)
- 0.0.0.0/0
rules:
mechanisms:
authenticators: (3)
- id: do_nothing
type: noop
- id: anon
type: anonymous
- id: reject_requests
type: unauthorized
unifiers: (4)
- id: do_nothing
type: noop
- id: create_jwt
type: jwt
default: (5)
methods:
- GET
- POST
execute:
- authenticator: reject_requests
- unifier: create_jwt
providers:
file_system: (6)
src: /heimdall/conf/rules.yaml
watch: true
Decision Service Quickstart
This document describes a very simple use case in which you’ll see heimdall’s Decision service in action.
Prerequisites
Download Heimdall in your flavor.
Docker (optionally) and
docker-compose (optionally)
Configure
heimdall can be configured via environment variables, as well as using a configuration file. For simplicity reasons, we’ll use a configuration file here. So create a config file named config.yaml
with the following content:
1 | Here we are setting the log level to info to be able to see any log output. By default, heimdall logs on error log level. |
2 | Configures heimdall’s decision service to trust requests from all sources. This allows usage of X-Forwarded-* headers. This configuration is only required if you want to try out the docker compose example from below. |
3 | Configures a couple of authenticators - the noop authenticator, which does nothing, the anonymous authenticator, which treats every request as anonymous (creates a subject with its id set to anonymous) and the unauthorized authenticator, which rejects every request with 401 Unauthorized HTTP code. |
4 | Configured a couple of unifiers - the noop unifier, which does nothing and the jwt` unifier, which transforms the information about the subject into a JWT. |
5 | Configures the default rule, which will obviously reject every request. |
6 | Configures a file_system provider, which allows heimdall loading rules from the local filesystem; here from the /heimdall/conf/rule.yaml file. |
With that configuration and without any additional rules, heimdall would reject all requests with 401 Unauthorized
. But it has a file_system
provider configured, which makes heimdall expect the referenced rules file already on startup. To make it more usable, create a rules.yaml
file with the following content:
version: "1alpha2"
rules:
- id: rule1 (1)
match:
url: http://<**>/public
execute:
- authenticator: do_nothing
- unifier: do_nothing
- id: rule2 (2)
match:
url: http://<**>/anonymous
execute:
- authenticator: anon
This file contains two rules:
1 | This rule should match the http://<**>/public url and accept every request without performing any authentication and unification. |
2 | This rule should match the http://<**>/anonymous url. It uses the anon authenticator from our mechanisms definitions and since it does not specify a unifier, the unifier from the default rule create_jwt is used. |
Run Standalone
Run heimdall specifying the configuration file from above
If you’re using a binary, put the rules.yaml
file into the /heimdall/conf
directory (as heimdall will look the rules.yaml
file in it according to our configuration from above) just execute
$ ./heimdall serve decision -c config.yaml
The above command will start heimdall in a decision operation mode. By default, the service will be served on port 4456
.
Otherwise, if you’ve built a Docker image, run heimdall in the decision operation mode via
$ docker run -t -v $PWD:/heimdall/conf -p 4456:4456 \
dadrus/heimdall:latest serve decision -c /heimdall/conf/config.yaml
In both cases, you’ll see similar output to
2022-08-04T07:40:12+02:00 INF No opentracing provider configured. Tracing will be disabled.
2022-08-04T07:40:12+02:00 INF Instantiating in memory cache
2022-08-04T07:40:12+02:00 INF Loading pipeline definitions
2022-08-04T07:40:12+02:00 WRN No rule provider configured. Only defaults will be used.
2022-08-04T07:40:12+02:00 WRN Key store is not configured. NEVER DO IT IN PRODUCTION!!!! Generating an
RSA key pair.
2022-08-04T07:40:12+02:00 WRN No key id for signer configured. Taking first entry from the key store
2022-08-04T07:40:12+02:00 INF Starting cache evictor
2022-08-04T07:40:12+02:00 INF Starting rule definition loader
2022-08-04T07:40:12+02:00 INF Management service starts listening on: :4457
2022-08-04T07:40:12+02:00 INF Metrics service starts listening on: :9000
2022-08-04T07:40:12+02:00 INF Decision service starts listening on: :4456
Ignore the warnings. They are expected as we’ve neither configured a rule provider, nor have we configured a key store for JWT signing purposes. Nevertheless, the default rule can be used.
Run Integrated
Alternatively, if you would like to have an environment close to a real scenario, you could make use of docker compose. Create the following docker-compose.yaml
file for this purpose:
version: "3"
services:
proxy:
image: traefik:2.9.1
ports:
- 9090:9090
command: >
--providers.docker=true
--providers.docker.exposedbydefault=false
--entryPoints.http.address=":9090"
--accesslog --api=true --api.insecure=true
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
labels:
- traefik.enable=true
- traefik.http.routers.traefik_http.service=api@internal
- traefik.http.routers.traefik_http.entrypoints=http
- traefik.http.middlewares.heimdall.forwardauth.address=http://heimdall:4456 (1)
- traefik.http.middlewares.heimdall.forwardauth.authResponseHeaders=Authorization
heimdall: (2)
image: dadrus/heimdall:latest
volumes:
- ./config.yaml:/heimdall/conf/config.yaml:ro
- ./rules.yaml:/heimdall/conf/rules.yaml:ro
command: -c /heimdall/conf/config.yaml serve decision
upstream: (3)
image: containous/whoami:latest
labels:
- traefik.enable=true
- traefik.http.services.whoami.loadbalancer.server.port=80
- traefik.http.routers.whoami.rule=PathPrefix("/")
- traefik.http.routers.whoami.middlewares=heimdall
This setup contains three services:
1 | is Traefik, which is used to dispatch the incoming requests and also forward all of them to heimdall first. |
2 | is heimdall, configured to use the configuration and the rule files from above |
3 | is a small service, which just echoes back whatever it receives. |
Use
Send some request to heimdall’s decision service endpoint.
If you’ve started heimdall as described in Run Standalone, that can be achieved by making a call to heimdall’s decision endpoint:
$ curl -v 127.0.0.1:4456/foobar
If you’ve started heimdall as described in Run Integrated, that can be achieved by making a call to the port 9090 exposed by Traefik:
$ curl -v 127.0.0.1:9090/foobar
In both cases, the default rule will apply, and you’ll receive a 401 Unauthorized
response.
Try sending requests to the /public
and the /anonymous
endpoints and see what happens. In both cases, the response will be an HTTP 200 OK
. And the response from the /anonymous
endpoint will also contain an Authorization
header containing a JWT, e.g. as shown below.
* Trying 127.0.0.1:4456...
* Connected to 127.0.0.1 (127.0.0.1) port 4456 (#0)
> GET /anonymous HTTP/1.1
> Host: 127.0.0.1:4456
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 04 Aug 2022 07:45:16 GMT
< Content-Length: 0
< Authorization: Bearer eyJhbGciOiJQUzI1NiIsImtpZCI6IjJkZGIxZDM3MWU1MGFjNDQ5ZGJhNjcyNj
ZmZDRjMzU0OWZjNmRmYTYiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE2NTYxNjY1MTYsImlhdCI6MTY1NjE2NjIxN
iwiaXNzIjoiaGVpbWRhbGwiLCJqdGkiOiIxYjdlODdjYi0zYjdjLTQ1ZDAtYWEyZi00MTRhYmI2YjBlMzciLCJ
uYmYiOjE2NTYxNjYyMTYsInN1YiI6ImFub255bW91cyJ9.MY6fjk7K6ZNn57Mrjy6UGI1cvIMCOOEJoCQF45PH
Q34BfoPxMuTRjdVUZPX4xnT4suyWySsaU1wisgXv4CuMf4WsEUCPKOH8NKv5Zty6eXjTdWQpekDWYsHpVVwz8U
HLmrRASlo_JKErj64wPbRcQWyLMR9X-4cR28ZuH3IbyXh4-XlGNEMAVWYFaZGv1QlEd7jcw3jSVK0b5AtY-NUc
VQlccWpqWD43AE-3spchqboFuiuW5IxFGd4Mc0Dp6uepuQ-XiWEFg9rxnaxl-Grr3LfSY83oML53Akrl4lGtVB
u55QVVjduv_b2ykRnqh7Im9lSivokuVMEuSE8bN2qnqg
<
* Connection #0 to host 127.0.0.1 left intact
You should also be able to see similar output as below from the heimdall’s instance.
...
2022-08-04T07:45:16+02:00 INF TX started _client_ip=127.0.0.1 _http_host=127.0.0.1:4456 _http_method=GET
_http_path=/foobar _http_scheme=http _http_user_agent=curl/7.74.0 _tx_start=1659599116
2022-08-04T07:45:16+02:00 INF TX finished _access_granted=true _body_bytes_sent=0 _client_ip=127.0.0.1
_http_host=127.0.0.1:4456 _http_method=GET _http_path=/foobar _http_scheme=http _http_status_code=200
_http_user_agent=curl/7.74.0 _subject=anonymous _tx_duration_ms=0 _tx_start=1659599116
By the way, this quickstart is also available on GitHub.
Last updated on Jun 28, 2023