Keycloak 之所以成为 IDaaS 首选,很大程度是因为它天然适配开源生态——Grafana、GitLab、Jenkins、Kubernetes、Vault、Harbor 等常见软件要么原生支持 OIDC/SAML,要么通过 OAuth2 Proxy 轻松接入。本节给出一套「配方集」,按软件查配方,最小改动落地 SSO。

前置:先在 Keycloak 创建一个 confidential Client,记录 client_idclient_secretredirect_uri。除非特别说明,统一用 OIDC + 授权码模式 + PKCE

通用模式:OAuth2 Proxy

绝大多数本身不支持 OIDC 的 Web 服务,都可以用 oauth2-proxy 在前置反代中统一接入。它是 Keycloak 集成的瑞士军刀。

# oauth2-proxy.cfg
provider          = "keycloak-oidc"
oidc_issuer_url   = "https://kc.example.com/realms/myrealm"
client_id         = "oauth2-proxy"
client_secret     = "SECRET"
redirect_url      = "https://app.example.com/oauth2/callback"
email_domains     = "example.com"
cookie_secret     = "32字节随机"
set_authorization_header = true
pass_access_token        = true
# Nginx 前置
location /oauth2/ { proxy_pass http://127.0.0.1:4180; }
location / {
    auth_request /oauth2/auth;
    error_page 401 = /oauth2/start;
    proxy_pass http://upstream_app;
}

下面各软件若原生支持 OIDC 则优先用原生,否则用此模式。

Grafana

Grafana 原生支持 OIDC,配置 grafana.ini

[auth.generic_oauth]
enabled = true
name   = Keycloak
client_id     = grafana
client_secret = SECRET
scopes        = openid email profile
auth_url      = https://kc.example.com/realms/myrealm/protocol/openid-connect/auth
token_url     = https://kc.example.com/realms/myrealm/protocol/openid-connect/token
api_url       = https://kc.example.com/realms/myrealm/protocol/openid-connect/userinfo
login_attribute_path = preferred_username
groups_attribute_path = groups
role_attribute_path   = contains(groups[*], 'grafana-admin') && 'Admin' || 'Viewer'
allow_sign_up = true

要点:

  • 在 Keycloak Client 的 Protocol Mappersgroups mapper(把用户 Realm/Client 角色映射成 groups claim),即可用角色驱动 Grafana 权限。
  • role_attribute_path 把 Keycloak 角色映射为 Grafana Admin/Editor/Viewer

GitLab

GitLab 通过 OmniAuth 支持 OIDC(gitlab.rb):

gitlab_rails['omniauth_providers'] = [
  {
    name: "openid_connect",
    label: "Keycloak",
    args: {
      name: "openid_connect",
      scope: ["openid", "profile", "email"],
      response_type: "code",
      issuer: "https://kc.example.com/realms/myrealm",
      discovery: true,
      client_auth_method: "basic",
      uid_field: "preferred_username",
      send_scope_to_token_endpoint: true,
      client_options: {
        identifier: "gitlab",
        secret: "SECRET",
        redirect_uri: "https://gitlab.example.com/users/auth/openid_connect/callback"
      }
    }
  }
]
gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']
gitlab_rails['omniauth_block_auto_created_users'] = false

要点:

  • Keycloak Client 的 redirect_uri 精确填 https://gitlab.example.com/users/auth/openid_connect/callback
  • 通过 groups claim 映射 GitLab Group/角色,实现按域控制权限。

Jenkins

Jenkins 用 OAuth2 / OIDC 插件Keycloak 插件。推荐 Keycloak 插件(更贴合):

  1. 安装 Keycloak Authentication Plugin
  2. Manage Jenkins → Configure Global Security → Security Realm = Keycloak。
  3. 填 Keycloak URL、Realm、Client ID/Secret。
  4. 角色策略:用 Keycloak Realm 角色映射 Jenkins 角色(admin/develop/read)。

CI 场景的「机器账号」用 Service Account + Client Credentials,不要给流水线人工账号。

Kubernetes / NGINX Ingress

Kubernetes 体系下,最常见的是在 NGINX Ingress Controller 前置 oauth2-proxy,按 Ingress 注解启用:

# oauth2-proxy Deployment + Service(kube-system)
apiVersion: apps/v1
kind: Deployment
metadata: { name: oauth2-proxy, namespace: kube-system }
spec:
  replicas: 1
  selector: { matchLabels: { app: oauth2-proxy } }
  template:
    metadata: { labels: { app: oauth2-proxy } }
    spec:
      containers:
      - name: oauth2-proxy
        image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.0
        args:
        - --provider=keycloak-oidc
        - --oidc-issuer-url=https://kc.example.com/realms/myrealm
        - --client-id=oauth2-proxy
        - --client-secret=SECRET
        - --cookie-secret=xxxxxxxxxxxxxxxx
        - --email-domain=*
        - --set-authorization-header
        ports: [{ containerPort: 4180 }]
# 业务 Ingress,启用认证
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app
  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"
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend: { service: { name: app, port: { number: 80 } } }

这是「网关层 SSO」模式:业务代码无需感知身份,鉴权在入口完成。详见 第18章 · 集成模式

Keycloak + oauth2-proxy 生产排错清单

oauth2-proxy 与 Keycloak 对接时,高频问题往往不是「OIDC 不通」,而是 issuer、audience、回调地址或反向代理头不一致。上线前建议按下表逐项核对:

症状 / 报错常见根因修正方式
expected audience / invalid aud,日志里只有 accountKeycloak access token 的 aud 没有包含 oauth2-proxy 的 client_id在 Keycloak Client 增加 Audience mapper,把 Included Client Audience 设为 oauth2-proxy;或在 oauth2-proxy 显式配置 --oidc-extra-audience
登录后反复跳转 / csrf cookie not foundredirect_url、Ingress auth-signin、Cookie Domain / SameSite 与实际访问域名不一致redirect_url 固定为外部入口 https://app.example.com/oauth2/callback;Ingress 使用 $host$escaped_request_uri;跨子域共享时再设置 --cookie-domain=.example.com
/oauth2/auth 返回 401,但用户已登录业务 Ingress 没把认证响应头传给后端,或 oauth2-proxy 未开启 header 输出oauth2-proxy 开启 --set-xauthrequest=true;NGINX Ingress 用 auth-response-headers 透传 X-Auth-Request-UserX-Auth-Request-EmailX-Auth-Request-Groups
Keycloak 回调到 http:// 或错误 hostKeycloak / oauth2-proxy 后面有反向代理,但 X-Forwarded-* 头或 proxy 配置缺失入口层保留 X-Forwarded-ProtoX-Forwarded-Host;Keycloak 侧按生产反向代理章节配置 hostname/proxy headers。
Keycloak 17+ 后 issuer 不匹配仍沿用旧 WildFly 路径 /auth/realms/<realm>新部署默认使用 https://kc.example.com/realms/<realm>;只有旧版本或保留兼容路径时才使用 /auth/realms/<realm>

一个较稳的最小配置如下,重点是 issuer、audience、PKCE、cookie secret 与 header 输出都显式写清:

oauth2-proxy \
  --provider=keycloak-oidc \
  --oidc-issuer-url=https://kc.example.com/realms/myrealm \
  --client-id=oauth2-proxy \
  --client-secret=$OAUTH2_PROXY_CLIENT_SECRET \
  --redirect-url=https://app.example.com/oauth2/callback \
  --cookie-secret=$OAUTH2_PROXY_COOKIE_SECRET \
  --email-domain='*' \
  --code-challenge-method=S256 \
  --set-xauthrequest=true \
  --set-authorization-header=true

验证顺序不要反:先访问 https://kc.example.com/realms/myrealm/.well-known/openid-configuration 确认 issuer;再登录一次并解码 access token,确认 aud 包含 oauth2-proxy;最后用浏览器开发者工具检查 /oauth2/callback 是否设置了同站点可用的 cookie。生产回滚最简单:移除业务 Ingress 的认证注解或 Traefik ForwardAuth middleware,保留 oauth2-proxy Deployment 以便排查,不要在事故中先删 Keycloak Client。需要完整的 Ingress / ForwardAuth 配置、验证命令和回滚步骤,可参考 Keycloak + oauth2-proxy 集成实战指南

Vault

Vault 用 JWT/OIDC Auth Method,让 Keycloak 签发的 token 直接换取 Vault token,实现云原生密钥获取:

vault auth enable oidc
vault write auth/oidc/config \
  oidc_discovery_url="https://kc.example.com/realms/myrealm" \
  client_id="vault" \
  client_secret="SECRET" \
  default_role="engineer"

vault write auth/oidc/role/engineer \
  bound_audiences="vault" \
  allowed_redirect_uris="https://vault.example.com/ui/vault/auth/oidc/oidc/callback" \
  user_claim="sub" \
  groups_claim="groups" \
  policies="default,engineer" \
  ttl="1h"

配合外部组映射(identity/group)即可按 Keycloak 角色决定 Vault 权限。

Harbor

Harbor 原生支持 OIDC(Configuration → Authentication → OIDC):

字段
OIDC Provider NameKeycloak
OIDC Endpointhttps://kc.example.com/realms/myrealm
OIDC Client IDharbor
OIDC Client SecretSECRET
OIDC Scopeopenid,profile,email,groups
Group Claim Namegroups

要点:开启 Verify Certificate;用 groups claim 映射 Harbor 项目成员角色,实现按组授权镜像仓库。

MinIO

MinIO 支持 OIDC(mc 或环境变量):

mc admin config set myminio identity_openid \
  config_url="https://kc.example.com/realms/myrealm/.well-known/openid-configuration" \
  client_id="minio" \
  client_secret="SECRET" \
  claim_name="policy" \
  claim_prefix="" \
  scopes="openid,profile"
mc admin service restart myminio

通过自定义 policy claim(Protocol Mapper 输出)或 Keycloak 角色到 MinIO policy 的映射,控制对 bucket 的访问。

Nextcloud

Nextcloud 用 Social login / OIDC 插件

'oidc_login_provider' => [
  'clientId'     => 'nextcloud',
  'clientSecret'  => 'SECRET',
  'oidcIssuer'   => 'https://kc.example.com/realms/myrealm',
  'authEndpoint' => 'https://kc.example.com/realms/myrealm/protocol/openid-connect/auth',
  'tokenEndpoint'=> 'https://kc.example.com/realms/myrealm/protocol/openid-connect/token',
  'userInfoEndpoint' => 'https://kc.example.com/realms/myrealm/protocol/openid-connect/userinfo',
],
'oidc_login_auto_redirect' => true,
'oidc_login_button_text'  => 'Keycloak 登录',

通用接入步骤速查

不论软件用原生还是 oauth2-proxy,通用五步:

  1. 在 Keycloak 创建 confidential Client,开启 Client AuthenticationAuthorization Code + PKCE
  2. 精确配置 Valid redirect URI(含回调路径),避免通配。
  3. 在 Client 的 Protocol Mappersemailprofilegroups 等所需 claim。
  4. 软件侧填 Issuer / Auth / Token / UserInfo / 客户端凭证。
  5. 联调一次登录流程,确认回调、token、用户属性、角色映射正确。

小结

Keycloak 与开源生态的集成主要分三条路:原生 OIDC(Grafana、GitLab、Harbor、Vault、MinIO、Nextcloud 等)、前置 OAuth2 Proxy(任意 Web 服务、K8s Ingress),以及 LDAP/AD 用户联邦(保留现有目录服务作为权威用户源)。掌握这三条路、五步通用流程与 Protocol Mapper 的 claim 映射,即可把一整套开源软件和目录服务统一纳入 SSO。集成中遇到具体报错,参见 常见问题排查。关于 LDAP/AD 联邦的完整配置步骤,参见 Keycloak LDAP / AD 用户联邦实战指南