How to restrict admin access to internal IPs?

Hi,

I’m trying to follow best practices for keycloak administration and I figured that I need to restrict access to admin console and admin endpoints. I want my backend apps to connect to keycloak using it’s private domain while the frontend apps talk with the public endpoints. Unfortunately, I can’t get it to work properly.

Keycloak version: 13.0.1
Proxy: Nginx

Here is a glimpse of my nginx config:

server {
    listen 443 ssl http2;
    server_name public.mykeycloak.org;
    <ssl config here>
    location /auth/realms/ {
        proxy_set_header HOST $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffers 8 8k;
        proxy_buffer_size 8k; 
        proxy_busy_buffers_size 16k;
        proxy_pass https://keycloak/auth/realms/;
    }

    location /auth/js/ {
        proxy_set_header HOST $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffers 8 8k;
        proxy_buffer_size 8k; 
        proxy_busy_buffers_size 16k;
        proxy_pass https://keycloak/auth/js/;
    }

    location /auth/resources/ {
        proxy_set_header HOST $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffers 8 8k;
        proxy_buffer_size 8k; 
        proxy_busy_buffers_size 16k;
        proxy_pass https://keycloak/auth/resources/;
    }
}

server {
    listen 443 ssl http2;
    server_name mykeycloak.internal;
    <ssl config here>
    location /auth/ {
        proxy_set_header HOST $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffers 8 8k;
        proxy_buffer_size 8k; 
        proxy_busy_buffers_size 16k;
        proxy_pass https://keycloak/auth/;
    }
}

upstream keycloak {
    server keycloak-1:8443;
    server keycloak-2:8443;
    server keycloak-3:8443;
}

The admin console itself worked well - I could access it using the private address and I was getting a 404 when I was using the public address. But my apps stopped working and I was seeing PERMISSION_TOKEN_ERROR in the logs which I assume might be related to the issuer of the jwt token.

I’ve looked at the docs and found some options that I thought would help me, so I implemented them as env variables in my keycloak compose file (I’m using the keycloak image provided by bitnami so env vars names are a bit different)

KEYCLOAK_PROXY_ADDRESS_FORWARDING=true
KEYCLOAK_EXTRA_ARGS=-Dkeycloak.frontendUrl=https://public.mykeycloak.org/auth -Dkeycloak.forceBackendUrlToFrontendUrl=true -Dkeycloak.adminUrl=https://mykeycloak.internal/auth

While the apps started to function properly, the admin console is inaccessible using the private address. I get the initial page but when I click on admin console, I am redirected to the public address which obviously returns 404 as /auth/admin/ path is not defined for that server name. It seems that the adminUrl property is not doing anything at all. I’m not sure about the forceBackendUrlToFrontendUrl property - do I need it? The name of the property should be self-explanatory, however I’m a little confused so if someone could shed some light on it, I would really appreciate it.

How can I set it up? The docs regarding this external/internal setup seem a bit murky.