背景是这样的:公司统一用 IDaaS(Identity as a Service)做登录,IDaaS 自己持有会话(cookie);后端服务有很多个,想加一个 auth 服务统一做校验 + RBAC,但不想让每个业务服务都折腾一遍接入。这篇文章记录整个方案的推导过程:认证架构怎么设计、ingress-nginx 怎么做全局拦截、ConfigMap 为什么必须进 Git(也就是 GitOps),以及完整的命令清单。

目录

  1. 认证架构:先定三件事
  2. auth 服务的”分级放行表”
  3. GitOps 是什么
  4. GitOps 能做什么(及边界)
  5. 业界通用做法
  6. auth 服务如何使用 GitOps
  7. ingress-nginx ConfigMap 原理详解
  8. 五个 global-auth-* 配置详解
  9. 命令大全
  10. 灰度上线流程(observe → enforce)
  11. 注意事项与红线

1. 认证架构:先定三件事

思路:新增一个 auth 服务,挂在 ingress 后面,所有服务的请求进来前先问它一遍——过了就注入用户信息,没过就把浏览器踢去 IDaaS 登录页,登录完带着 cookie 回来。这个模式就是标准的 oauth2-proxy / 统一认证网关

动工前有三个决策点要先定,否则会返工:

① auth 服务做”判断服务”,别做反向代理。 ingress-nginx 原生支持 auth-url:每个请求 ingress 内部先发一个子请求问 auth 服务,auth 只回 200/401,业务流量完全不经过它。反过来让 auth 当反代(所有 backend 指向它)等于自研网关,超时、websocket、大文件、流式全是坑。

② 会话归属:IDaaS 管认证,auth 只做校验 + RBAC。 IDaaS 自持会话(cookie 种在父域),auth 服务里没有 StpUtil.login、没有自己的 cookie、没有 SSO 回调——它就剩一个 /authz:验 cookie、查权限、回结果。登出天然同步:IDaaS 会话一没,下个请求自然 401。sa-token 只用它的 RBAC 部分(StpInterface + 显式传 uid 的 hasRole/hasPermission),别在后端偷偷 StpUtil.login 变相造会话,那就变成和 IDaaS 双头会话,状态不一致的坑全回来了。

③ 页面和 API 的失败行为必须分开。 302 只对”浏览器直接访问”有意义;XHR 会被浏览器自动跟随 302 拿到 SSO 的 HTML,前端没法处理。API 统一返回 401,前端统一一个拦截器跳 IDaaS 登录页(loginUrl 由前端自己配置——nginx 默认会吞掉 auth 子请求的响应体)。

还有两个硬前提要跟 IDaaS 对清楚:

  • cookie 的 domain 是不是父域。只有 IDaaS 把会话 cookie 直接种在 .company.com,各子域请求才能带着它到 /authz 做校验。如果 cookie 只在 IDaaS 自己域名下,每个子域首次访问都得跳一趟换票,免本地会话的简化就不成立了。
  • 校验方式是什么:SDK 本地验签(JWT/公钥)还是调内省接口?内省的 QPS 限制多少?——这直接决定性能设计。

性能设计的答案:全站流量都打 /authz,如果每次回源内省,IDaaS 就成了全站最热依赖。所以要两层缓存:ingress 层 auth-cache-duration 按 cookie 缓存一层,auth 服务里再加一层 Redis 缓存(cookie → 校验结果,TTL 30~60s);能本地验签就别走内省。代价要说清楚:撤销延迟 = 缓存 TTL(踢人、禁用后最多缓存期内还能访问),按安全要求调。

2. auth 服务的”分级放行表”

“全局开关一打开,所有现有服务瞬间从无需登录变成必须登录”——这是推广最大的阻力。解法是:强制不强制,决定权放在 auth 服务里,而不是靠改各服务的 ingress

ingress 的全局子请求照发,auth 服务按”应用”决定态度:

# 各服务的模式配置
apps:
  a.company.com:  enforce    # 严格:校验 cookie + RBAC,不过就 401
  b.company.com:  observe    # 观察期:照常校验、打日志,但永远返回 200 放行
  c.company.com:  bypass     # 白名单:根本不检查(webhook、公开 API、auth 自己)
  "*":            observe    # 未登记的服务默认 observe(等于没上认证,零惊动)

