Add a tutorial to deploy Keycloak in cluster mode - #3622
Conversation
EtienneM
left a comment
There was a problem hiding this comment.
praise: that's great, I don't have much to say about this :)
| This tutorial covers the deployment of Keycloak on Scalingo. Configuring, | ||
| managing, and administrating Keycloak is out of the scope of this tutorial. |
There was a problem hiding this comment.
suggestion: add a link to the Keycloak documentations for these?
| 5. (optional) Create credentials for the initial administrator user: | ||
| ```bash | ||
| scalingo --app my-keycloak env-set KC_BOOTSTRAP_ADMIN_USERNAME=<admin_username> | ||
| scalingo --app my-keycloak env-set KC_BOOTSTRAP_ADMIN_PASSWORD=<admin_password> | ||
| ``` |
There was a problem hiding this comment.
question: what is the admin password if we don't set this? If it's insecure to not set an admin password, I would mark this step as mandatory
There was a problem hiding this comment.
You're right, I've made them mandatory (well they technically aren't but they are if you follow the doc) in c57358e
If the user don't create them, Keycloak will ask them to create one... but the interface is only available on localhost. So it won't work.
|
|
||
| - Review the official changelog that is published with each release. Breaking | ||
| and notable changes should catch your attention. | ||
| - Ensure your SPIs and themes are compatible with the new version. |
There was a problem hiding this comment.
I've added a link to the little explanation we have in ffd9547
| Moreover, the buildpack makes use of the following environment variables. They | ||
| can be leveraged to customize your deployment: | ||
|
|
||
| - `KEYCLOAK_VERSION`\\ |
There was a problem hiding this comment.
question: that makes me think: do we have a NewReleases configuration to track Keycloak releases?
There was a problem hiding this comment.
I don't think so.
Actually, updating the default version in the buildpack is something I'd like to automate through GitHub Action.
In the meantime, and until it's done, you're right, let's add it :)
Co-authored-by: Étienne M. <EtienneM@users.noreply.github.com>
SPIs are ~explained in the Customizing section.
Legal RiskThe following dependencies were released under a license that RecommendationWhile merging is not directly blocked, it's best to pause and consider what it means to use this license before continuing. If you are unsure, reach out to your security team or Semgrep admin to address this issue. MPL-2.0
|
yanjost
left a comment
There was a problem hiding this comment.
One security flag on the nginx sample — happy to chat about the exact Scalingo router CIDR if useful.
| charset utf-8; | ||
|
|
||
| # Optional hardening: | ||
| proxy_hide_header X-Powered-By; |
There was a problem hiding this comment.
issue (high — security): this nginx sample doesn't set any X-Forwarded-* headers, but step 5 above mandates KC_PROXY_HEADERS=xforwarded, which tells Keycloak to trust the incoming X-Forwarded-For verbatim for client-IP resolution.
nginx's default is to forward whatever X-Forwarded-For the downstream sent — so a remote client can just set X-Forwarded-For: 8.8.8.8 (rotating values too) and Keycloak will attribute the request to that fake IP. This defeats:
- the per-IP brute-force /
loginFailurescounter; - realm-level IP allow/deny policies;
- audit-log forensics on
clientAddress; - any downstream SIEM rule keyed on Keycloak's reported source IP.
Suggested additions in the server { … } block (around the # Optional hardening: lines):
| proxy_hide_header X-Powered-By; | |
| # Optional hardening: | |
| proxy_hide_header X-Powered-By; | |
| # Trust only the Scalingo router for real-IP / XFF rewriting. | |
| # Replace with the documented Scalingo router CIDR(s). | |
| # set_real_ip_from <scalingo-router-CIDR>; | |
| # real_ip_header X-Forwarded-For; | |
| # real_ip_recursive on; | |
| proxy_set_header Host $host; | |
| proxy_set_header X-Real-IP $remote_addr; | |
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
| proxy_set_header X-Forwarded-Proto $scheme; | |
| proxy_set_header X-Forwarded-Host $host; | |
| proxy_set_header X-Forwarded-Port $server_port; |
To verify afterwards: send a request with a forged X-Forwarded-For header, then check clientAddress in the Keycloak admin event log — it should show your real source IP, not the forged one.
There was a problem hiding this comment.
questions:
- Isn't
X-Forwarded-Forset by our frontend reverse proxies? - If this is a security flaw, shouldn't we better put these settings in our default nginx config file (the one provided by our buildpack)?
- Can you provide the Scalingo routers CIDRs?
Thanks!
There was a problem hiding this comment.
Good questions — I traced the full request path, and I need to correct part of my initial comment.
Our front routers do set X-Forwarded-For, but the versioned router configuration preserves any client-provided value and appends the address obtained from the PROXY protocol. The resulting chain can therefore be fake, real-client-IP.
The nginx-buildpack correctly turns the last XFF element into $remote_addr. However, the tutorial’s nginx snippet then forwards the original XFF unchanged. Keycloak 26.5.1, through Quarkus 3.27.1, uses the first XFF element, so it would retain fake.
My original $proxy_add_x_forwarded_for suggestion was therefore incorrect: it would produce fake, real, real. The proxy must overwrite the headers:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;I think the immediate fix belongs in this tutorial because this specific Keycloak + application-proxy composition creates the unsafe trust chain. A broader nginx-buildpack hardening review may still be worthwhile, but it has compatibility implications for custom and multi-proxy configurations.
One more correction to my initial impact assessment: Keycloak’s native brute-force counter is user-based, not IP-based. The demonstrated impact is on audit/forensics and any IP-based policy, extension or SIEM processing.
No description provided.