---

title: CI/CD密钥最小化与短期凭证治理(OIDC-Federation-工作负载身份)最佳实践

keywords:

  • OIDC
  • 联邦
  • 短期凭证
  • 工作负载身份
  • 最小权限
  • 轮换

description: 通过 OIDC 联邦与短期凭证替代长期密钥,结合最小权限与时间窗口治理,降低CI/CD密钥泄露风险。

categories:

  • 文章资讯
  • 技术教程

---

核心要点

  • 使用工作负载身份与 OIDC 获取短期令牌;令牌作用域最小化并设定严格过期。
  • 禁止在仓库存放长期密钥;必要时采用按需获取与即时失效策略。
  • 对令牌的发行方、受众与时间窗口进行严格校验并记录审计。

实现示例

type Jwt = { header: { alg: string; kid?: string }; payload: { iss: string; aud: string; exp: number; nbf?: number; iat?: number; jti?: string } ; sig: string }

function within(created: number, expires: number, now: number, leewaySec: number): boolean {
  if (expires <= created) return false
  return now + leewaySec * 1000 >= created && now - leewaySec * 1000 <= expires
}

function validateOidcToken(jwt: Jwt, expected: { iss: string; aud: string; maxTtlSec: number }): { ok: boolean; errors: string[] } {
  const errors: string[] = []
  if (jwt.header.alg !== 'RS256') errors.push('alg')
  if (jwt.payload.iss !== expected.iss) errors.push('iss')
  if (jwt.payload.aud !== expected.aud) errors.push('aud')
  const now = Date.now()
  const iat = (jwt.payload.iat ?? Math.floor(now / 1000)) * 1000
  const exp = jwt.payload.exp * 1000
  if (!within(iat, exp, now, 60)) errors.push('time-window')
  if (exp - iat > expected.maxTtlSec * 1000) errors.push('ttl')
  return { ok: errors.length === 0, errors }
}

async function verifyJwtSig(jwt: Jwt, jwk: JsonWebKey): Promise<boolean> {
  const base = Buffer.from(JSON.stringify(jwt.header)).toString('base64url') + '.' + Buffer.from(JSON.stringify(jwt.payload)).toString('base64url')
  const key = await crypto.subtle.importKey('jwk', jwk, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['verify'])
  return crypto.subtle.verify({ name: 'RSASSA-PKCS1-v1_5' }, key, Buffer.from(jwt.sig, 'base64url'), Buffer.from(base))
}

运行治理

  • 令牌仅在步骤内有效,执行完成即销毁;缓存最短并启用重放防护。
  • 审计字段包含 issaudkidjti 与时间窗口;异常触发强制撤销。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部