核心逻辑就几行伪代码:

String app  = 从域名解析出是哪个服务;
String mode = 配置表查模式(app);            // enforce / observe / bypass

if (mode == bypass)  return 200;

result = 验IDaaS cookie + 查RBAC;

if (mode == observe) { 记日志("本该拦", app, path, 失败原因); return 200; }

if (mode == enforce) return result.ok() ? 200+注入头 : 401;

三个模式的语义:

模式 用户视角 auth 服务行为
enforce 没登录会被踢去 SSO 登录页 校验失败返回 401,成功返回 200 + 注入用户头
observe 和”没有认证”完全一样,功能照常用 校验照做、日志记一笔”本该拦”,然后照样放行
bypass 无感知 直接放行,不校验(有 cookie 也会注入头,方便后续切换)

看清楚 observe 那行:它对用户来说和”没有认证”完全一样,唯一的区别是 auth 日志里多了一行”谁、哪个域、哪个路径、为什么本该拦”。这样:

  • 还没准备好接认证的服务什么都不用做,落在 observe 档,行为和今天一模一样;
  • 哪个服务准备好了(前端 401 拦截器做了、内网调用白名单加了),改一行配置从 observe 切成 enforce,即时生效、不用动它的 ingress;
  • 出问题随时改回 observe,秒级回滚。

业务服务这边呢?认证层面零改动——不接 IDaaS SDK、不做登录跳转、没有会话代码。但不是什么都不用干:把”读 header”封装成共享 starter(Filter/ArgumentResolver 把 X-Auth-User-Id 等转成 UserContext),统一”缺头 = 401,默认拒绝”的语义,细粒度权限的数据源想清楚放哪(header 只扛粗校验,操作级权限查共享权限服务)。这些封装成 starter 和全局配置,才配得上”其他服务什么都不用改”。

3. GitOps 是什么

用最简单的话说:GitOps 就是”把部署变成改文件”

  • 以前:你对集群干活——kubectl edithelm upgrade,改了什么只有你自己知道,改错了不好回退,别人不能 review。
  • 以后:你对文件干活——集群里所有该有人负责的东西(部署、配置、权限、密钥引用)都写成声明式文件放在 Git 仓库里,想变更就改文件提 PR;集群里跑着一个机器人程序(Argo CD / Flux)盯着仓库,仓库一变,自动把集群”掰”成和文件一致的样子。

四条原则(OpenGitOps / CNCF 官方定义),所有业界做法都从这四条推出来:

原则 含义
声明式 期望状态用声明式配置描述(YAML / Helm),不是脚本
版本化且不可变 期望状态存在 Git 里,有完整历史,只能追加不能篡改
自动拉取(Pull) 由集群内的控制器主动拉取仓库,而不是人在外面 kubectl push
持续调和(Reconcile) 控制器不停对比”集群现状 vs 仓库声明”,发现偏差就纠正或告警

4. GitOps 能做什么(及边界)

能管什么(原则上一句:”集群里所有该有人负责的东西”):

类别 例子
应用部署 各服务的 Deployment / Service / Ingress、Helm values、镜像版本
集群配置 ingress-nginx 的 ConfigMap、namespace、ResourceQuota、NetworkPolicy
RBAC 谁有什么权限,整张权限表在 Git 里
密钥 加密后入库(sealed-secrets / external-secrets),解密在集群侧完成
平台组件 监控告警规则、日志采集配置、auth 服务及其分级放行表
策略 Kyverno / OPA 规则

白拿到的能力

  1. 回滚 = git revert——发布出问题 revert 一下,控制器自动把集群掰回去,秒级;
  2. 变更审计免费送——谁在什么时候改了什么、谁 review 批的,PR 历史就是变更日志;
  3. 环境晋升——dev / staging / prod 各一个目录,改动往上一个目录”晋升”就是一个 PR;
  4. 多集群一致性——N 个集群同步一份仓库,不会”测试配了生产忘了”;
  5. 灾难重建——集群炸了,重建 = apply 一遍仓库;
  6. 权限收敛——人不再需要生产集群写权限,日常变更全走 PR,写权限只留给 GitOps 机器人;
  7. 漂移检测当告警用——有人绕过流程手改集群,Argo CD / Flux 立刻标记 OutOfSync,可接告警。

边界(不要期望错位):

  • 不管数据库里的数据和运行时状态——只管”声明式该是什么样”,Pod 里发生了什么它不看;
  • 不替代 CI——构建镜像、跑测试仍在 CI;GitOps 接管的是 CI 之后”新镜像怎么变成线上服务”那段。

5. 业界通用做法

标准流水线(构建与部署分离)

开发者 push 业务代码
   ▼
CI:跑测试 → 构建镜像 → 推镜像仓库(打 tag)
   ▼
CI 最后一步:自动把"配置仓库"里的镜像 tag 改成新版本,提一个 PR
   ▼
人 review 这个 PR(这一步就是发布审批)
   ▼
合并 → 集群里的 Argo CD / Flux 发现仓库变了 → 自动 apply

关键认知:CI 管到”镜像构建好”为止,GitOps 管从”镜像”到”线上服务”那段。

推荐仓库结构

gitops-repo/
├── apps/                        # 各应用的部署清单
│   ├── auth-service/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   ├── ingress.yaml
│   │   └── access-config.yaml   # auth 分级放行表
│   └── order-service/...
├── platform/                    # 平台组件
│   ├── ingress-nginx/
│   │   └── controller-configmap.yaml   # ← 全局认证配置在这里
│   ├── argocd/
│   └── monitoring/
├── envs/                        # 环境差异(目录分环境,主流做法)
│   ├── dev/  ├── staging/  └── prod/
└── policies/                    # Kyverno 规则等

几个标志性模式

  • App of Apps:Argo CD 里建一个”根应用”指向一个目录,目录里是所有其他应用的 Application 清单。接入新服务 = 加一个 yaml 提 PR,全自动。
  • 密钥不进明文 Git:sealed-secrets(仓库存加密块,集群内解密)或 external-secrets(仓库只存引用,真值在 Vault)。
  • 渐进式发布:Argo Rollouts / Flagger 把发布变成”5% → 看指标 → 25% → … → 100%”,指标恶化自动回滚。
  • 策略即代码:Kyverno / OPA 在 PR 阶段挡住不合规配置。
  • 镜像自动更新:Image Updater 盯镜像仓库,新 tag 自动提 PR 改 manifest,人只做 review。

落地成熟度:Level 1 配置进 Git + CI apply(有版本化但没有 reconcile,不算真 GitOps)→ Level 2 装 Argo CD/Flux、核心应用托管、有漂移检测 → Level 3 全集群托管 + PR 审批即发布 + 密钥方案 + 策略校验 → Level 4 多集群 + 渐进发布 + IaC。大多数公司终态在 2~3 级,别一上来追求 4。

工具:Argo CD(UI 直观、资料多,推荐起步)或 Flux(更轻、纯声明式);配套 sealed-secrets、Kyverno、Argo Rollouts。

6. auth 服务如何使用 GitOps

结合本方案,先搬三样进仓库——它们”高频改、又怕改坏”,最能体现 GitOps 价值:

进仓库的东西 仓库路径示例 说明
auth 服务自身的部署清单 apps/auth-service/ Deployment、Service、Ingress、SDK 密钥的 Secret 引用
ingress-nginx 的全局认证 ConfigMap platform/ingress-nginx/controller-configmap.yaml 全站行为,最需要 PR 审批
auth 服务分级放行表 apps/auth-service/access-config.yaml 各服务 enforce/observe/bypass 配置

变更流程(以”把 order 服务切到 enforce”为例):

1. checkout 分支,修改 access-config.yaml:order.company.com: observe → enforce
2. 提交、提 PR
3. 平台负责人 review(这一步就是审批)
4. 合并 → Argo CD 自动同步 auth 服务的 ConfigMap
5. auth 服务热加载配置(或自动重启)
6. 观察日志确认生效;出问题 → git revert → 自动回滚

全程不碰 kubectl,所有动作有记录、可回滚。配套红线:集群只读,一切变更走 PR——把能直接写生产 ConfigMap 的 RBAC 收到只剩 GitOps 机器账号。这条执行到位,GitOps 的价值就拿到 80%。

