Unable to use subrequest authentication for proxied site
Lists
lists at benjamindsmith.com
Sat Sep 19 16:26:57 UTC 2020
How do I configure nginx to use subrequest authentication for a reverse proxied
application with websocket upgrades? The documentation doesn't seem to contain
the information I need to do this.
https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/
When I do, I either get
A) 404 for every request.
B) All requests pass regardless of php session ID (or not at all) or
It seems that I can either proxy the authentication request (and nginx
attempts to serve local content) OR proxy the request itself (and then I get
the etherpad content without it being authenticated) I can't seem to get both
working together.
SYSTEM CONFIGURATION
I have an instance of Etherpad running on a VM on a host called Alpha. Alpha
is running CentOS 7, the VM is running Centos8.
The Etherpad instance is used in a PHP application running on another server,
and it's important to prevent the etherpad pages from being public, so it
seems the easiest way to secure things is to use subrequest authentication.
Applcation: https://mydomain.com
Etherpad URL: https://etherpad.mydomain.com
1) Within the application, the URL for the etherpad iframe has
&sess_id=$php_session_id added. EG:
https://etherpad.mydomain/p/MyPad?sess_id=MyPhpSessId
This is so that nginx can make a subrequest to the application, passing the
PHP Sessid to validate that the end user with the PHP Sessid has rights to the
document in the etherpad instance.
2) The application has an external authentication page at /external/
etherpad.php. It returns http code 200 when the values in the php session
match the URL of the etherpad address as passed in the header X-Original-URI.
(EG: "MyPad" is referenced in MyPhpSessid) and 401 when this test fails.
3) Nginx is set up on Alpha to proxy to the VM called Virtual. The proxy is
set up with Let's Encrypt SSL certificates; the etherpad instance is not
encrypted but has no direct ports to the public cloud.
WHAT I'M EXPECTING FOR A SUCCESSFUL HIT
1) nginx receives a request like:
https://etherpad.mydomain.com/p/MyPadId?sess_id=PhpSessionId
2) nginx makes a request to
https://mydomain.dom/external/etherpad.php
with header:
X-Original-URI: /p/MyPadId?sess_id=PhpSessionId
3) /external/etherpad.php receives authentication request, gets X-Original-URI
and validates the request, returning an http_code 200 when all is well.
4) nginx receives the result of #3, and passes the original request to the
etherpad instance.
5) Etherpad responds with the result
6) Successful Etherpad instance runs in the application.
*********************************************************
WHAT IS HAPPENING (Schenario 1)
1) nginx receives a request like:
https://etherpad.mydomain.com/p/MyPadId?sess_id=PhpSessionId
2) nginx makes a request to
https://mydomain.dom/external/etherpad.php
with header:
X-Original-URI: /p/MyPadId?sess_id=PhpSessionId
3) /external/etherpad.php receives authentication request, gets X-Original-URI
and validates the request, returning an http_code 200 when all is well.
4) Nginx attempts to resolve the request as a local file, can't find it, and
returns 404 to the end user.
SCENARIO 1 NGINX CONFIG FILE
----------------------
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name etherpad.mydomain.com;
listen 8008;
listen 9000 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/etherpad.mydomain.com/fullchain.pem;
# managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/etherpad.mydomain.com/
privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_pass http://192.168.122.61:9001/;
proxy_set_header Host $host;
proxy_pass_header Server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1; # recommended with keepalive connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /p/ {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
}
location /auth {
internal;
proxy_pass https://mydomain.com/external/etherpad.php;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
----------------------
*********************************************************
WHAT IS HAPPENING (Schenario 2: invalid session ID)
1) nginx receives a request like:
https://etherpad.mydomain.com/p/MyPadId?sess_id=INVALID
2) nginx makes a request to
https://mydomain.dom/external/etherpad.php
with header:
X-Original-URI: /p/MyPadId?sess_id=INVALID
3) /external/etherpad.php receives authentication request, gets X-Original-URI
and validates the request, returning an http_code 401.
4) nginx IGNORES the result of #3, and passes the original request to the
etherpad instance, even when validation fails.
5) Etherpad responds with the result
6) Successful Etherpad instance runs in the application despite lacking
credentials.
SCENARIO 2 NGINX CONFIG FILE
----------------------
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name etherpad.mydomain.com;
listen 8008;
listen 9000 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/etherpad.mydomain.com/
fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/etherpad.mydomain.com/
privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_pass http://192.168.122.61:9001/;
proxy_set_header Host $host;
proxy_pass_header Server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1; # recommended with keepalive connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /p/ {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
# NOTE THAT THIS IS A COPY OF LOCATION / UNTIL THE END OF THIS BLOCK.
proxy_pass http://192.168.122.61:9001/;
proxy_set_header Host $host;
proxy_pass_header Server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1; # recommended with keepalive connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /auth {
internal;
proxy_pass https://mydomain.com/external/etherpad.php;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part.
URL: <http://mailman.nginx.org/pipermail/nginx/attachments/20200919/fcbab907/attachment.bin>
More information about the nginx
mailing list