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 缓存或缩短刷新周期
演练练习#
- 使用 Keycloak 创建 ops realm 和 ops-portal client,配置回调地址并完成一次 Web 登录。
- 创建 ops-agent client(client credentials),获取 access_token 调用一个受保护 API。
- 将 access_token 的 exp 改为已过期值,验证应用侧拒绝并输出合理日志。
- 模拟 IP 变更与设备指纹异常,触发二次验证或冻结策略。
关键落地建议#
- 先统一身份源与账号治理,再逐步接入系统实现 SSO。
- 制定令牌与会话标准、SDK 与统一中间件,降低系统接入成本。
- 对接 Jenkins、Prometheus、K8s、Git 等统一登录,并统一审计链路。
- 持续进行渗透测试与风控策略优化,确保认证链路安全可用。