ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ingress NGINX Controller 外部 OAuth 认证实战:用 auth-url / auth-signin 注解集成 OAuth2 Proxy 与 Vouch Proxy

Ingress NGINX Controller 外部 OAuth 认证实战:用 auth-url / auth-signin 注解集成 OAuth2 Proxy 与 Vouch Proxy Ingress NGINX Controller 外部 OAuth 认证实战用 auth-url / auth-signin 注解集成 OAuth2 Proxy 与 Vouch Proxy【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx本文以 ingress-nginx 官方示例 docs/examples/auth/oauth-external-auth/README.md 为骨架系统讲解如何通过auth-url与auth-signin两个注解让 Ingress NGINX Controller 把请求转发给外部认证服务OAuth2 Proxy、Vouch Proxy进行鉴权从而保护 Kubernetes Dashboard 等应用。读完本文你将掌握多 Ingress 协同的认证架构、两类 OAuth 网关的完整部署配置、认证注解族的每一个可用参数以及 Controller 底层通过auth_request子请求实现鉴权的原理。一、核心机制多个 Ingress 协同保护同一个 HostExternal OAuth 认证的整体思路并不是在单个 Ingress 上启用复杂的认证插件而是针对同一个 Host 部署多个 Ingress 对象各司其职第一个 Ingress没有任何特殊注解仅负责把认证服务的路径例如/oauth2暴露出去使外部认证端点可被访问。其他 Ingress 通过nginx.ingress.kubernetes.io/auth-url注解要求 Controller 在转发请求前先向第一个 Ingress 暴露的认证端点发送子请求进行校验再通过nginx.ingress.kubernetes.io/auth-signin注解把返回401未认证的请求重定向到登录端点。一个典型的注解组合如下... metadata: name: application annotations: nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd$escaped_request_uri ...这里用到了两个 Nginx 变量$host当前请求的 Host 头动态指向同一个域名下的认证端点天然支持多域名复用$escaped_request_uri当前请求的完整 URI已做 URL 转义作为登录成功后的回跳地址rd参数确保用户认证完成后能回到最初访问的页面。版本要求该功能需要ingress-nginx-controller v0.9.0或更高版本示例文档明确标注。在当前仓库中相关注解由 internal/ingress/annotations/authreq/main.go 负责解析与校验。二、auth-url / auth-signin 注解作用域、风险与校验规则在 authreq/main.go 中Controller 为外部认证定义了完整的注解族其中最关键的两个注解定义如下节选authReqURLAnnotation auth-url authReqSigninAnnotation auth-signin ... authReqURLAnnotation: { Validator: parser.ValidateRegex(parser.URLWithNginxVariableRegex, true), Scope: parser.AnnotationScopeLocation, Risk: parser.AnnotationRiskHigh, Documentation: This annotation allows to indicate the URL where the HTTP request should be sent, }, authReqSigninAnnotation: { Validator: parser.ValidateRegex(parser.URLWithNginxVariableRegex, true), Scope: parser.AnnotationScopeLocation, Risk: parser.AnnotationRiskHigh, Documentation: This annotation allows to specify the location of the error page, },三个值得注意的源码事实auth-url是必填项Parse方法main.go#L314-L324会先读取auth-url若缺失则直接报错若 URL 解析失败整个 Location 会被拒绝LocationDeniedError。而auth-signin是可选参数缺失时只记录日志。作用域是 LocationAnnotationScopeLocation注解只对所在 Ingress 的路径规则生效而不是全局。两者都被标记为高风险AnnotationRiskHigh注解它们允许在 URL 中携带 Nginx 变量。结合 Controller 的annotations-risk-level安全配置过高的风险等级注解可能会被拒绝应用。测试用例authreq/main_test.go验证了该解析器的行为空 URL、无 scheme 的 URL、非法 host如http://foo..bar.com都会导致解析失败而携带 query 参数如?allowed_groupssnow-group,rain-group的合法 URL 会被正确接受。三、完整的认证注解族除auth-url与auth-signin外Controller 还支持一整组用于调优认证行为的注解官方说明见 docs/user-guide/nginx-configuration/annotations.md源码定义见 authreq/main.go注解说明默认值nginx.ingress.kubernetes.io/auth-url认证服务 URLController 会向该地址发送子请求进行鉴权必填无nginx.ingress.kubernetes.io/auth-method发送认证子请求使用的 HTTP 方法GET/HEAD/POST/PUT/PATCH/DELETE/CONNECT/OPTIONS/TRACEGETnginx.ingress.kubernetes.io/auth-signin未认证时重定向的登录页地址错误页位置无nginx.ingress.kubernetes.io/auth-signin-redirect-param错误页 URL 中携带原始请求地址的参数名无nginx.ingress.kubernetes.io/auth-response-headers认证请求完成后需要透传给后端的响应头逗号分隔无nginx.ingress.kubernetes.io/auth-proxy-set-headers指定一个 ConfigMap其中的键值对作为请求头发送给认证服务仅限同命名空间无nginx.ingress.kubernetes.io/auth-request-redirect设置X-Auth-Request-Redirect请求头的值无nginx.ingress.kubernetes.io/auth-cache-key开启认证结果缓存并指定缓存键如$remote_user$http_authorization关闭nginx.ingress.kubernetes.io/auth-cache-duration按响应码设置认证结果缓存时长如200 202 10m, 401 5m200 202 401 5mnginx.ingress.kubernetes.io/auth-keepalive到auth-url的 keepalive 连接数上限0关闭nginx.ingress.kubernetes.io/auth-keepalive-requests单条 keepalive 连接可服务的最大请求数1000nginx.ingress.kubernetes.io/auth-keepalive-timeout空闲 keepalive 连接保持时长秒60nginx.ingress.kubernetes.io/auth-keepalive-share-vars是否在主请求与认证子请求之间共享 Nginx 变量falsenginx.ingress.kubernetes.io/auth-always-set-cookie是否总是设置认证请求返回的 Cookiefalsenginx.ingress.kubernetes.io/auth-snippet自定义认证配置片段仅在与auth-url同时使用时生效无几个容易踩坑的细节均有源码依据缓存默认值DefaultCacheDuration 200 202 401 5mmain.go#L176-L177即默认对200/202/401响应缓存 5 分钟。缓存格式对应 Nginxproxy_cache_valid指令。keepalive 与变量互斥当auth-url的 host 部分包含$变量如$host时auth-keepalive会被强制重置为0main.go#L372-L378因为 Nginx 的 upstream 块无法引用变量。keepalive 的 HTTP/2 限制官方文档明确提示auth-keepalive在 HTTP/2 listener 下因 Lua subrequest 限制不生效需要关闭use-http2。跨命名空间限制auth-proxy-set-headers引用的 ConfigMap 必须与 Ingress 同命名空间除非 Controller 开启了allow-cross-namespace-resources否则 Location 会被拒绝main.go#L449-L455。缓存键按 server location 隔离auth-cache-key的缓存空间是每个 server、每个 location 独立的缓存结果不会跨 location 复用。四、方案一OAuth2 Proxy Kubernetes DashboardGitHub 作为 OAuth2 Provider下面完整演示如何把oauth2_proxy部署进 Kubernetes 集群并用它保护 Kubernetes Dashboard。完整清单见 oauth2-proxy.yaml。4.1 准备步骤第 1 步安装 Kubernetes Dashboard使用官方提供的 Dashboard 清单示例基于 v1.10.1创建资源kubectl create -f kubernetes-dashboard-v1.10.1.yaml第 2 步创建 GitHub OAuth Application在 GitHub 的 Settings → Developer settings → OAuth Apps 中创建一个自定义 OAuth 应用Homepage URL填 Ingress 规则中的 FQDN例如https://foo.bar.comAuthorization callback URL为 FQDN 加上/oauth2/callback例如https://foo.bar.com/oauth2/callback。第 3 步按实际环境替换 oauth2-proxy.yaml 中的占位值需要配置的变量如下占位符 / 环境变量填写的值OAUTH2_PROXY_CLIENT_IDGitHub OAuth 应用中的Client IDOAUTH2_PROXY_CLIENT_SECRETGitHub OAuth 应用中的Client SecretOAUTH2_PROXY_COOKIE_SECRET用下面的命令生成python -c import os,base64; print(base64.b64encode(os.urandom(16)).decode(ascii))OAUTH2_PROXY_GITHUB_USERS可选但推荐允许登录的 GitHub 用户名列表如alice,bob__INGRESS_HOST__有效 FQDN如foo.bar.com__INGRESS_SECRET__存放有效 SSL 证书的 Secret 名称示例清单中 oauth2-proxy 容器的核心启动参数oauth2-proxy.yamlcontainers: - args: - --providergithub - --email-domain* - --upstreamfile:///dev/null - --http-address0.0.0.0:4180 env: - name: OAUTH2_PROXY_CLIENT_ID value: Client ID - name: OAUTH2_PROXY_CLIENT_SECRET value: Client Secret - name: OAUTH2_PROXY_COOKIE_SECRET value: SECRET # 推荐去掉 --email-domain* 并设置白名单 # - name: OAUTH2_PROXY_GITHUB_USERS # value: alice,bob image: quay.io/oauth2-proxy/oauth2-proxy:latest ports: - containerPort: 4180 protocol: TCP注意点--upstreamfile:///dev/null表示 oauth2-proxy 自身不代理任何后端它只负责 OAuth 鉴权默认--email-domain*放行了所有邮箱域示例注释中明确建议删除该参数并设置OAUTH2_PROXY_GITHUB_USERS白名单以收紧访问控制同一个文件中还定义了暴露 4180 端口的oauth2-proxyService以及两个 Ingress见下。第 4 步部署$ kubectl create -f oauth2-proxy.yaml该文件一次创建四类资源Deployment、Service 及两个 Ingress其中两个 Ingress 的分工正是第一节所述架构第一个 Ingressoauth2-proxyoauth2-proxy.yaml无认证注解仅把 host__INGRESS_HOST__下的/oauth2路径pathType: Prefix路由到oauth2-proxyService 的 4180 端口并配置 TLS Secret第二个 Ingressexternal-auth-oauth2oauth2-proxy.yaml对根路径/启用外部认证metadata: annotations: nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start?rd$escaped_request_uri name: external-auth-oauth2 spec: ingressClassName: nginx rules: - host: __INGRESS_HOST__ http: paths: - path: / pathType: Prefix backend: service: name: kubernetes-dashboard port: number: 804.2 验证访问配置的 URL例如https://foo.bar.com未认证用户会被重定向到 GitHub 授权页面授权完成后跳回 Dashboard五、方案二Vouch Proxy Kubernetes Dashboard第二个示例使用 Vouch Proxy。5.1 准备步骤第 1 步安装 Kubernetes Dashboard同 4.1 第 1 步。第 2 步创建 GitHub OAuth Application同 4.1 第 2 步唯一区别是回调地址Homepage URL填 Ingress 规则中的 FQDN例如https://foo.bar.comAuthorization callback URL为 FQDN 加上/oauth2/auth例如https://foo.bar.com/oauth2/auth注意 Vouch Proxy 使用的是/oauth2/auth与 oauth2-proxy 的/oauth2/callback不同。第 3 步替换 vouch-proxy.yaml 中的占位值环境变量填写的值VOUCH_COOKIE_DOMAINIngress Host即 FQDNOAUTH_CLIENT_IDGitHubClient IDOAUTH_CLIENT_SECRETGitHubClient SecretVOUCH_WHITELIST可选但推荐允许登录的 GitHub 用户名列表如alice,bob__INGRESS_HOST__有效 FQDN如foo.bar.com__INGRESS_SECRET__存放有效 SSL 证书的 Secret 名称示例清单中 Vouch Proxy 容器的关键环境变量vouch-proxy.yamlenv: - name: VOUCH_ALLOWALLUSERS value: true # 推荐移除 VOUCH_ALLOWALLUSERS 并设置白名单 # - name: VOUCH_WHITELIST # value: alice,bob - name: VOUCH_COOKIE_DOMAIN value: Ingress Host - name: VOUCH_LISTEN value: 0.0.0.0 - name: VOUCH_DOCUMENT_ROOT value: oauth2 - name: OAUTH_PROVIDER value: github - name: OAUTH_CLIENT_ID value: Client ID - name: OAUTH_CLIENT_SECRET value: Client Secret image: quay.io/vouch/vouch-proxy:latest ports: - containerPort: 9090 protocol: TCP注意点VOUCH_DOCUMENT_ROOToauth2使 Vouch 的服务端点挂载在/oauth2路径下默认VOUCH_ALLOWALLUSERStrue允许所有用户示例注释同样建议改为VOUCH_WHITELIST白名单官方还提供不同 Provider 的配置示例见 Vouch Proxy 项目config目录可自行替换OAUTH_PROVIDER。第 4 步部署$ kubectl create -f vouch-proxy.yaml文件同样包含 Deployment、Service 和两个 Ingress。Vouch 方案的external-auth-oauth2Ingress 注解与 oauth2-proxy 方案不同vouch-proxy.yamlmetadata: annotations: nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/validate nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/login?url$scheme://$http_host$request_uri name: external-auth-oauth2 spec: ingressClassName: nginx rules: - host: __INGRESS_HOST__ http: paths: - path: / pathType: Prefix backend: service: name: kubernetes-dashboard port: number: 80两个差异值得注意auth-url指向 Vouch 的鉴权端点/oauth2/validate而 oauth2-proxy 是/oauth2/authauth-signin使用$scheme://$http_host$request_uri构造回跳地址而 oauth2-proxy 使用$escaped_request_uri二者都支持在登录 URL 中携带原始请求信息。5.2 验证访问https://foo.bar.com未认证用户将先进入 GitHub 授权登录流程认证成功后进入 Dashboard效果与 4.2 节相同。六、底层原理Controller 如何用 auth_request 子请求完成鉴权从 Nginx 配置模板 rootfs/etc/nginx/template/nginx.tmpl 可以看到外部认证的完整落地方式模板为每个启用了认证的 Location 生成一个internal的内部子请求 Locationlocation {authPath} { internal; ... }该 Location 不可从外部直接访问内部 Location 通过proxy_pass把请求转发到auth-url指定的认证服务并支持proxy_cache、proxy_method、proxy_set_header等调优指令主 Location 末尾执行auth_request {authPath};nginx.tmpl#L1236Nginx 会先向认证服务发起子请求返回2xx则放行原始请求返回401则触发error_page 401 {signinLocation};nginx.tmpl#L1251把用户重定向到auth-signin指定的登录页。因此整个请求链路是客户端 ── Ingress NGINX ──auth_request── 认证服务(/oauth2/validate 或 /oauth2/auth) │ │ │ 2xx 放行 / 401 重定向登录 │ 校验 Cookie / Token ▼ ▼ 后端应用(Kubernetes Dashboard) ── 携带用户身份的响应头模板中还处理了auth_response_headers透传、auth_always_set_cookie时auth_request_set $auth_cookie $upstream_http_set_cookie;的设置逻辑以及 keepalive upstream 的生成nginx.tmpl#L624-L629。此外Controller 支持在 ConfigMap 中配置global-auth-url实现全局外部认证并可用nginx.ingress.kubernetes.io/enable-global-auth: false对单个 Ingress 关闭该行为详见 docs/user-guide/nginx-configuration/annotations.md 与 docs/user-guide/nginx-configuration/configmap.md 的global-auth-url小节。七、实施建议与注意事项版本前提外部认证注解要求 ingress-nginx-controller 不低于 v0.9.0本文示例中的ingressClassName: nginx、pathType: Prefix等字段按当前仓库与新版 Kubernetes APInetworking.k8s.io/v1编写。必须使用 HTTPSauth-url/auth-signin中携带 Cookie 与重定向地址请务必为 Ingress 配置 TLS Secret即__INGRESS_SECRET__避免凭证明文传输。务必设置用户白名单两个示例默认都是允许所有用户生产环境应分别使用OAUTH2_PROXY_GITHUB_USERS或VOUCH_WHITELIST限定可登录的 GitHub 账号。$host变量与 keepalive 互斥当auth-url使用$host这类变量时auth-keepalive不会生效这是 Nginx upstream 块无法引用变量的固有限制。回调地址不要写错oauth2-proxy 使用/oauth2/callbackVouch Proxy 使用/oauth2/auth需与各自auth-url端点保持一致否则 GitHub OAuth 回调会 404。八、延伸阅读通用外部认证示例docs/examples/auth/external-auth/README.md注解族完整文档docs/user-guide/nginx-configuration/annotations.md注解解析源码internal/ingress/annotations/authreq/main.go 及单元测试 internal/ingress/annotations/authreq/main_test.goNginx 模板中的auth_request实现rootfs/etc/nginx/template/nginx.tmpl本文使用的两份完整清单oauth2-proxy.yaml、vouch-proxy.yaml【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进