Argo CD Application 示例:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: auth-service
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://git.company.com/platform/gitops-repo.git
    targetRevision: main
    path: apps/auth-service
  destination:
    server: https://kubernetes.default.svc
    namespace: auth-system
  syncPolicy:
    automated:
      prune: false
      selfHeal: true      # 有人手改集群会被自动纠正
    syncOptions:
      - CreateNamespace=true

7. ingress-nginx ConfigMap 原理详解

这一节是我自己踩过最懵的地方——”一个 ConfigMap 凭什么改全局 ingress?”缺的知识点是:

ingress-nginx 不是一个”配置了就生效的 k8s 内置功能”,而是一个跑在 Pod 里的程序。

  1. Ingress 对象本身什么都做不了,它只是存了”域名 → Service”的路牌;
  2. controller(一个 Deployment,Pod 里 = controller 程序 + 一个真正的 nginx)实时 watch 集群里的 Ingress / Service / Secret / ConfigMap,把它们渲染成一份真实的 nginx.conf,写入同 Pod 的 nginx,然后 nginx -s reload 热加载;
  3. 接线方式:controller 启动参数里有 --configmap=<namespace>/<名字>,它就认准了这个 ConfigMap。往里面加的每个 key 都会变成渲染 nginx.conf 的全局参数;
  4. 优先级:Ingress 注解 > ConfigMap 全局值——”个别服务覆盖/退出用注解”就是从这来的;
  5. 数量关系:一个集群通常只有一套 controller(多个副本是同一套的分身,读同一个 ConfigMap);但可以有多套不同 ingressClass 的 controller,每套各认各的 ConfigMap,改配置不能漏;
  6. 安全兜底:reload 前会先 nginx -t 校验,非法配置会 reload 失败并沿用旧配置(错误打在日志里)——所以改完一定要看日志。

配了 global-auth-url 之后实际发生的事:

浏览器 GET a.company.com/api (带 IDaaS cookie)
   └─ controller 内部子请求 GET auth:8080/authz(带上 cookie)
        ├─ 返回 200 → 把 X-Auth-User-* 头复制到原请求上,转给 a 服务的 pod
        ├─ 返回 401 → 302 到 global-auth-signin 指的 IDaaS 登录页(back=原URL)
        └─ 其他返回 → 500

渲染出来的 nginx.conf 里每个 location 会多出类似内容(可以进 Pod 亲眼看到):

location / {
    auth_request /_external_auth;                                    # 转发前先发子请求
    error_page 401 = @sso_redirect;
    auth_request_set $authHeader1 $upstream_http_x_auth_user_id;     # 从 auth 响应里取头
    proxy_set_header X-Auth-User-Id $authHeader1;                    # 注入给后端
}
location = /_external_auth {
    internal;
    proxy_pass_request_body off;
    proxy_pass http://auth.auth-system.svc.cluster.local:8080/authz;
}

生效范围与例外:

  • 默认全开:配置后这套 controller 管的所有 Ingress 自动被保护,其他服务的 ingress YAML 一行不用改——这就是”推广成本低”的含义;
  • 只管这个 controller 名下的流量:绕过 ingress 直连 Pod(NodePort/LB)不走这套,所以 NetworkPolicy 仍然必要;
  • cookie 到不到得了 auth 服务,配置管不了:各服务域名必须在 IDaaS cookie 的父域下;
  • 必须退出的:auth 服务自己的 ingress(否则 302 死循环)、纯公开入口、webhook、健康检查、非浏览器调用方。

8. 五个 global-auth-* 配置详解

这五个 key 是 ingress-nginx 硬编码支持的配置名——controller 源码按这些字符串取值,key 名不能自己发明(写 my-auth-url 它不认识)。能用的完整清单在官方文档:ConfigMap - ingress-nginx

