CouchDB 3.3 如何集成 Keycloak 通过 OpenID Connect 颁发 JWT?
解读
在国内金融、政务云等合规场景下,CouchDB 常被要求关闭默认的 cookie/basic 认证,转而由统一身份认证平台(Keycloak)签发 JWT,以实现单点登录与细粒度授权。面试官问“如何集成”,核心想验证候选人是否亲手踩过国产 Keycloak 的坑:包括国产化改造后的 SM2/SM3 算法、外网无法访问的 Maven 仓库、以及 CouchDB 3.3 的 jwt_auth 插件与 Keycloak 的 OIDC discovery 端点之间如何打通。回答必须给出可落地的配置片段,并指出国产化 Keycloak 与社区版的差异点,否则会被认为“只看过文档”。
知识点
- CouchDB 3.3 的 jwt_auth 插件加载机制与 secret 刷新策略
- Keycloak 的 OIDC well-known 端点(/realms/{realm}/.well-known/openid-configuration)与 JWK Set 轮换
- JWT 声明到 CouchDB 角色的映射规则:{couchdb.roles: ["_admin"]}
- 国产化改造:信创环境需替换 SunEC 算法提供者为 BouncyCastle,并配置 SM2withSM3 的 JWT 签名验证
- 高并发下的 JWK 缓存与 fallback 证书策略,防止 Keycloak 重启导致 401 风暴
答案
步骤一:启用 jwt_auth
在 local.ini 追加:
[jwt_auth]
enabled = true
secret_fetcher = couch_jwt_http
http_url = https://keycloak.example.com/realms/couchdb/protocol/openid-certs
alg = RS256
required_claims = {"iss":"https://keycloak.example.com/realms/couchdb"}
步骤二:国产化 Keycloak 证书兼容
若 Keycloak 使用国密 SM2 证书,需在 CouchDB 所在容器安装 BCFIPS 1.0.2 包,并在 vm.args 追加:
-Djava.security.properties=/opt/couchdb/etc/sm2.security
步骤三:角色映射
在 Keycloak 的 Client Scope 里添加 couchdb.roles 映射器,类型为 User Realm Role,Token Claim Name 填 couchdb.roles,Multivalued 开启。
在 CouchDB 的 default.json 里配置:
{"jwt_auth":{"roles_claim":"couchdb.roles","role_prefix":""}}
步骤四:验证
curl -H "Authorization: Bearer ${KC_ACCESS_TOKEN}" https://couchdb.example.com/_session
返回 {"userCtx":{"name":"alice","roles":["_admin"]}} 即成功。
步骤五:生产加固
- 在 nginx ingress 层开启 ssl_verify_depth 2,强制客户端证书校验,防止 JWT 泄露后的重放。
- 设置 [jwt_auth] max_token_age = 300,与 Keycloak 的 Access Token Lifespan 保持一致,避免边缘时钟漂移导致 401。
拓展思考
- 若客户要求双向 TLS + JWT 混合认证(mTLS 做通道加密,JWT 做业务鉴权),CouchDB 的 ssl_verify_fun 回调如何同时校验客户端证书与 JWT?
- 当 Keycloak 集群跨两地三中心部署,JWK Set 出现分区不一致时,CouchDB 的 secret_fetcher 如何实现 last-writer-wins 的证书合并策略?
- 国产化场景下,SM2 公钥长度 512 bit,超出 CouchDB 默认 jwt_auth 的 RSA 4096 缓存槽,需重新编译 couch_jwt_http 模块,如何在不改源码的情况下通过 ERL_FLAGS 动态扩容?