Is there a way to configure SSO oauth2 Prometheus via Nginx Ingress and Oauth2-proxy - single-sign-on

I want all users who access Prometheus GUI to be able to log in via SSO keycloak which supports the oauth2 protocol, but now the current configuration, before reaching prometheus gui, there is an nginx server and on the upstreams I have several websites like: grafana , prometheus etc. I searched on the google what is the best solution to do that and I found the Oauth2-proxy that can be done this but after the authentication, the oauth2-proxy is redirect me to the auth page and not to prometheus, everything works ok but not the redirect url.
nginx.conf
user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
listen 443 ssl default_server;
server_name example.com;
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect "https://example.com/prometheus";
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location ^~ /prometheus/ {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
auth_request_set $token $upstream_http_x_auth_request_access_token;
proxy_set_header X-Access-Token $token;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
auth_request_set $auth_cookie_name_upstream_1 $upstream_cookie_auth_cookie_name_1;
if ($auth_cookie ~* "(; .*)") {
set $auth_cookie_name_0 $auth_cookie;
set $auth_cookie_name_1 "auth_cookie_name_1=$auth_cookie_name_upstream_1$1";
}
if ($auth_cookie_name_upstream_1) {
add_header Set-Cookie $auth_cookie_name_0;
add_header Set-Cookie $auth_cookie_name_1;
}
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass "http://192.168.1.20:9090/prometheus/"; # This is where my web server is hosted
}
oauth2-proxy.cfg
provider="keycloak"
provider_display_name="SSO connect"
ssl_insecure_skip_verify=true
login_url="https://auth.keycloak/oauth2/authorize"
redeem_url="https://auth.keycloak/oauth2/token"
validate_url="https://auth.keycloak/oauth2/userinfo"
client_id="8m67vhg34hgj-232k-786j-90cf-45656gjh5f64g"
client_secret="sd;kfposdfk546idfj;"
cookie_secure="true"
redirect_url="https://example.com/prometheus/oauth2/callback"
upstreams="http://192.168.1.20:9090/prometheus/" # My website server
email_domains="*"
cookie_secret="AkaBxYPzIvMdQziWECV6Ow=="
http_address = "127.0.0.1:4180"
https_address = ":443"
reverse_proxy = true
oauth2 bin command :
[root#nginx]# ./oauth2-proxy --config=/etc/nginx/oauth2-proxy.cfg
[2022/02/03 17:23:54] [proxy.go:89] mapping path "/prometheus/" => upstream "http://192.168.1.20:9090/prometheus/"
[2022/02/03 17:23:54] [oauthproxy.go:148] OAuthProxy configured for Keycloak Client ID: 8m67vhg34hgj-232k-786j-90cf-45656gjh5f64g
[2022/02/03 17:23:54] [oauthproxy.go:154] Cookie settings: name:_oauth2_proxy secure(https):true httponly:true expiry:168h0m0s domains: path:/ samesite: refresh:disabled
The oauth2-proxy port 4180 is listening ok :
[root#nginx]# netstat -naptu | grep 4180
tcp 0 0 127.0.0.1:4180 0.0.0.0:* LISTEN 26031/./oauth2-prox
Here is the page of prometheus login point out on oauth2-proxy for authentication
After authentication, is redirect me to the https://auth.keycloak page and not to the upstream https://example.com/prometheus
On the outh2-proxy I have this output whenever I want to access "https://example.com/prometheus"
9 Safari/537.36" 401 13 0.000
[2022/02/03 17:29:59] [validator.go:77] Rejecting invalid redirect "https://example.com": domain / port not in whitelist
[2022/02/03 17:29:59] [director.go:85] Invalid redirect provided in X-Auth-Request-Redirect header: https://example.com
[2022/02/03 17:29:59] [validator.go:77] Rejecting invalid redirect "https://example.com": domain / port not in whitelist
[2022/02/03 17:29:59] [director.go:85] Invalid redirect provided in X-Auth-Request-Redirect header: https://example.com
What I'm missing here .. I don't have any ideas anymore.

I found the solution:
Step1. Download oauth2-proxy binary - my version is oauth2-proxy v7.2.1
Step2. Create oauth2-proxy as services in order to run "start| stop | status".
[root#nginx]# cat oauth2_proxy.service
[Unit]
Description=oauth2_proxy daemon
After=syslog.target network.target
[Service]
ExecStart=/var/opt/oauth2-proxy --config=/etc/nginx/oauth2-proxy.cfg
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target
Running Status oauth2_proxy command
[root#nginx]# systemctl status oauth2_proxy
● oauth2_proxy.service - oauth2_proxy daemon
Loaded: loaded (/etc/systemd/system/multi-user.target.wants/oauth2_proxy.service; bad; vendor preset: disabled)
Active: active (running) since Tue 2022-02-08 11:03:05 CET; 1 day 22h ago
Main PID: 34114 (oauth2-proxy)
CGroup: /system.slice/oauth2_proxy.service
└─34114 /var/opt/oauth2-proxy --config=/etc/nginx/oauth2-proxy.cfg
Feb 08 11:03:05 nginx.local systemd[1]: Started oauth2_proxy daemon.
Feb 08 11:03:05 nginx.local oauth2-proxy[34114]: [2022/02/08 11:03:05] [logging.go:27] Redirecting logging to file: /var/log/oauth2/oauth2_proxy.log
Step3. Create ouath2-proxy.cfg and add the below lines:
provider="oidc"
provider_display_name="SSO Connect"
login_url="https://auth.keycloak/oauth2/authorize"
validate_url="https://auth.keycloak/oauth2/token"
profile_url="https://auth.keycloak/oauth2/userinfo"
client_id="8m67vhg34hgj-232k-786j-90cf-45656gjh5f64g"
client_secret="sd;kfposdfk546idfj"
redirect_url="https://example.com/oauth2/callback"
upstreams=["http://192.168.1.20:9090/prometheus/"] # My website server
###OIDC settings
#reverse_proxy=true
oidc_issuer_url="https://auth.keycloak"
insecure_oidc_allow_unverified_email=true
email_domains=["*"]
cookie_secret="AkaBxYPzIvMdQziWECV6Ow=="
http_address="127.0.0.1:4180"
whitelist_domains="tool.example.com"
cookie_domains=["tool.example.com"]
cookie_secure="false"
cookie_samesite="lax"
pass_authorization_header = true
pass_access_token = true
pass_user_headers = true
set_authorization_header = true
set_xauthrequest = true
cookie_refresh = "1m"
cookie_expire = "30m"
scope="openid email profile"
Step4. Add lines below on nginx.conf in order to make the authentication and redirecting to prometheus upstream
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $request_uri;
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location ^~ /prometheus/ {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
proxy_pass http://prometheus_backend/prometheus/;
}
I hope you don't have any problems and make it works.

Related

Custom location for PGAdmin redirect to 'localhost/' nginx

I have a nginx server with a nodejs API on 'localhost/api' and PGAdmin4 on 'localhost/'. In this case everything works without problem, but as soon as I configure the location of PGAdmin4 in the nginx.conf on 'localhost/pgadmin4', when I click on the login button on the PGAdmin4 interface, I am redirected to 'localhost/' and do not access therefore to PGAdmin.
I have tried several solutions found here, but nothing works ..
Here is my nginx.conf file (pgadmin in proxy_pass is defined in my docker-compose.yml):
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events { worker_connections 1024; }
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /dev/null;
upstream app {
least_conn;
server app:3000 weight=10 max_fails=3 fail_timeout=30s;
}
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
location /api/ {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /pgadmin {
proxy_pass http://pgadmin;
proxy_http_version 1.1;
proxy_set_header X-Script-Name /pgadmin;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}
With apache24 as the reverse-proxy and pgadmin4 running standalone with uWSGI, I was successful with setting the X-Script-Name header in the reverse-proxy.
Alternatively, it works also properly with not setting the X-Script-Name header in the reverse-proxy, not rewriting URL path-component in the reverse proxy, but instead adding the following configuration to uWSGI:
route-run = addvar:SCRIPT_NAME=/pgadmin
route = ^/pgadmin(.*) rewrite:$1
This removes the relocating URL path-component from PATH_INFO and puts it into SCRIPT_NAME, and is independent of what webserver is used.
I am not familiar with nginx, but comparing Your quoted config with the documentation at https://www.pgadmin.org/docs/pgadmin4/latest/container_deployment.html#http-via-nginx I might assume Your proxy_path value is wrong, and should rather contain something like http://localhost:5050/.

How to change request_uri in nginx proxy_pass?

I am running a django application through gunicorn via unix socket and I have my nginx configuration which looks like this :
Current NGINX config File :
upstream django_app_server {
server unix:/django/run/gunicorn.sock fail_timeout=0;
}
server{
listen 80;
server_name demo.mysite.com;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://django_app_server;
break;
}
}
}
so my django is running on a unix socket here , lets say if it was running on localhost then it has a url which looks like :
http://127.0.0.1:8000/demo/app1
http://127.0.0.1:8000/demo/notifications
Main goal
so what i want to do is , when someone visit http://demo.mysite.com/app1 they can access via proxy pass the url : http://127.0.0.1:8000/demo/app1
It would have been really easy if i would be running django on localhost tcp port and i could have easy done this and it would have worked for me :
server{
listen 80;
server_name demo.mysite.com;
location / {
proxy_pass http://127.0.0.1:8000/demo/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
How do i achieve this with my current nginx configurtion ?
One approach is to use rewrite ... break, for example:
location / {
try_files $uri #proxy;
}
location #proxy {
rewrite ^ /demo$uri break;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://django_app_server;
}
See this document for details.

Nginx HTTP to HTTPS redirect loop

I have the folloiwng Nginx configuration:
server {
listen 80;
server_name .example.net .example.com;
return 301 https://example.com$request_uri;
}
server {
listen 80;
server_name beta.example.com;
error_page 403 /403;
error_page 404 /404;
error_page 500 /500;
client_max_body_size 5M;
# Handle all locations
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/cert_chain.crt;
ssl_certificate_key /etc/ssl/csr.pem;
server_name example.com;
error_page 403 /403;
error_page 404 /404;
error_page 500 /500;
client_max_body_size 5M;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
I'm wanting to redirect HTTP requests to HTTPS however I get a redirect loop. I've read other answers on different questions including this one and this one however none of their solutions solved mine. Any ideas? Thanks.
It seems like your backend (running on 127.0.0.1:8000) issues Location: http://example.com/ header.
Please look into the access logs, nginx's and backend's too.
Or use httpliveheaders or tcpdump to investigate the traffic.

Nginx https reverse proxy infinite loop

this is my site-available nginx configuration for flask application
server {
listen 80;
server_name _;
access_log /var/log/nginx/nginx_access.log;
error_log /var/log/nginx/nginx_error.log;
rewrite ^ https://$http_host$request_uri? permanent;
}
server {
listen 443;
server_name _;
access_log /var/log/nginx/nginx_access.log;
error_log /var/log/nginx/nginx_error.log;
ssl on;
ssl_certificate /etc/nginx/ssl/<redacted>.pem;
ssl_certificate_key /etc/nginx/ssl/<redacted>.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_redirect off;
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;
}
}
I have gone through the questions
Nginx configuration leads to endless redirect loop
and nginx redirect loop with ssl. I seem to have the configuration specified in them already.
EDIT
Flask application is running via gunicorn/supervisord
Supervisor config.conf
[program:config]
command=/usr/local/bin/gunicorn run:app --config /etc/gunicorn/gunicorn.conf --preload
directory=/srv/<application>
autostart=true
autorestart=true
startretries=10
stderr_logfile = /var/log/supervisord/<application>-stderr.log
stdout_logfile = /var/log/supervisord/<application>-stdout.log
user=root
Gunicorn gunicorn.conf
bind = '0.0.0.0:5000'
backlog = 2048
workers = 3
worker_class = 'sync'
worker_connections = 1000
timeout = 30
keepalive = 2
accesslog='/var/log/gunicorn/gunicorn_access.log'
errorlog='/var/log/gunicorn/gunicorn_error.log'
pidfile = '/tmp/gunicorn.pid'
loglevel = 'debug'
Flask Application
run.py
from app import app
from app import views
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
view.py
from app import app, session
from flask import render_template, json, jsonify
import datetime
#app.route("/hello/")
def render_templates():
return render_template("display.html")
(... other code ..)
NB: I have an ELB in front of the flask application. 80 and 443 ports are open.
Input: https://example.com/hello/ Output: Redirected Loop
Any help will be appreciated.Thanks in advance.
I did figure out the issue.
The nginx configuration should have been
server {
listen 80;
server_name _;
access_log /var/log/nginx/nginx_access.log;
error_log /var/log/nginx/nginx_error.log;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
As ELB does an unloading of HTTPS encryption to HTTP request , my previous configuration was redirecting all my HTTP requests into HTTPS.

redirect reverse-proxy to SSL depending on origin of request

I have an NGINX server which binds to port 443, provides authentication, and reverse-proxies all SSL requests to a bunch of back-end servers. Another server listens on port 80, but it momentarily does simply leads to a placeholder page. How do I get NGINX to redirect all external requests to the SSL-protected sites, while redirecting all intranet requests to the same sites without SSL? Here is the relevant part of my nginx.conf:
server {
listen 80;
server_name intranet;
allow 10.10.0.0/16;
#charset koi8-r;
access_log logs/host.access.log main;
#######################################
#
# locations on LOCALHOST
#
#######################################
location / {
allow all;
root /data/www;
index index.html index.htm;
}
##############
# HTTPS server
##############
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /srv/ssl/ExternalSite.com.combined.crt;
ssl_certificate_key /srv/ssl/ExternalSite.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
#######################################
#
# Reverse proxy blocks
#
#######################################
#General ExternalSite web site
location / {
auth_basic "Please enter userid and password to enter the ExternalSite web site";
auth_basic_user_file /var/www/www.ExternalSite.com/.htpasswd;
proxy_buffers 16 4k;
proxy_buffer_size 2k;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Accept-Encoding "";
proxy_pass http://10.10.10.16:2080;
}
#nagios server
location /nagios {
auth_basic "Please enter userid and password to enter the ExternalSite nagios web site";
auth_basic_user_file /var/www/www.ExternalSite.com/.htpasswd;
proxy_set_header Authorization $http_authorization;
proxy_buffers 16 4k;
proxy_buffer_size 2k;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Accept-Encoding "";
proxy_pass http://10.10.10.18/nagios;
}
# # munin server
location /munin {
auth_basic "Please enter userid and password to enter the ExternalSite munin web site";
auth_basic_user_file /var/www/www.ExternalSite.com/.htpasswd;
proxy_set_header Authorization $http_authorization;
proxy_buffers 16 4k;
proxy_buffer_size 2k;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Accept-Encoding "";
proxy_pass http://10.10.10.18/munin;
}
#######################################
#
# End of Reverse proxy blocks
#
#######################################
}
To split Intranet and external requests, create another server section and modify the listen instruction to include corresponding interface.
I.e., if your Intranet interface is 10.10.10.1 and public IP is 54.200.200.200, for Intranet you would do:
listen 10.10.10.1:80
And for external requests:
listen 54.200.200.200:80
Then to redirect to ssl, use the nginx return statement to the same server but with https.
Update: sample Nginx configuration schema (as per comments):
#######################################
#
# Intranet server
#
#######################################
server {
listen 10.10.10.1:80 default_server;
server_name intranet;
allow 10.10.0.0/16;
deny all;
# server configuration with all locations, proxy_passes, etc.
}
#######################################
#
# Internet server, redirecting to ssl
#
#######################################
server {
listen 80;
server_name www.yourdomain.com;
location / {
return https://www.yourdomain.com$request_uri;
}
}
##############
# HTTPS server
##############
server {
listen 443 ssl;
server_name www.yourdomain.com;
# server configuration with all locations, proxy_passes, etc.
}