key 来源 作用
global-auth-url key 固定;值 = 你们 auth 服务地址 子请求打到哪(auth 服务的校验接口)
global-auth-signin key 固定;值 = IDaaS 登录页地址 401 时浏览器被 302 去哪(back 带原地址)
global-auth-response-headers key 固定;头名列表你们定的 auth 响应里哪些头要”注入”给后端(头名要当公司规范定死)
global-auth-cache-key key 固定;cookie 名填 IDaaS 实际的 cookie 名 缓存 key,按 cookie 区分用户(必须绑凭证,写死了会把 A 的认证结果发给 B)
global-auth-cache-duration key 固定;值 = 你们定的时长 校验结果缓存多久,少打 auth 服务(撤销延迟 = 缓存 TTL)

对应关系:每个 global-xxx 都有 Ingress 注解版 nginx.ingress.kubernetes.io/xxx。注解管单个 Ingress,global- 前缀的 ConfigMap 版管所有 Ingress 兜底。

完整示例(这段就是要进 Git 仓库的 platform/ingress-nginx/controller-configmap.yaml):

apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
data:
  # ── 全局认证(本方案新增) ──────────────────────────────
  global-auth-url: "http://auth.auth-system.svc.cluster.local:8080/authz"
  global-auth-signin: "https://idaas.xxx.com/login?back=$pass_access_scheme://$http_host$escaped_request_uri"
  global-auth-response-headers: "X-Auth-User-Id,X-Auth-User-Name,X-Auth-User-Roles"
  global-auth-cache-key: "$cookie_<idaas的cookie名>"
  global-auth-cache-duration: "30s"
  # ── 以下为 controller 原有的其他配置,保留不动 ──────────
  # proxy-read-timeout: "60"
  # proxy-send-timeout: "60"

如果 controller 是 Helm 装的,不要 kubectl edit,改 values 再 upgrade(否则下次 upgrade 手改会被冲掉):

# values.yaml
controller:
  config:
    global-auth-url: "http://auth.auth-system.svc.cluster.local:8080/authz"
    global-auth-signin: "https://idaas.xxx.com/login?back=$pass_access_scheme://$http_host$escaped_request_uri"
    global-auth-response-headers: "X-Auth-User-Id,X-Auth-User-Name,X-Auth-User-Roles"
    global-auth-cache-key: "$cookie_<idaas的cookie名>"
    global-auth-cache-duration: "30s"

单个 Ingress 的例外写法

metadata:
  annotations:
    nginx.ingress.kubernetes.io/enable-global-auth: "false"   # 彻底退出全局认证
    # 或者只覆盖单项:
    nginx.ingress.kubernetes.io/auth-url: "http://auth.auth-system.svc.cluster.local:8080/authz-custom"

9. 命令大全

以下命令中 ingress-nginx 是 controller 所在 namespace、auth-system 是 auth 服务所在 namespace、ingress-nginx-controller 是 ConfigMap 名,按实际情况替换。

9.1 第一步:摸清现状

# 集群里有几套 ingress controller?各是什么 ingressClass?
kubectl get ingressclass
kubectl get deploy -A | grep -i ingress

# controller 的启动参数——确认它认哪个 ConfigMap(找 --configmap=...)
kubectl -n ingress-nginx get deploy ingress-nginx-controller \
  -o jsonpath='{.spec.template.spec.containers[0].args}'

# 现有 Ingress 都归哪个 class 管
kubectl get ingress -A \
  -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,CLASS:.spec.ingressClassName'

# 看目标 ConfigMap 现在的内容(可能已有其他 key,编辑时保留)
kubectl -n ingress-nginx get cm ingress-nginx-controller -o yaml

9.2 修改 ConfigMap——临时/应急方式(不建议日常用)

正式路径见 9.3(GitOps)。kubectl 直改仅用于测试环境试验或生产应急。改完 controller 会自动 watch 并热加载,不需要重启

# 方式一:交互式编辑
kubectl -n ingress-nginx edit cm ingress-nginx-controller

# 方式二:一条命令打补丁(推荐脚本化使用)
kubectl -n ingress-nginx patch cm ingress-nginx-controller --type merge -p '
{"data":{
  "global-auth-url":"http://auth.auth-system.svc.cluster.local:8080/authz",
  "global-auth-signin":"https://idaas.xxx.com/login?back=$pass_access_scheme://$http_host$escaped_request_uri",
  "global-auth-response-headers":"X-Auth-User-Id,X-Auth-User-Name,X-Auth-User-Roles",
  "global-auth-cache-key":"$cookie_<idaas的cookie名>",
  "global-auth-cache-duration":"30s"
}}'

