上篇文章中,我们提到了 Traefik 的 Forward Auth
,本篇内容我们来展开聊聊如何使用它。
准备基础的 Web 服务Demo
这篇文章里,我们继续使用 whoami
作为 Web 服务,基础的配置文件和上一篇文章中一致,暂时不需要额外的设置:
version: '3'
services:
whoami:
image: containous/whoami
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.test-auth-web.middlewares=https-redirect@file"
- "traefik.http.routers.test-auth-web.entrypoints=http"
- "traefik.http.routers.test-auth-web.rule=Host(`whoami.lab.com`, `whoami.lab.io`)"
- "traefik.http.routers.test-auth-ssl.entrypoints=https"
- "traefik.http.routers.test-auth-ssl.tls=true"
- "traefik.http.routers.test-auth-ssl.rule=Host(`whoami.lab.com`, `whoami.lab.io`)"
networks:
- traefik
networks:
traefik:
external: true
使用容器配置 Traefik Forward Auth 服务
thomseddon/traefik-forward-auth 这个开源项目让我们在使用 Traefik 的时候,结合 Forward Auth 中间件,可以快速实现通用 OAuth / SSO 功能:
- 支持多种验证“服务商”:Google/ 通用OAuth / 通用OIDC
- 支持自定义请求服务器和指定路径,方便与现有系统集成
- 支持基础的用户限制、授权来源限制、支持设置跨域 Cookie
简单来说,只要你的系统对外暴露服务是通过 Traefik,那么可以非常轻松愉快的使用这个模式为应用添加一层通用的前置 SSO 。可以达到效果类似我们在外部公网访问公司内网服务时候,会出现的一个登陆框,只有登陆成功后,才会展示我们想要看的内容。
使用这个方案的好处是,我们只需要结合一些简单的胶水代码,就可以做到背后的应用无修改接入或者几乎无修改接入,即使应用本身不支持 OAuth / SSO 方式接入,或者说我们无法直接修改的商业付费软件。
version: '3'
services:
traefik-forward-auth:
image: thomseddon/traefik-forward-auth:v2.2.0
restart: always
hostname: traefik-auth.lab.io
environment:
- LOG_LEVEL=trace
- DEFAULT_PROVIDER=generic-oauth
- PROVIDERS_GENERIC_OAUTH_AUTH_URL=https://sso.lab.io/dialog/authorize
- PROVIDERS_GENERIC_OAUTH_TOKEN_URL=http://sso-web/oauth/token
- PROVIDERS_GENERIC_OAUTH_USER_URL=http://sso-web/api/userinfo
- PROVIDERS_GENERIC_OAUTH_USER_URL=http://sso-web/api/traefik-auth-user
- PROVIDERS_GENERIC_OAUTH_CLIENT_ID=abc123
- PROVIDERS_GENERIC_OAUTH_CLIENT_SECRET=ssh-secret
- PROVIDERS_GENERIC_OAUTH_SCOPE=*
- PROVIDERS_GENERIC_OAUTH_TOKEN_STYLE=header
- SECRET=something-random
- INSECURE_COOKIE=true
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.traefik-auth-web.entrypoints=http"
- "traefik.http.routers.traefik-auth-web.rule=Host(`traefik-auth.lab.com`, `traefik-auth.lab.io`)"
- "traefik.http.routers.traefik-auth-ssl.entrypoints=https"
- "traefik.http.routers.traefik-auth-ssl.rule=Host(`traefik-auth.lab.com`, `traefik-auth.lab.io`)"
- "traefik.http.routers.traefik-auth-ssl.tls=true"
- "traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
- "traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
- "traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4181"
networks:
- traefik
networks:
traefik:
external: true
使用这个项目因为配置项比较多,而显得比较复杂,实际上并非如此,我们一点一点来理解它。
配置应用参数
我们在环境变量中定义了许多内容,这些内容的解释可以参考官方文档,这里我选择了 OAuth 作为授权服务配置,为了演示方便,我将他们运行在相同主机的相同容器网卡中,PROVIDERS_GENERIC_OAUTH_AUTH_URL
是用于用户在浏览器前端访问的地址,用于“确认授权”行为,所以需要配置对外访问的网络域名,除此之外,PROVIDERS_GENERIC_OAUTH_TOKEN_URL
、PROVIDERS_GENERIC_OAUTH_USER_URL
、PROVIDERS_GENERIC_OAUTH_USER_URL
可以都走容器内部通信,更加高效。
如果我们的 SSO 服务可以进行独立部署,那么这里四个 URL 变量需要都配置成可访问的域名地址,如果使用 https 协议,涉及自签名证书,需要重新构建容器。下一篇内容,我们再仔细展开 SSO 服务,这里稍作了解,有个印象就行啦。
environment:
- LOG_LEVEL=trace
- DEFAULT_PROVIDER=generic-oauth
- PROVIDERS_GENERIC_OAUTH_AUTH_URL=https://sso.lab.io/dialog/authorize
- PROVIDERS_GENERIC_OAUTH_TOKEN_URL=http://sso-web/oauth/token
- PROVIDERS_GENERIC_OAUTH_USER_URL=http://sso-web/api/userinfo
- PROVIDERS_GENERIC_OAUTH_USER_URL=http://sso-web/api/traefik-auth-user
- PROVIDERS_GENERIC_OAUTH_CLIENT_ID=abc123
- PROVIDERS_GENERIC_OAUTH_CLIENT_SECRET=secret
- PROVIDERS_GENERIC_OAUTH_SCOPE=*
- PROVIDERS_GENERIC_OAUTH_TOKEN_STYLE=header
- SECRET=something-random
- INSECURE_COOKIE=true
接着我们来进行服务路由的配置。
配置应用服务路由
配置服务路由比较简单,可以根据需求和喜好,设置是否“执行 HTTP 自动转发 HTTPS”等逻辑,设置方法上一篇文章中有描述,就不再赘述:
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.traefik-auth-web.entrypoints=http"
- "traefik.http.routers.traefik-auth-web.rule=Host(`traefik-auth.lab.com`, `traefik-auth.lab.io`)"
- "traefik.http.routers.traefik-auth-ssl.entrypoints=https"
- "traefik.http.routers.traefik-auth-ssl.tls=true"
- "traefik.http.routers.traefik-auth-ssl.rule=Host(`traefik-auth.lab.com`, `traefik-auth.lab.io`)"
...
接着是配置 forwardauth
中间件,这里和配置应用参数情况类似,因为是同机部署演示,这里使用应用名称即可。如果是独立部署,需要替换为访问域名:
labels:
...
- "traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
- "traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
- "traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4181"
上面的中间件配置中还存在一个 authResponseHeaders
配置项 :用来向后续服务传递通过鉴权的用户信息,可以根据自己的需求进行修改或者移除。
最后,使用 docker-compose -d
启动应用,等待应用启动完毕,就可以准备应用接入啦。
完成应用配置
我们将文章开头的 Web 服务 Demo 配置中添加一条简单的配置规则,让刚刚配置的 traefik-forward-auth
加入到应用服务路由中:
version: '3'
services:
whoami:
image: containous/whoami
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
...
- "traefik.http.routers.test-auth-ssl.middlewares=traefik-forward-auth@docker"
...
networks:
- traefik
networks:
traefik:
external: true
将内容单独保存一个新的 docker-compose.yml
,再次继续使用 docker-compose up -d
启动服务,接着进行服务效果验证。
验证 Forward Auth SSO 效果
打开浏览器,输入 whoami.lab.io
,可以看到首先是被重定向到了 https
协议,然后再次被重定向到了 sso.lab.io/...
的 SSO 鉴权地址,提示我们输入账号密码。
我们使用 curl
再来模拟一次服务端请求:
curl https://whoami.lab.io -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to whoami.lab.io (127.0.0.1) port 443 (#0)
...
> GET / HTTP/2
> Host: whoami.lab.io
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 307
< content-type: text/html; charset=utf-8
< date: Wed, 02 Dec 2020 13:45:35 GMT
< location: https://sso.lab.io/dialog/authorize?client_id=abc123&redirect_uri=https%3A%2F%2Fwhoami.lab.io%2F_oauth&response_type=code&scope=%2A&state=396bd5c20d6bcfdffc2426bddf619707%3Ageneric-oauth%3Ahttps%3A%2F%2Fwhoami.lab.io%2F
< set-cookie: _forward_auth_csrf=396bd5c20d6bcfdffc2426bddf619707; Path=/; Domain=whoami.lab.io; Expires=Thu, 03 Dec 2020 01:45:35 GMT; HttpOnly
< content-length: 271
<
<a href="https://sso.lab.io/dialog/authorize?client_id=abc123&redirect_uri=https%3A%2F%2Fwhoami.lab.io%2F_oauth&response_type=code&scope=%2A&state=396bd5c20d6bcfdffc2426bddf619707%3Ageneric-oauth%3Ahttps%3A%2F%2Fwhoami.lab.io%2F">Temporary Redirect</a>.
* Connection #0 to host whoami.lab.io left intact
* Closing connection 0
可以看到配置依然是生效的,服务端返回了 307 重定向,我们发送到 whoami.lab.io
的请求被转向到了 sso.lab.io
,符合我们的预期。
接着在浏览器中输入账号密码,点击提交,可以看到被重定向到了页面授权确认页面。
点击允许,进行授权,等待授权完毕,我们就可以正式访问到应用的页面了。当然,也有一些应用会精简掉用户确认的对话框,让验证的整个流程更加的顺滑:
可以看到,应用请求头 X-Forwarded-User
和 Cookie 中可以看到通过授权的用户信息,可以进行进一步处理,或者鉴权规则的完善。
最后
写到这里,Traefik 基础鉴权验证的内容就完毕了,但是 SSO / OAuth 相关的内容才刚刚开始。
–EOF