skip to Main Content

I am trying to deploy an application that uses Keycloak as an authentication service and GraphDB as repository. The application is running behind a proxy and I am having trouble setting up the OpenID configuration in GraphDB. I created a minimal example with just Keycloak, GraphDB and nginx proxy (custom-nginx just contains a nginx.conf with reverse proxy declarations for the services):

version: "3.9"
services:
  nginx:
    build:
      context: nginx
    image: custom-nginx
    ports:
      - 80:80
      - 443:443
    depends_on:
      - auth-server
      - db-server
  auth-server-db:
    image: postgres:13
    environment:
      POSTGRES_DB:
      POSTGRES_USER:
      POSTGRES_PASSWORD:
    volumes:
      - auth-server-db:/var/lib/postgresql/data
  auth-server:
    image: quay.io/keycloak/keycloak:22.0
    command:
      - start
    environment:
      KC_HOSTNAME_URL: ${URL}/auth
      KC_HOSTNAME_ADMIN_URL: ${URL}/auth/
      KC_HOSTNAME_STRICT_BACKCHANNEL: false
      KC_PROXY: edge
      KC_HTTP_ENABLED: true
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASS}
      DB_VENDOR: POSTGRES
      DB_ADDR: auth-server-db
      DB_DATABASE: ${POSTGRES_DB}
      DB_USER: ${POSTGRES_USER}
      DB_SCHEMA: public
      DB_PASSWORD: ${POSTGRES_PASSWORD}
    ports:
      - "127.0.0.1:8088:8080"
    volumes:
      - auth-server:/opt/keycloak/data
    depends_on:
      - auth-server-db
  db-server:
    image: ontotext/graphdb:10.3.2
    depends_on:
        - auth-server
    environment:
      GDB_JAVA_OPTS: -Dgraphdb.external-url=${URL}/db-server -Dgraphdb.auth.methods=openid -Dgraphdb.auth.openid.issuer=http://auth-server:8080/realms/termit -Dgraphdb.auth.openid.token_issuer=${URL}/auth/realms/termit -Dgraphdb.auth.openid.client_id=${GDB_CLIENTID} -Dgraphdb.auth.openid.username_claim=preferred_username -Dgraphdb.auth.openid.auth_flow=code -Dgraphdb.auth.openid.token_type=access -Dgraphdb.auth.openid.proxy=true -Ddefault.min.distinct.threshold=67108864 -Dgraphdb.workbench.cors.enable=true -Dgraphdb.workbench.cors.origin=* -Dgraphdb.workbench.cors.expose-headers=*
    restart: always
    ports:
      - "127.0.0.1:7200:7200"
    volumes:
      - db-server:/opt/graphdb/home
volumes:
  auth-server-db:
  auth-server:
  db-server:

When I try this setup with GraphDB, I get the following error:
The Issuer "http://localhost/auth/realms/termit" provided in the configuration did not match the requested issuer "http://auth-server:8080/realms/termit". But if I set the issuer URI to localhost, it cannot connect to it.

My experience with Spring-based applications behind a proxy is that I would set JWT issuer URI to the public URL of the authentication server (e.g., http://localhost/auth/realms/termit) and JWK Set URI to the internal Docker service URL. Is there any similar setting in GraphDB so that I could get both services working behind a proxy (in Docker)?

Any help or examples are much appreciated. Thanks

The nginx.conf contains the following:

worker_processes  1;

events {
    worker_connections 1024;
}

http {
    client_max_body_size 25M;

    include mime.types;
    default_type application/octet-stream;

    server {
        listen 80;
        server_name  localhost;

        add_header Access-Control-Allow-Origin *;

        location /auth/ {
            proxy_pass http://auth-server:8080/;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-Host $server_name;
            proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Cookie $http_cookie;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            # Increase buffer sizes to handle large headers sent by Keycloak and its clients
            proxy_buffer_size   128k;
            proxy_buffers       4 256k;
            proxy_busy_buffers_size 256k;
        }

        location = /db-server {
            return 302 /db-server/;
        }

        location /db-server/ {
            rewrite ^/graphdb/(.*) /$1 break;
            proxy_pass http://db-server:7200;
            proxy_redirect http://db-server:7200/ /db-server/;
            proxy_set_header X-Forwarded-Host $host;
        }
    }
}

2

Answers


  1. Chosen as BEST ANSWER

    Answering my own question: I was able to get the configuration working, although not the way I was hoping to achieve. My working setup (minimal sample can be found with explanation on GitHub) configures GraphDB to access Keycloak via its public URL (e.g., http://172.17.0.1/auth) instead of the Docker service URL (http://auth-server:8080).

    On Keycloak's side it is necessary to configure the client with public access and ensure that the access token contains roles and audience claim.

    For local testing, it is not possible to use http://localhost as public URL because the services interpret the URL as localhost within the service's container instead of the Docker host (my computer). Instead, I used http://172.17.0.1 which is the network interface created by Docker on the host system (IP may vary per system).


  2. The problem if I understand it well, Keycloak will use it’s own url to issue token ‘localhost’, GraphDB using proxy will use proxy url ‘auth-server:8080’.

    For GraphDB, make sure the public facing URL (the issuer) is set to http://localhost/auth/realms/termit.
    For internal calls, GraphDB will need to access Keycloak using an internal Docker network address: http://auth-server:8080. But it should validate tokens based on the public facing URL.

    Also, be sure that KC_HOSTNAME_URL is your public URL : http://localhost/auth.

    Edit after comment :

    Only relationnal database are supported https://www.keycloak.org/server/db

    Maybe you could try to write an intermediate mirco service, use it as a ‘Custom Keycloak Provider’ and make link yourself.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search