# 方式三:整文件 apply(推荐先备份)
kubectl -n ingress-nginx get cm ingress-nginx-controller -o yaml > cm-backup-$(date +%F).yaml
# 编辑后:
kubectl apply -f controller-configmap.yaml

⚠️ 修改前先备份:kubectl -n ingress-nginx get cm ingress-nginx-controller -o yaml > cm-backup.yaml;回滚(无 GitOps 时):kubectl apply -f cm-backup.yaml

9.3 修改 ConfigMap——GitOps 正式路径(推荐)

# 1. 在 Git 仓库里改文件(而不是改集群)
git checkout -b feat/global-auth
vim platform/ingress-nginx/controller-configmap.yaml     # 或 Helm 的 values.yaml
git add . && git commit -m "ingress-nginx: add global auth config"
git push origin feat/global-auth

# 2. 提 PR → 平台负责人 review → 合并

# 3. 用 Argo CD CLI 观察与控制同步(若开了 auto-sync 则自动完成)
argocd app list
argocd app get platform-ingress-nginx          # 看同步状态
argocd app diff platform-ingress-nginx         # 看集群和仓库的差异
argocd app sync platform-ingress-nginx         # 手动触发同步
argocd app history platform-ingress-nginx      # 看同步历史

# 4. 回滚:revert 仓库(首选,保持仓库=真相)
git revert <commit> && git push
# 或临时回滚某次同步(Argo CD 层面):
argocd app rollback platform-ingress-nginx <history-id>

9.4 改完之后:验证生效

# 1. 盯 controller 日志,必须看到成功 reload
kubectl -n ingress-nginx logs -f deploy/ingress-nginx-controller
#    正常输出:"Backend successfully reloaded"
#    配置非法时 reload 失败并沿用旧配置,错误会持续打在日志里

# 2. 亲眼验证渲染出来的 nginx.conf
kubectl -n ingress-nginx exec deploy/ingress-nginx-controller -- \
  grep -B2 -A8 "auth_request" /etc/nginx/nginx.conf

# 3. 功能验证
curl -i http://a.company.com/api/xxx
#    预期:无 cookie → 401(或 302 跳 IDaaS 登录页)
#    有效 IDaaS cookie → 200,后端能收到 X-Auth-User-* 头

# 4. 后端确认收到注入的头
#    在业务服务里打印请求头,确认 X-Auth-User-Id / X-Auth-User-Name / X-Auth-User-Roles 存在

9.5 退出全局认证的命令(某个服务不想被管)

# 方式一:给 Ingress 加注解(编辑 yaml,进仓库走 PR)
#   metadata.annotations:
#     nginx.ingress.kubernetes.io/enable-global-auth: "false"
kubectl -n <ns> edit ingress <ingress-name>     # 临时应急可直接改

# 方式二(推荐):不改 ingress,在 auth 服务分级放行表里把该服务配成 bypass / observe

9.6 多集群同步检查

for ctx in $(kubectl config get-contexts -o name); do
  echo "=== $ctx ==="
  kubectl --context $ctx -n ingress-nginx get cm ingress-nginx-controller \
    -o jsonpath='{.data.global-auth-url}{"\n"}'
done

9.7 分级放行表的变更命令

# ── GitOps 路径(正式) ─────────────────────────────
vim apps/auth-service/access-config.yaml        # 如 order.company.com: observe → enforce
git commit && 提 PR && 合并
# Argo CD 自动同步;若 auth 是"启动加载"模式,确认 Deployment 因 checksum 变化自动滚动重启
kubectl -n auth-system rollout status deploy/auth

# ── 临时/应急路径(直接改集群,事后必须补回 Git) ────
kubectl -n auth-system edit cm auth-access-config
#   改完热加载生效;启动加载模式需:
kubectl -n auth-system rollout restart deploy/auth

# ── 观察效果 ────────────────────────────────────────
kubectl -n auth-system logs -f deploy/auth       # observe 模式的"本该拦"日志在这里

10. 灰度上线流程(observe → enforce)

