-
-
Notifications
You must be signed in to change notification settings - Fork 41
Using nginx sso with haproxy and SPOE
- Docker
- haproxy
- nginx-sso
- haproxy-spoe-server
- A python script as glue between haproxy and nginx-sso
Two docker containers are used. One for nginx-sso
itself, and the other is an SPOE agent for haproxy that can run the python script.
mkdir -p /srv/spoe-server
docker run \
--name=spoe-server \
-p 172.17.0.1:12345:12345 \
--restart=unless-stopped \
--volume="/srv/spoe-server:/data" \
-d mjbnz/haproxy-spoe-server:latest
mkdir -p /srv/nginx-sso
docker run \
--name=nginx-sso \
-p 172.17.0.1:8082:8082 \
--restart=unless-stopped \
--volume="/srv/nginx-sso:/data" \
-d luzifer/nginx-sso:latest
A python script is used as the glue between haproxy-spoe-server
and nginx-sso
. After deploying the haproxy-spoe-server
container, replace the content of spoe_python.py
in the /data
volume (/srv/spoe-server/spoe_python.py
if you used the above command) with the following, then restart the container:
import spoa
import ipaddress
import requests
auth_url = "http://172.17.0.1:8082/auth"
def check_sso_auth(args):
raw_args = args
args = dict()
for a in raw_args:
if a['value'] is not None:
args[a['name']] = str(a['value'])
authed = False
headers = {
'X-Real-IP': args['ip'],
'X-Host': args['host'],
'X-Origin-URI': args['uri']
}
if 'ff' in args: headers['X-Forwarded-For'] = args['ff']
if 'cookies' in args: headers['Cookie'] = args['cookies']
r = requests.get(auth_url, headers=headers)
if r.status_code == 200:
authed = True
if 'Set-Cookie' in r.headers:
spoa.set_var_str("cookie", spoa.scope_txn, r.headers['Set-Cookie'])
spoa.set_var_boolean("auth", spoa.scope_txn, authed)
return
spoa.register_message("check-sso-auth", check_sso_auth)
Configuration of nginx-sso is beyond the scope of this short howto - there's nothing special required from it, so you should configure it as you please.
The following contains the absolute basics, you should ensure that the rest of the configuration is fleshed out how you need it for your environment. It covers the configuration for SPOE, and how to deal with the redirects to nginx-sso for the login form. It also doesn't have any SSL configuration, that's left up to you.
Note that the filter being applied can be placed in the frontend, but to selectively apply it based on the Host:
header will take a little extra care and attention. You don't really want to apply the filter to the nginx-sso login page domain name or path. To do this, you'll need to create an acl in the spoa-server.spoe.conf
file, and then check that acl on the event
line with an haproxy condition (unless
or if
). You will also need to change the event to be on-frontend-http-request
. There are some commented examples in the file content below.
defaults
mode http
timeout connect 5s
timeout client 5s
timeout server 1m
frontend fe-http
bind :80
acl is_login hdr(host) -i login.yourdomain.com
use_backend be-login-nginx-sso if is_login
default_backend be-http
backend be-http
description Primary webserver
filter spoe engine spoa-server config spoa-server.spoe.conf
acl is_authed var(txn.sso.auth) -m bool
http-request set-var(req.sch) str(https) if { ssl_fc }
http-request set-var(req.sch) str(http) if !{ ssl_fc }
http-request redirect code 302 location http://login.yourdomain.com/login?go=%[var(req.sch)]://%[hdr(host)]%[url] unless is_authed
http-response add-header Set-Cookie %[var(txn.sso.cookie)] if is_authed
server webserver-1 ip.of.your.webserver:80
backend be-login-nginx-sso
description nginx-sso login page
option forwardfor
server nginx-sso 172.17.0.1:8082
backend be-spoe-server
mode tcp
server spoe-server 172.17.0.1:12345
[spoa-server]
spoe-agent spoa-server
messages check-sso-auth
option var-prefix sso
timeout hello 100ms
timeout idle 30s
timeout processing 15ms
use-backend be-spoe-server
spoe-message check-sso-auth
args ip=src ff=req.fhdr(x-forwarded-for) host=req.fhdr(host) uri=url cookies=req.fhdr(cookie)
event on-backend-http-request
# When applying to the frontend, something like this will be needed:
# acl is_login hdr(host) -i login.yourdomain.com
# event on-frontend-http-request unless is_login
For more information on haproxy and SPOE, see: