1
0
mirror of https://github.com/Luzifer/nginx-sso.git synced 2024-09-16 17:08:26 +00:00
8 Using nginx sso with haproxy and SPOE
Mike Beattie edited this page 2020-08-10 17:29:11 +12:00
Using:

Docker containers

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.

haproxy-spoe-server
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
nginx-sso
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

spoe-server python script

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)

nginx-sso config

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.

haproxy config

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.

haproxy.conf

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.conf

[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

Further reading

For more information on haproxy and SPOE, see: