Keycloak with Wildfly application behind a Nginx reverse proxy - nginx

AWS EC2 Ubuntu 18.04
Keycloak 5.0.0
Nginx 1.15.8
I am trying to place an application (not my development) based on the Wildfly with the Keycloak integration (openid-connect) and am aware of posts that relate to my task, but I believe my question has not been covered in those posts.
In my case everything works fine, an application and a keycloak server behind a Nginx reverse proxy. What I can't understand is that according to this Keycloak document it is necessary to make the following changes in the keycloak standalone.xml (in my case):
<http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="proxy-https"/>
<socket-binding name="proxy-https" port="443"/>
If I understand it correctly, this setup assumes that an application sends an authentication request to http-listener and it is redirected to the proxy-https. It is not quite clear where the proxy is supposed to sent its proxy_pass.
But anyway, in my case, an application sends the authentication request the following way:
<realm>MyRealm</realm>
<resource>MyRealm</resource>
<public-client>true</public-client>
<auth-server-url>https://<host name>:8843/auth/</auth-server-url>
<ssl-required>external</ssl-required>
I have just changed https port in the Keycloak stanalone.xml to 8943 and assigned port 8843 to the Nginx server with the location /auth/, like in this fragment:
server {
listen 192.168.80.40:8843 ssl http2 default_server;
server_name <host name>;
location /auth/ {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port 8843;
add_header Strict-Transport-Security "max-age=15552000";
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass https://192.168.80.40:8943/auth/;
proxy_redirect off;
}
}
It works, but I am not quite sure if it is the right way to place a Keycloak server behind the Nginx reverse proxy, considering the above mentioned Keycloak article. It is basically a question not about something that doesn't work but rather why it works.
If some Keycloak experts can assure me that my setup is workable, I would very appreciate it.
My second question:
Is it possible to restrict an external access only to the application realm, if users decide to open:
https://<host name>:<port>/auth
I would like to block any external access to the master realm login screen.
When I am using /auth/realms/MyRealm/ in the Nginx location, it does prevent users from accessing the master realm login screen, but it shows just some ugly login screen for the application realm, which actually works, but looks unprofessional.
Thanks in advance.
UPDATE:
The only solution for my second question I have found so far:
location /auth/realms/master/ {
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port 8843;
add_header Strict-Transport-Security "max-age=15552000";
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
add_header Pragma "no-cache";
proxy_pass https://192.168.80.40:8943/auth/realms/master/;
proxy_redirect off;
allow X.X.X.X;
deny all;
}
And similar for the root location:
location / {
*
*
*
proxy_pass https://192.168.80.40:8943$request_uri;
proxy_redirect off;
allow X.X.X.X;
deny all;
}
The location /auth/ is not changed.
https://<host name>:<port>/auth still opens "Welcome to Keycloak" screen but access to the "Administration Console" is forbidden. At least, I have now a normal login screen for the application realm and rogue Internet people are going to nowhere from that Welcome screen.
I still need help with my first question.

Related

Reverse Proxy HTTPS Requests as HTTP to Upstream Server

