log:
level: info (1)
serve:
decision:
trusted_proxies: (2)
- 0.0.0.0/0
mechanisms:
authenticators: (3)
- id: anon
type: anonymous
- id: reject_requests
type: unauthorized
finalizers: (4)
- id: create_jwt
type: jwt
default_rule: (5)
methods:
- GET
- POST
execute:
- authenticator: reject_requests
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, Podman, or other container runtime of your choice (examples are however using 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 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 finalizer - the jwt` finalizer, 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: "1alpha3"
rules:
- id: rule1 (1)
match:
url: http://<**>/public
execute:
- authenticator: anon
- id: rule2 (2)
match:
url: http://<**>/anonymous
execute:
- authenticator: anon
- finalizer: create_jwt
This file contains two rules:
1 | This rule should match the http://<**>/public url and accept every request without performing any authentication and finalization. For that reason it uses the anon authenticator from our mechanisms definitions. |
2 | This rule should match the http://<**>/anonymous url. It uses the anon authenticator and create_jwt finalizer from our mechanisms definitions. Latter creates a JWT for the created anonymous subject. |
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 container 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 Nov 23, 2023