-
Notifications
You must be signed in to change notification settings - Fork 349
Add support for having different URLs for user redirection and provider endpoints to Gatekeeper #539
Comments
Gatekeeper points to discovery endpoint, the discovery endpoint then advertises the URLs that Gatekeeper should use. This is not something that should be configured separately in Gatekeeper. It's up to the IdP to advertise URLs to be used. Keycloak supports using different URLs for frontend request, and backend request. Assuming Gatekeeper uses the backend URL for Keycloak to fetch discovery endpoint, only auth endpoint (used for user-agent redirects) will be advertised on the front-end URL, while backend requests will use internal URL. So what is the issue? I'm completely lost in your long description.. |
That's what the second test case covers. In this case a frontend URL (
{
"issuer": "http://localhost:8080/auth/realms/test",
"authorization_endpoint": "http://localhost:8080/auth/realms/test/protocol/openid-connect/auth",
"token_endpoint": "http://keycloak:8080/auth/realms/test/protocol/openid-connect/token",
"token_introspection_endpoint": "http://keycloak:8080/auth/realms/test/protocol/openid-connect/token/introspect",
"userinfo_endpoint": "http://keycloak:8080/auth/realms/test/protocol/openid-connect/userinfo",
"end_session_endpoint": "http://localhost:8080/auth/realms/test/protocol/openid-connect/logout",
"jwks_uri": "http://keycloak:8080/auth/realms/test/protocol/openid-connect/certs",
"check_session_iframe": "http://localhost:8080/auth/realms/test/protocol/openid-connect/login-status-iframe.html",
...
"introspection_endpoint": "http://keycloak:8080/auth/realms/test/protocol/openid-connect/token/introspect"
} You are right: The auth endpoint is derived from the frontend URL. But: Also the issuer URL seems to be derived from the frontend URL. And that seems to make Gatekeeper fail to start: “"issuer" in config (http://localhost:8080/auth/realms/test) does not match provided issuer URL (http://keycloak:8080/auth/realms/test)” (The actual error seems to come from coreos/go-oidc.) I am not saying that the issuer URL as advertized by Keycloak is incorrect. For a public IdP I completely understand that. But in an containerized application that Keycloak and Gatekeeper are components of, making the config discovery request to a backend URL IMHO is a valid use case. I should probably rephrase the issue title and focus the description to the second test case. |
Gatekeeper should read issuer from discovery endpoint, so if it doesn't then that's a bug in Gatekeeper |
issuer doesn't have to be a URL, it just happens to be that in most cases |
@abstractj this looks entirely distinct from #524. @devopsix I'm facing the same problem, did you find a workaround? |
In case someone stumbles on this, this is how I worked around the issue in docker-compose. Let's say that the keycloak container is reachable from outside the stack as version: '3.6'
services:
# ...
keycloak:
image: quay.io/keycloak/keycloak:9.0.2
command: -Djboss.http.port=80
volumes:
# ...
environment:
# ...
labels:
# ...
networks:
default:
aliases:
- keycloak.localtest.me
sysctls:
# necessary to allow keycloak to bind to port <1024 since it doesn't run as root
- net.ipv4.ip_unprivileged_port_start=0 |
@bard no problem, reopened so we can discuss more about your scenario. |
@bard, I am using OAuth2 Proxy now. I had investigated similar work-arounds as yours for Kubernetes but with no success. |
Thanks @abstractj. My scenario is the same as OP's second case above, where gatekeeper and the browser access keycloak through different URLs, respectively the private (LAN) and public (Internet) one. I think that gatekeeper doesn't support that scenario, because if the discovery URL is e.g. The reason I hoped it would work was because I had read the following in keycloak's docs, configured keycloak accordingly (with
That said, they're different projects, so wrong assumption; also the reason why I was after this was for convenience in development only, and the workaround seems to be holding well. |
Hi @JoelSpeed I can be wrong, but I believe this may be one of the use cases you mentioned as core feature in oauth2-proxy. If that's not the case, let's create a new issue. |
@abstractj I don't think it is no. As for the topic of this conversation, Gatekeeper (or OAuth2 Proxy) needs an OIDC issuer URL to perform discovery. The way that OIDC works, this has to be a publicly accessible URL. OIDC mandates that the issuer is public so that the URLs it provides can be accessed by the end user as part of the authentication flow. Unfortunately, without allowing OIDC issuer verification to be skipped, there's not really a workaround for this apart from manually providing the token URLs etc yourself. In OAuth2 Proxy, you have the option to skip issuer verification from our next major release, but this is a rare use case as far as I can tell (One of the Azure AD options requires it?). Normally I would expect GateKeeper or OAuth2 Proxy to hit the public endpoint for doing discovery. If you want to play with that you may be able to using our test environments that were recently merged https://github.com/oauth2-proxy/oauth2-proxy/tree/master/contrib/local-environment (I don't know GateKeeper well enough to give advice about it I'm afraid) |
Rather than skipping the verification entirely, It could be nice to pass an |
Gatekeeper does not start if the Issuer returned from the discovery endpoint is not matching the URL defined as discovery-url in the Gatekeeper config. As noted by OP, in Kubernetes environments you reach the discovery endpoint with a different URL than defined as Issuer (which is the public accessible URL = Frontend URL in Keycloak). Gatekeeper is not compatible with the Frontend URL feature of Keycloak. For me this is clearly a bug. |
After more playing around with this, I found the combination of keycloak's
I think this may be the solution to this issue. |
@cowlingj I have updated my original example to louketo-proxy:1.0.0 and keycloak:10.0.2 and tried using the Given the attached docker-compose.yml in your current working directory.
It seems that the token exchange fails because it is tried directly with the public provider URL without going through the “provider proxy”:
|
@devopsix what have you set |
I use Without that option louketo-proxy would fail to start as originally described:
The the attached docker-compose.yml shows all options:
|
@devopsix docker compose is not kubernetes, it has no access to localhost, so you either have to provide the outside host replacement name (google it), or use internal service name. In case of the first just change http://localhost:8080/auth/realms/test to use docker.for.mac.host.internal in case of mac. |
@Morriz, technically that's correct, no doubt. But please note what @cowlingj suggested above:
As far as I understand, this is only expected to work in combination with using Keycloak as OpenID provider proxy to itself ( Using the internal service name will result in the |
Yes, a proxy like leuketo or oauth2-proxy (it has better cookie domain support) solves that. |
TL;DR With Gatekeeper, it is not possible to have users redirected to public URLs like
https://www.example.com/auth/realms/test/protocol/openid-connect/auth?client_id=test&redirect_uri=...
while using internal URLs likehttp://keycloak:8080/auth/realms/etlms/protocol/openid-connect/token
for provider endpoints.In a containerized environment I would like to use Keycloak Gatekeeper for securing a web service which has no OAuth2/OIDC support. The web service, Gatekeeper and Keycloak containers all are in one “scope” (same namespace in Kubernetes in my target setup; one
docker-compose.yml
file for demonstrating the issue). For reasons beyond my control I cannot point Gatekeeper to the “public Keycloak URL” (sayhttps://www.example.com/auth/...
) but have to use an “internal Keycloak URL” with a container/service name for the hostname part (e.g.http://keycloak:8080/auth/...
).URLs in the OIDC configuration retrieved from the discovery URL contain either the realm frontend URL (if configured) or URLs crafted from the request's Host header (if realm frontend URL not configured). But for my setup I need a mix of both in Gatekeeper and even after browsing the Gatekeeper sources I don't see how that would be possible.
I will try demonstrating the issue.
Given the attached
docker-compose.yml
file:http://localhost:8081
in web browser and verify “Welcome to nginx!” page is shown.http://localhost:8080/auth/admin
in web browser and log in as user “keycloak” with password “keycloak”.docker-compose.yml
file.docker-compose up -d gatekeeper
http://localhost:8082
in web browser.Expected result: Login page loads (
http://localhost:8080/auth/realms/test/protocol/openid-connect/auth?client_id=test&redirect_uri=...
)Actual result: Login page fails to load because user is redirected to
http://keycloak:8080/auth/realms/test/protocol/openid-connect/auth?client_id=test&redirect_uri=...
but hostname “keycloak” does not resolve for the user.http://localhost:8080
.docker-compose stop gatekeeper
docker-compose up gatekeeper
http://localhost:8082
in web browser.Expected result: Login page loads (
http://localhost:8080/auth/realms/test/protocol/openid-connect/auth?client_id=test&redirect_uri=...
)Actual result: Login page fails to load because Gatekeeper does not start due to
{"error": "\"issuer\" in config (http://localhost:8080/realms/test) does not match provided issuer URL (http://keycloak:8080/auth/realms/test)"}
.http://localhost:8080/auth/...
is the equivalent of the (user-resolvable) “public Keycloak URL” andhttp://keycloak:8080/auth/...
is the equivalent of the (cluster private) “internal Keycloak URL” in my target setup.docker-compose.yml and realm-export.json.zip
The text was updated successfully, but these errors were encountered: