docker-composekeycloakreverse-proxygraphdb

GraphDB + Keycloak behind proxy


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;
        }
    }
}

Solution

  • 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).