From 8e801d31b244e780b878fd2d159a1cf0535fe436 Mon Sep 17 00:00:00 2001 From: graych Date: Tue, 16 Oct 2018 11:32:39 +0800 Subject: [PATCH] auth options: auth/auth_webhook/auth_match/auth_expires --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++---- oidc-access.lua | 45 ++++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ae6d8a9..1cb42db 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,11 @@ 在nginx-ingress-controller基础上扩展 openid-connect 登录代理功能,支持自动刷新过期的的 id-token (通过刷新 access-token 实现) -- Patch 2018-06-17: 负载均衡传入 X-Forwarded-Proto 未同时传入 X-Forwarded-Port 时使用协议默认端口 -- Patch 2018-08-01: 升级到 nginx-ingress-controller 0.17.1 + lua-resty-openidc v1.6.1 -- Patch 2018-08-01: 支持 Annotations 配置 openidc:ext.ingress.kubernetes.io/oidc-* -- Patch 2018-08-01: 支持对Service进行主动健康检查,使用 Annotations 配置:ext.ingress.kubernetes.io/check-http-* +- Update 2018-06-17: 负载均衡传入 X-Forwarded-Proto 未同时传入 X-Forwarded-Port 时使用协议默认端口 +- Update 2018-08-01: 升级到 nginx-ingress-controller 0.17.1 + lua-resty-openidc v1.6.1 +- Update 2018-08-01: 支持 Annotations 配置 openidc:ext.ingress.kubernetes.io/oidc-* +- Update 2018-08-01: 支持对Service进行主动健康检查,使用 Annotations 配置:ext.ingress.kubernetes.io/check-http-* +- Update 2018-10-16: 支持通过白名单和webhook进行访问控制 # Docker Image ``` @@ -175,7 +176,7 @@ data: ``` -# 健康检查 (New) +# 主动健康检查 (New) ``` --- apiVersion: v1 @@ -207,6 +208,73 @@ ext.ingress.kubernetes.io/check-http-extras="{ ``` +# 访问控制:白名单 (New) +``` +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: example-ac + annotations: + ext.ingress.kubernetes.io/oidc-access-extras: > + { + "claim_headers": { + "X-WEBAUTH-USER": "sub", + "X-WEBAUTH-EMAIL": "email", + "X-WEBAUTH-RESULT": "auth", # sub==xiaopal => X-WEBAUTH-RESULT: admin , sub==any-other => HTTP 401 + }, + "auth": "sub", + "auth_match": { + "xiaopal": "admin" + }, + "auth_expires": 600 # session cache expires + } +spec: +... + +``` + +# 访问控制:webhook (New) +``` +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: example-ac + annotations: + ext.ingress.kubernetes.io/oidc-access-extras: > + { + "claim_headers": { + "X-WEBAUTH-USER": "sub", + "X-WEBAUTH-EMAIL": "email", + "X-WEBAUTH-RESULT": "auth", # sub==xiaopal => X-WEBAUTH-RESULT: admin , sub==any-other => HTTP 401 + }, + "auth": "sub", + "auth_webhook": "http://some-service/do-auth", # GET /do-auth?auth=xiaopal => 200 OK admin + "auth_expires": 600 + } +spec: + +... + + + ext.ingress.kubernetes.io/oidc-access-extras: > + { + "claim_headers": { + "X-WEBAUTH-RESULT": "auth", # sub==xiaopal => X-WEBAUTH-RESULT: admin , sub==any-other => HTTP 401 + }, + "auth": "sub", + "auth_webhook": "http://some-service/do-auth", # GET /do-auth?auth=xiaopal => 200 OK remote-admin + "auth_match": { + "remote-admin": "admin" + }, + "auth_expires": 600 + } + + +``` + + # 更多示例 ``` --- diff --git a/oidc-access.lua b/oidc-access.lua index 459ff30..c4806bc 100644 --- a/oidc-access.lua +++ b/oidc-access.lua @@ -141,13 +141,54 @@ if oidc_access and oidc_access ~= "" and oidc_access ~= "none" then claims["enc_id_token"] = session.data["enc_id_token"] claims["bearer_enc_id_token"] = "Bearer " .. session.data["enc_id_token"] end - local str = require "resty.string" - claims["session$id"] = str.to_hex(session.id) + claims["session$id"] = require("resty.string").to_hex(session.id) + claims["session.id"] = claims["session$id"] end if claims and cfg["enc_id_token"] and not claims["enc_id_token"] then claims = nil end + + if claims and (cfg["auth_webhook"] or cfg["auth_match"]) then + + local function auth_perform() + if session.data["auth$update"] then + if not cfg["auth_expires"] then + return session.data["auth$result"] + elseif cfg["auth_expires"] and session.data["auth$update"] + cfg["auth_expires"] > ngx.time() then + return session.data["auth$result"] + end + end + local auth = claims[cfg["auth"] or "sub"] + if auth and cfg["auth_webhook"] then + local httpc = require("resty.http").new() + local res, err = httpc:request_uri(cfg["auth_webhook"], {query={auth=auth}}) + if res and res.status >= 200 and res.status < 300 then + auth = res.body or "ok" + else + if err or res.status < 400 or res.status >= 500 then + ngx.log(ngx.ERR, "failed to request "..cfg["auth_webhook"]..": "..(err or "HTTP "..res.status)) + end + return nil + end + end + if auth and cfg["auth_match"] then + auth = cfg["auth_match"][auth] + end + if auth then + session.data["auth$result"] = auth + session.data["auth$update"] = ngx.time() + session:save() + end + return auth + end + + claims["auth"] = auth_perform() + if not claims["auth"] then + claims = nil + end + end + if not claims and (action ~= "pass") then ngx.status = 401 ngx.exit(ngx.HTTP_UNAUTHORIZED)