19.8.3 认证与单点登录(SSO)设计

认证与单点登录(SSO)设计的目标是在保证安全性的前提下,实现统一入口、统一身份、统一审计与统一策略。运维平台需覆盖人机交互(Web/CLI)、机器访问(API/SDK/Agent)以及第三方系统对接的认证需求,并兼顾跨域、多环境与高可用。

文章图片

核心原则:统一身份源与账号治理;最小暴露与分层认证;MFA 与风险感知;可审计与可追溯;高可用与容灾;优先采用标准协议(OIDC/OAuth2)。

协议选型与场景:
- SSO:OAuth2.0 + OIDC(统一登录与用户信息)
- 服务对服务:OAuth2 Client Credentials 或 mTLS
- 兼容历史系统:SAML2/CAS
- API 访问:JWT/PASETO,明确签名算法与过期策略

认证流程(简化):
1. 用户访问业务系统触发重定向至 IdP。
2. IdP 完成密码 + MFA 校验与风险评估。
3. 认证服务签发访问令牌与刷新令牌。
4. 业务系统校验令牌签名、有效期、aud、scope/roles。
5. 刷新令牌与会话续期遵循最短有效期与滑动窗口。

参考实现:Keycloak + Nginx 反向代理#

安装与启动(Docker)#

# 1) 启动 Keycloak(开发/测试示例,生产建议使用外部数据库)
docker run -d --name keycloak \
  -p 8080:8080 \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=Admin@123 \
  quay.io/keycloak/keycloak:23.0 \
  start-dev

# 预期:访问 http://127.0.0.1:8080 可打开 Keycloak 控制台

创建 Realm 与 Client(命令示例)#

# 进入容器并使用 kcadm.sh
docker exec -it keycloak /opt/keycloak/bin/kcadm.sh config credentials \
  --server http://127.0.0.1:8080 --realm master \
  --user admin --password Admin@123

# 创建 realm
docker exec -it keycloak /opt/keycloak/bin/kcadm.sh create realms \
  -s realm=ops -s enabled=true

# 创建 OIDC client(运维平台 Web)
docker exec -it keycloak /opt/keycloak/bin/kcadm.sh create clients \
  -r ops -s clientId=ops-portal \
  -s publicClient=true -s 'redirectUris=["https://ops.example.com/*"]'

# 预期:Keycloak 中 ops realm 下出现 ops-portal Client

Nginx 统一入口(示例反向代理)#

# /etc/nginx/conf.d/ops-portal.conf
server {
  listen 443 ssl;
  server_name ops.example.com;

  ssl_certificate     /etc/nginx/certs/ops.crt;
  ssl_certificate_key /etc/nginx/certs/ops.key;

  location / {
    proxy_pass http://ops-portal:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

应用侧令牌校验(示例伪代码 + 关键字段)#

1) 读取 Authorization: Bearer <token>
2) 校验签名:使用 IdP 提供的 JWKs
3) 校验 exp、iss、aud
4) 解析 scope/roles,映射本地 RBAC

CLI/Agent 获取短期令牌(Client Credentials)#

# 通过 client_id/client_secret 获取 access_token(示例)
TOKEN=$(curl -s -X POST \
  http://127.0.0.1:8080/realms/ops/protocol/openid-connect/token \
  -d "grant_type=client_credentials" \
  -d "client_id=ops-agent" \
  -d "client_secret=agent-secret" | jq -r .access_token)

# 使用令牌访问 API
curl -H "Authorization: Bearer $TOKEN" https://ops.example.com/api/v1/nodes

令牌与会话安全配置示例#

{
  "access_token_ttl": "15m",
  "refresh_token_ttl": "14d",
  "signing_alg": "RS256",
  "claims_min": ["sub","aud","iss","exp","roles","tenant_id"],
  "rotate_keys_days": 30
}

风险与 MFA 策略示例#

- 高危操作:生产发布、权限提升、数据导出
- 强制 MFA:TOTP/硬件Key/短信二次验证
- 风险因子:设备指纹、IP 信誉、地理位置、访问时段
- 异常策略:连续失败 >= 5 次冻结 30 分钟

令牌验证关键命令(JWKs 与 JWT 解析)#

# 1) 获取 JWKs
curl -s http://127.0.0.1:8080/realms/ops/protocol/openid-connect/certs

# 2) 解码 JWT(不验签,仅查看声明)
echo "$TOKEN" | awk -F. '{print $2}' | base64 -d | jq

常见问题与排错#

# 1) 回调地址不匹配导致 400/401
# 检查 Client 的 redirectUris 是否包含实际回调地址
# Keycloak -> Clients -> ops-portal -> Valid Redirect URIs

# 2) 令牌无效/过期
# 查看 exp,检查服务器时间(NTP)
timedatectl status

# 3) JWKS 缓存未更新导致验签失败
# 清理网关/应用的 JWKS 缓存或缩短刷新周期

演练练习#

  1. 使用 Keycloak 创建 ops realm 和 ops-portal client,配置回调地址并完成一次 Web 登录。
  2. 创建 ops-agent client(client credentials),获取 access_token 调用一个受保护 API。
  3. 将 access_token 的 exp 改为已过期值,验证应用侧拒绝并输出合理日志。
  4. 模拟 IP 变更与设备指纹异常,触发二次验证或冻结策略。

关键落地建议#

  • 先统一身份源与账号治理,再逐步接入系统实现 SSO。
  • 制定令牌与会话标准、SDK 与统一中间件,降低系统接入成本。
  • 对接 Jenkins、Prometheus、K8s、Git 等统一登录,并统一审计链路。
  • 持续进行渗透测试与风控策略优化,确保认证链路安全可用。