阶段 做什么 效果
Phase 0 部署 auth 服务,不动任何 ingress 配置;用 curl 直接打 /authz 验证 SDK 校验、RBAC、白名单逻辑 零影响
Phase 1 ConfigMap 配上五个 global-auth-*,但 auth 服务默认 observe 全站行为零变化,唯一效果是日志开始出现”谁、哪个域、哪个路径、为什么本该拦”。跑 1~2 周
Phase 2 挑 1~2 个不重要的服务切 enforce 试点 实战暴露问题(前端 401 拦截器没做、OPTIONS 被拦、内部调用被断),打磨流程
Phase 3 逐个迁移。准入条件:① 用户都有 IDaaS 账号 ② 域名在 cookie 父域下 ③ 没有匿名的非浏览器调用方 每切一个先看它 observe 期”零失败记录”再切,基本保证切换当天没人被挡
Phase 4 新服务默认 enforce;bypass 清单冻结,新增走审批 稳态运行

回滚随时可用:把某个服务在放行表里改回 observe,秒级生效,不用动它的 ingress。

11. 注意事项与红线

配置类:

  1. global-auth-cache-key 必须绑凭证(按 cookie 维度)——写死了会把 A 用户的认证结果发给 B 用户,是事故级配置;
  2. ConfigMap 本身要进 Git(Helm / Kustomize 管理),多集群同步下发,不要 kubectl edit 手改——它是全站行为,改错一行全站 401 或全站裸奔;
  3. controller 配置写错不会全站挂(reload 前有 nginx -t 校验),但只防”写坏 nginx”,防不了”写对了但行为错了”(如 auth-url 填错服务名 → 全站 500)——必须 staging 先走一遍 + 盯日志;
  4. 多套 controller / 多集群:每套各认各的 ConfigMap,漏一套就有一套流量裸奔;
  5. 区分 Secret 和 ConfigMap:这个 ConfigMap 里全是非敏感配置,放 Git 没问题;auth 的 SDK 密钥等凭据走 Secret,Secret 进 Git 要加密(sealed-secrets / external-secrets)。

认证链路类:

  1. OPTIONS 预检不带 cookie:会被 auth 拦死,所有跨域前端直接报 CORS 错——auth 服务对 OPTIONS 直接放行;
  2. auth 服务自己的路由所在 ingress 必须退出全局认证,否则 302 死循环;
  3. Header 伪造:客户端可以自带 X-Auth-User-Id。对策:ingress 侧清除入站同名头;auth 服务无论如何都回写 X-Auth-*(没有用户也写空值);根本防线是 NetworkPolicy 保证后端只能从 ingress 进;
  4. 开放重定向back / rd 参数要校验只允许本站域名;
  5. 撤销延迟 = 缓存 TTL:踢人、禁用后最多缓存期内还能访问,按安全要求调 global-auth-cache-duration
  6. 绕过路径:健康检查、webhook、服务间内网调用不走这套——服务间调用用白名单或 sa-token same-token 互信,不要复用用户会话;
  7. IDaaS 可用性 = 全站可用性:缓存层同时是它抖动时的缓冲;失败策略建议 fail-closed;
  8. API 返回 401 而不是 302:XHR 会被浏览器自动跟随 302 拿到 SSO 的 HTML。业务服务统一 401,前端统一一个拦截器跳 IDaaS 登录页。

本地开发:

  1. 日常开发:业务 starter 的 dev profile 本地造用户,不碰网络;
  2. 联调:首选部署到 dev 集群自己的 namespace 走真实链路;一定要本地起服务,需 hosts 把 dev 域名指到 127.0.0.1 + 本地 nginx 做 auth_request 打到 dev 的 /authz + mkcert 本地 HTTPS(IDaaS cookie 是 Secure 的);
  3. 红线:本地/联调只允许指 dev auth 和 dev 权限库,不给任何直连生产 auth 的路径。

运维类:

  1. 退出清单要有登记:谁能 enable-global-auth: "false" 要走审批,有条件用 Kyverno 审计/拦截;
  2. 监控告警:auth 服务上报”401 比例 / 延迟”告警——ConfigMap 改错的第一个症状是全站 401 或 500;
  3. observe 日志是这个方案的眼睛:别打了没人看,接告警或每周汇总,否则 Phase 1 白跑。

参考