Closed tsaarni closed 3 months ago
Hi @tsaarni - thank you for raising this issue.
IMHO the concept of some request requiring TLS, while others don't, might something that worked in the past where we divided the world into external, untrusted networks and internal, trusted networks. This is IMHO no longer the case in a world where zero trust is promoted.
So I'd say this option didn't age well, and it should rather be removed from Keycloak, than being extended. Using plain HTTP in a development environment might work, still in a production environment all requests should use HTTPS.
I'd be happy to hear your thoughts on this, especially when this concept should still be used.
cc: @stianst
We sometimes use it inside Kubernetes cluster. TLS is terminated at the ingress controller, at the edge of the cluster internal network. The internal "connection leg" can be optionally configured for clear-text HTTP like this:
Thank you for providing the diagram. I assume the ingress controller adds HTTP headers which Keycloak then uses to identify the original IP address used by the external client to connect to the ingress controller, and it will also use those extra HTTP headers to identify that the request originated via HTTPS?
If we would drop the check altogether, is there any use case that would not work any more for you?
Adding back the triage label and a comment to the PR.
Let's see if we can get this out of triage. To elaborate the options seem to be:
@ahus1 wrote:
I assume the ingress controller adds HTTP headers which Keycloak then uses to identify the original IP address used by the external client to connect to the ingress controller, and it will also use those extra HTTP headers to identify that the request originated via HTTPS?
If we would drop the check altogether, is there any use case that would not work any more for you?
I'm not aware of any existing checks for the HTTPS scheme in the X-Forwarded-Proto
header from the proxy. As @shawkins mentioned, if we decide to remove the check entirely (option 3) there might not be any check for TLS unless a new one is implemented.
Defaulting to NONE
(option 2) seems bit counter-intuitive, especially if we are deprecating EXTERNAL
to promote a zero trust architecture. An alternative option could be to deprecate EXTERNAL
and set the new default to ALL
.
Options other than (1) could potentially break backwards compatibility and might require extra work for users.
To explain more about my previous comment about the deprecation:
To explain more about the current logic in Keycloak how the TLS detection works when Keycloak is behind a proxy that terminates (or re-encrypts) the TLS connection:
While I'm ok to proceed with this PR, we should have a separate issue to deprecate this feature including a discussion around this. Once it will then be removed, it would default to a no-op, which would be "NONE".
Due to the amount of issues reported by the community we are not able to prioritise resolving this issue at the moment.
If you are affected by this issue, upvote it by adding a :thumbsup: to the description. We would also welcome a contribution to fix the issue.
@ahus1 converted your last comment to a new issue https://github.com/keycloak/keycloak/issues/31914
Before reporting an issue
Area
core
Describe the bug
When using IPv6 and client is sending request from link-local or unique local address (ULA), client is blocked from sending clear-text HTTP requests when realm configuration is set to require SSL for "External request" (link).
Version
main
Regression
Expected behavior
Requests sent from IPv6 link-local or unique local address should succeed.
Actual behavior
Requests are rejected with response
403 Forbidden
with bodyHow to Reproduce?
One way to reproduce is to use Kubernetes cluster with IPv6 enabled
403 Forbidden
For example for local development, Kind would use link-local addresses for pods and services within the cluster and a "real" CNI like Calico would typically use unique local addresses (ULA).
Anything else?
The code that checks for the request is here https://github.com/keycloak/keycloak/blob/ece72cd491b68422940136bc6171392e07db6679/common/src/main/java/org/keycloak/common/enums/SslRequired.java#L53-L54
Looking at the git history, it seems that initially the code aimed to cover only clients within localhost, and later it took the current form where it was extended to allow IPv4 private addresses (link).
In case of IPv6 the private address ranges are following:
While the JDK method
Inet4Address.isSiteLocalAddress()
covers private address ranges for IPv4 (link), the IPv6 versionInet6Address.isSiteLocalAddress()
only covers site-local unicast address range (link). According to RFC4291 section2.5.7 this address range is now deprecated and should be considered as global address by new implementationWhile the documentation for interface
InetAddress.isSiteLocalAddress()
says (link)it seems likely to me that applications may rather use it for the effect of "all private address ranges", than for the specific (now deprecated) IPv6 site-local definition, especially considering the method is used through the upper class that covers both IPv4 and IPv6. Still, the JDK IPv6 implementation seems to take strict interpretation of covering site-local only and does not offer any method for checking for IPv6 private address ranges.