Proxy Service Quickstart

This document describes a simple use case in which you’ll see heimdall’s Proxy service in action. Here, we’ll create a minimal but complete environment for running heimdall with containers.

Prerequisites

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.

  1. Create a config file (config.yaml) with the following content:

    log:
      level: info  (1)
    
    rules:
      mechanisms:
        authenticators:
        - id: anonymous_authenticator  (2)
          type: anonymous
        - id: noop
          type: noop
        authorizers:
        - id: deny_all_requests  (3)
          type: deny
        - id: allow_all_requests  (4)
          type: allow
        unifiers:
        - id: create_jwt  (5)
          type: jwt
        - id: noop
          type: noop
    
      default:  (6)
        methods:
          - GET
          - POST
        execute:
          - authenticator: anonymous_authenticator
          - authorizer: deny_all_requests
          - unifier: create_jwt
    
      providers:
        file_system:  (7)
          src: /heimdall/conf/rule.yaml
          watch: true
    1Here we are setting the log level to info to be able to see any log output. By default, heimdall logs on error log level.
    2Configures the anonymous authenticator.
    3Configures the deny authorizer.
    4Configures the allow authorizer. It will be used in our rule to allow requests.
    5Configures the jwt unifier.
    6Configures the default rule.
    7Configures the file_system provider, which will allow loading of our rule from the file system.

    Put together, this configuration will let heimdall create a JSON Web Token (JWT) with sub claim set to anonymous for every request on every URL for the HTTP methods GET and POST. The JWT itself will be put into the Authorization header as a bearer token. Since the above default rule cannot be used to forward requests to the upstream service, the deny authenticator will reject the requests for us and enforce a configuration of an authorization mechanism in a specific rule, which we’re going to define next.

  2. Create a rule file (rule.yaml) with the following contents:

    version: "1alpha2"
    rules:
    - id: rule1  (1)
      match:
        url: http://<**>/anonymous
      forward_to:
        host: upstream
      execute:
        - authorizer: allow_all_requests
    
    - id: rule2  (2)
      match:
        url: http://<**>/public
      forward_to:
        host: upstream
      execute:
        - authenticator: noop
        - authorizer: allow_all_requests
        - unifier: noop
    1This rule matches any host and the /anonymous path and forwards the request to our upstream service (which we’re going to define next). In addition, it reuses the configuration from the default rule. Here, the methods, which are allowed, as well as the authorizers and unifiers. So we don’t need to define them here.
    2This rule matches any host and the /public path and forwards the request as the previous rule to our upstream service. This rule doesn’t perform any kind of request verification or transformation.
  3. Create or copy the following docker-compose.yaml file and modify it to include the correct paths to your config.yaml and rule.yaml files:

    version: "3"
    
    services:
      heimdall:  (1)
        image: dadrus/heimdall:latest
        volumes:
          # Mount your config file:
          - ./config.yaml:/heimdall/conf/config.yaml:ro
          # Mount your rule file:
          - ./rule.yaml:/heimdall/conf/rule.yaml:ro
        ports:
          - 4455:4455
        command: -c /heimdall/conf/config.yaml serve proxy
    
      upstream:  (2)
        image: containous/whoami:latest
    1Configures heimdall to use our config and rule files and to run in proxy operation mode.
    2Configures the "upstream" service. Here it is a very simple service, which just echoes back everything it receives.

Run

Run docker compose:

$ docker-compose up

Docker will automatically download the required container images. Then, heimdall will start in the proxy mode and run with the configuration details set in the previous steps. You’ll then be able to see an output similar to

Creating network "heimdall_default" with the default driver
Starting heimdall_heimdall_1 ... done
Starting heimdall_upstream_1 ... done
Attaching to heimdall_heimdall_1, heimdall_upstream_1
upstream_1  | Starting up on port 80
heimdall_1  | 2022-08-04T07:50:08+02:00 INF No opentracing provider configured. Tracing will be disabled.
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Instantiating in memory cache
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Loading pipeline definitions
heimdall_1  | 2022-08-04T07:50:08+02:00 WRN Key store is not configured. NEVER DO IT IN PRODUCTION!!!!
                                        Generating an RSA key pair.
heimdall_1  | 2022-08-04T07:50:08+02:00 WRN No key id for signer configured. Taking first entry from the
                                        key store
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Starting cache evictor
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Starting rule definition loader
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Starting rule definitions provider: file_system
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Loading initial rule set
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Rule set changed src=file_system:/heimdall/conf/rule.yaml
                                        type=Create
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Loading rule set src=file_system:/heimdall/conf/rule.yaml
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Metrics service starts listening on: :9000
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Proxy service starts listening on: :4455
heimdall_1  | 2022-08-04T07:50:08+02:00 INF Management service starts listening on: :4457

Ignore the warnings. They are expected and will not have any effects in this case.

Use

Send a request to heimdall’s proxy endpoint:

$ curl -v 127.0.0.1:4455/foobar

Here, heimdall will not match any of the defined rules, which will result in the execution of the default rule. Thus, you’ll see 403 Forbidden as answer.

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:4455...
* Connected to 127.0.0.1 (127.0.0.1) port 4455 (#0)
> GET /foobar HTTP/1.1
> Host: 127.0.0.1:4455
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 04 Aug 2022 07:53:41 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 872
<
Hostname: 4f809f75f31b
IP: 127.0.0.1
IP: 172.22.0.3
RemoteAddr: 172.22.0.2:42100
GET /foobar HTTP/1.1
Host: upstream
User-Agent: curl/7.74.0
Accept: */*
Authorization: Bearer eyJhbGciOiJQUzI1NiIsImtpZCI6IjNhYjFiMDdmMmMyNjlkMWVlMTRjNzQ2NDA4
OTAyZjRlNWQ1MDAyOTgiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE2NTkzMzczMjEsImlhdCI6MTY1OTMzNzAyMSw
iaXNzIjoiaGVpbWRhbGwiLCJqdGkiOiJjMmEzNjczMy04ZDBjLTQzYWQtOGFkNi0xM2Q4NGVhNDI1MTgiLCJuY
mYiOjE2NTkzMzcwMjEsInN1YiI6ImFub255bW91cyJ9.gw-h15LaUUYV-Sjk6Vf-kZflnZxn88lejVIIatKliv
FkeUz8oo9x9juKBSzr4nIVWjGZ_atGVmLoKshudHdnpvABx5cgBaz2_KDgifVzGORE1zld9vGDpU7IPjOyC9-M
b7vOOA1fq9pbQ4nfXw100AJJKFXSct9cYa3163kk_s-jEIPclhB0ZiPqGI-t_GiYJBCVKOTJPkkLKB51KCgn2y
PvO3qLCwO81JdCSFG9k2WLjWZlQe-a8u4El-2qctx8yB-vBFPIaQlwCJh66of3hcUs98IoVlMLGdTJSI4pX9nK
s8OMxVO37eI501gZXXkF5IiSsRAqV_o8pMcGZ47Ztg
Forwarded: for=172.22.0.1;proto=http
X-Forwarded-For: 172.22.0.1

* Connection #0 to host 127.0.0.1 left intact

You should also be able to see similar output as below from the docker-compose environment:

...
2022-08-04T07:53:41+02:00 INF TX started _client_ip=127.0.0.1 _http_host=127.0.0.1:4455 _http_method=GET
 _http_path=/foobar _http_scheme=http _http_user_agent=curl/7.74.0 _tx_start=1659599621
2022-08-04T07:53:41+02:00 INF TX finished _access_granted=true _body_bytes_sent=872 _client_ip=127.0.0.1
 _http_host=127.0.0.1:4455 _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=1659599621

By the way, this quickstart is also available on GitHub.

Last updated on Jun 28, 2023