---
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))
}
运行治理
- 令牌仅在步骤内有效,执行完成即销毁;缓存最短并启用重放防护。
- 审计字段包含
iss、aud、kid、jti与时间窗口;异常触发强制撤销。

发表评论 取消回复