We are using NGINX on our cPanel server to reverse proxy ZKTeco ZKBioSecurity servers. Due to compatibility with some of their devices not supporting HTTPS, all our servers use HTTP, but, of course, all sessions to our NGINX server is secured with HTTPS and a Sectigo certificate provided by cPanel’s AutoSSL.
Here’s the problem: it seems that the ZKBioSecurity servers are detecting that the client is using HTTPS to connect to them through NGINX, and because of this, give the following prompt each time you want to log in, advising you to download and install the ISSOnline driver and certificate. The certificate, however, is issued to the ZKBioSecurity server for 127.0.0.1, so of course this is rather pointless as we are connecting to the NGINX server using a FQDN. This does not happen if we use HTTP:
So my question: is there something in the request (the HTTP header perhaps?) that NGINX forwards to the upstream server that contains the protocol (HTTPS) the client used to connect to the server? Because this somehow seems to be the case.
Here’s our NGINX config for ZKBioSecurity servers:
location /.well-known {
root /home/novacloud/public_html/subdomain/.well-known;
allow all;
try_files $uri = 404;
}
location / {
if ($scheme = http) {
return 301 https://$host$request_uri;
}
proxy_pass http://192.168.0.1:8080;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
The server_name directive is, of course, managed by cPanel. The above is an example of the include files we use in the main cPanel NGINX configuration file. I thought it was the proxy_set_header X-Forwarded-Proto $scheme, but even if I remove this, I still get the Driver Detection Exception prompt.
Here’s a Pastebin of a cURL of the ZKBioSecurity server from our cPanel/NGINX server

NGINX internal redirect from uri path to JSF context root

I'm configuring a cloud server which use NGINX as reverse proxy to serve different applications on different URI (all the applications are on the same wildfly standalone instance).
To be more specific i've a JSF application with a contextroot, let's say, /jsfcontext and i've set up a NGINX location like /mypublicuri.
What happens is that when I navigate to https://myserver.com/mypublicuri/index.xhtml i receive the following error:
/mypublicuri/index.xhtml Not Found in ExternalContext as a Resource.
I'm pretty sure it's related to a missing internal redirect route or some kind of "hack" that i need to specify in order to make everything work but i'm a newbie in NGINX and I don't know how to properly set everything up.
Thanks for the help
Cheers
Read NGINX documentation but my lack of english knowledge makes difficoult to understand what should I have to do
My actual NGINX config
server {
server_name myserver.com www.myserver.com;
access_log /usr/share/logs/access.log;
error_log /usr/share/logs/error.log;
location / {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
location /anotherworkingapp {
add_header Allow "GET, POST, HEAD, PUT, DELETE" always;
proxy_pass http://127.0.0.1:8080$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
location /mypublicuri {
proxy_pass http://127.0.0.1:8080/jsfcontext$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
}

Accessing WSO2-APIM using Nginx

I am accessing my wso2 apim,store and publisher using Nginx.
and want to access using the following:
wso2 api manager to be accessed using nginx url as:
https://nginx-ip/wso2am/carbon
wso2 store to be accessed using nginx url as:
https://nginx-ip/wso2am/store
wso2 store to be accessed using nginx url as:
https://nginx-ip/wso2am/publisher
I tried using nested location block inside location block but wasn't successful.
So, now I am working by having a location block for all of them separately but the same also doesn't works.
Here is my nginx configuration file for store:
location /wso2am/store/
{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://wso2-ip:9443/store/;
proxy_redirect https://$http_host/store/ /wso2am/store/;
proxy_cookie_path / /wso2am/;
limit_rate 25M;
#limit_req zone=wso2am burst=100 nodelay;
}
For the above configuration the GUI for store doesn't appears properly.
Similarly for publisher and carbon(for apim management console).
And the nested nginx configuration is as follows:
location /wso2am/ {
location /wso2am/store/
{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://wso2-ip:9443/store/;
proxy_redirect https://$http_host/oauth2/callback /oauth2/callback;
proxy_redirect https://$http_host/ /wso2am/store/;
proxy_redirect https://$http_host/wso2am/ /wso2am/store/;
proxy_redirect https://$http_host/store/ /wso2am/store/;
proxy_cookie_path / /wso2am/;
limit_rate 25M;
}
}
Where do I have to change in headers or any other location to go correct?
Update 1:
My wso2am store and publisher are working after incorporating the comments and using the following nginx conf:
location /wso2am/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://wso2-apim-ip:9443/;
proxy_redirect https://$http_host/carbon/ /wso2am/carbon/;
proxy_redirect https://$http_host/store/ /wso2am/store/;
proxy_redirect https://$http_host/publisher/ /wso2am/publisher/;
proxy_cookie_path / /wso2am/;
}
Note: But using the above configuration,I login to apim-carbon,I get logged in and then if I click on any of the options on the home page such as list,add.I get logged out and the reason behind it after investigation was the CSRF token is not being sent in the request while accessing it using Nginx.
How can the csrfprevention.js issue be resolved keeping it true.?
Disclamer: this is an incomplete answer, for I am myself digging into this question
I faced the very same issue with both wso2am and wso2ei. I am pretty sure that we need to edit /repository/conf/carbon.xml in this section (I must admit that the comments are not crystal clear):
<!--
Webapp context root of WSO2 Carbon management console.
-->
<WebContextRoot>/wso2am</WebContextRoot>
<!--
Proxy context path is a useful parameter to add a proxy path when a Carbon server is fronted by reverse proxy. In addition
to the proxy host and proxy port this parameter allows you add a path component to external URLs. e.g.
URL of the Carbon server -> https://10.100.1.1:9443/carbon
URL of the reverse proxy -> https://prod.abc.com/appserver/carbon
appserver - proxy context path. This specially required whenever you are generating URLs to displace in
Carbon UI components.
-->
<MgtProxyContextPath>/</MgtProxyContextPath>
<ProxyContextPath>/wso2am</ProxyContextPath>
The following works if your Nginx listen to 443 in SSL mode (couldn't do it with HTTP because of the redirections -> make a self signed certificate if you plan to use it on a local network)
location /wso2am {
proxy_pass https://wso2_apimanager_container:9443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_ssl_verify off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /wso2am/store {
proxy_pass https://wso2_apimanager:9443/store;
}
location /wso2am/publisher {
proxy_pass https://wso2_apimanager:9443/publisher;
}
location /wso2am/admin {
proxy_pass https://wso2_apimanager:9443/admin;
}
}
It works but I am not completely sure why. Can someone explain to me in which aspect <MgtProxyContextPath> differs from </MgtProxyContextPath> and from <WebContextRoot>?
allow proxy for admin publisher and store: to make /publisher, /store and /admin accessible, you need to edit the end of their respective site.json located in /repository/deployment/server/jaggeryapps/name_of_the_service/site/conf/site.json . For /publisher, you would write:
"reverseProxy" : {
"enabled" : "auto", // values true , false , "auto" - will look for X-Forwarded-* headers
"host" : "some.ip.or.domain", // If reverse proxy do not have a domain name use IP
"context":"/wso2am/publisher",
//"regContext":"" // Use only if different path is used for registry
},
Still have issue with the login though
You can follow this guide [1] to configure WSO2 API Manager with Nginx.
[1] -
https://docs.wso2.com/display/AM260/Configuring+the+Proxy+Server+and+the+Load+Balancer

Proxy_pass to url NGINX with a Meteor Server

I have configured a meteor server and setup the nginx configuration. The route works however when configuring dynamic subdomains to point to a specific part of the web app it produces a 404 error on the browser when loading the meteor file.
I am attempting to direct all *.domain.com to http://localhost:3000/booking/
My configuration is:
server {
server_name *.domain.com;
listen 80;
location / {
proxy_pass http://localhost:3000/booking/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; #for websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
The 404 occurs in the Meteor JS file.
If I remove the above nginx subdomain configuration and go to a subdomain it works perfectly, loading the route application. I assume I am missing something to load the application correctly.
The issue only occurs when I proxy_pass to a route within the URL <url>/booking
There are different ways of solving the issue.
1 - In case of 404 try a fallback option without booking in url
server {
server_name *.domain.com;
listen 80;
location / {
proxy_pass http://localhost:3000/booking/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; #for websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
error_page 404 = #fallback;
}
location #fallback {
proxy_pass http://localhost:3000/$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; #for websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
2 - Have a separate block for js and css
server {
server_name *.domain.com;
listen 80;
location / {
proxy_pass http://localhost:3000/booking/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; #for websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
location ~ \.(js|css|font)$ {
proxy_pass http://localhost:3000/$request_uri;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
I have a similar setup, where I have configured different Meteor applications on several subdomains plus a static website on the domain root, all pointing interlly to different ports.
Here is my setup step by step.
Folder structure, location and proxy pass
First thing to think about is the folder strucutre. Depending on your subdomain's VHost-root directory there is a relative path to your subdomain's application folder.
Imagine the following setup:
/www (dir, usually under /var)
/domain (dir)
/websitexy (dir, a static website is deployed under this dir)
/subdomain (dir)
/books (dir, subdomain app is deployed under this dir)
For such a setup I made my nginx config to point to the app's location within the subdomain:
location /books {
I had a similar issue when first time starting my app. One thing I found out is, that my config worked, when setting proxy_pass on my private ip/port combination:
proxy_pass http://172.x.x.x:3000;
This also involves to remove the route name (/books) adter the port number on this entry. Now your proxy pass involves all routing within your subdomain.
Note on routing
Note, that there can be confusion about routing here. By setting the location property you set the routing on the nginx level (server's directory structure), which is why there is no route within your proxy pass.
Your application may have it's own internal routing defined. It is important, that you app's internal router retrieves all requests based from it's application ur root. This is why it is important to have the proxy pass not to include any path after the port number.
Websocket
I have read some articles on nginx and websocket connections. Basically my initial settings came from this article and looked like from this documentation article:
location /app {
proxy_pass 172.x.x.x;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
I also had to add a proxy_read_timeout and proxy_send_timeout because there was an issue with the websocket protocol otherwise:
By default, the connection will be closed if the proxied server does
not transmit any data within 60 seconds. This timeout can be increased
with the proxy_read_timeout directive
So I also set the timeout values:
proxy_read_timeout 36000s;
proxy_send_timeout 36000s;
proxy_set_header Connection "upgrade";
Read more on this here and here.
Summarizing my setup looks like the following (using your app credentials):
location /books {
proxy_pass http://172.x.x.x:3000;
proxy_http_version 1.1;
proxy_read_timeout 36000s;
proxy_send_timeout 36000s;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
So to solve your case, you may check on your vhost directory (the one where your app is deployed, see folder structure above) and change your location and proxy_pass setting accordingly.
If this is not working, you may need to add some more output of your errors, e.g. a excerpt of the log when attempt to connect.

WildFly console served with nginx

I stuck to configure a simple reverse proxy on AWS.
Since we have one host (reverse proxy nginx) serving the public access I decided to follow the rules and created the following configuration.
server {
listen 9990;
server_name project-wildfly.domain.me;
access_log /var/log/nginx/wildfly.access.log;
error_log /var/log/nginx/wildfly.error.log;
proxy_buffers 16 64k;
proxy_buffer_size 128k;
root /var/www/;
index index.html index.htm;
location /console {
proxy_set_header Host $server_addr:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Cache-Control "no-cache, no-store";
proxy_pass http://10.124.1.120:9990/console;
}
location /management {
proxy_set_header Host $server_addr:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Cache-Control "no-cache, no-store";
proxy_pass http://10.124.1.120:9990/management;
}
}
This will serve the admin console and I'm able to log in with the user. Then this message appears:
Access Denied
Insufficient privileges to access this interface.
Nothing within the error log. Thanks for any hint!
I had the same issue when configuring Wildfly 15 and nginx 1.10.3 as reverse proxy.
Setup was very similar to the first post, redirecting /management & /console to wildflyhost:9990.
I was able to access the console directly via :9990 and when comparing the network traffic between direct and nginx-proxied traffic, I noticed that Origin and Host were different.
So in my case the solution was to force the Origin and Host headers in Nginx to something that Wildfly is expecting. I couldn't find this solution elsewhere, so I'm posting it here for future reference anyhow although the thread is old.
location /.../ {
proxy_set_header Host $host:9990;
proxy_set_header Origin http://$host:9990;
proxy_redirect off;
proxy_http_version 1.1;
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_pass_request_headers on;
proxy_pass http://wildflyhost:9990
...
}
Maybe you need turn on management module.
Try this:sh standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 &

Resources