OIDC と bot ユーザー + アクセスキー

OIDC の利点は長期認証情報の排除です(デフォルトで一時認証情報の有効期限は 1 時間です)。
さらに使用元も制限できます(例えば CircleCI の特定プロジェクトのブランチ etc )。

bot ユーザー + アクセスキーの問題点

問題 内容
長期認証情報 アクセスキーは手動で削除するまで有効。漏洩しても気づきにくい
漏洩リスク CircleCI の環境変数に保存 → CircleCI が侵害されたら即アウト
ローテーション負担 定期的に手動で交換 + CircleCI の環境変数も更新が必要
使用元の無制限 漏洩したキーは世界中どこからでも使える

OIDC が解決する点

OIDC では CircleCI がジョブ実行ごとに JWT トークン(一時的な身元証明書) を発行し、AWS STS ( AWS Security Token Service )がそれと引き換えに 有効期限付きの一時認証情報 を返します。

CircleCI Job
    |
    | (1) JWT トークン発行( CircleCI が署名)
    |
    ▼
AWS STS ( AssumeRoleWithWebIdentity )
    |
    | (2) JWT を検証 → 一時認証情報を発行(有効期限: 1 時間等)
    ▼
AWS リソース操作
    |
    | (3) 有効期限切れで自動失効
    |
    ▼
(終了)
比較 bot ユーザー + アクセスキー OIDC
認証情報の寿命 永続(手動削除まで) 短期(自動失効)
CircleCI に保存するシークレット あり(アクセスキー) なし
漏洩時の影響 失効させるまで悪用され続ける すぐ期限切れ
使用元の制限 不可 可(特定の org/project/branch のみ許可)
ローテーション 手動で必要 不要

条件の絞り込み例(trust policy の Condition):

"Condition": {
  "StringLike": {
    "oidc.circleci.com/org/xxx:sub": "org/xxx/project/yyy/user/*"
  }
}

Appendix: JWT トークン

JWT とは

JWT(JSON Web Token)は、2者間で情報を安全にやり取りするための 署名付き JSON です。OIDC では「私は CircleCI の特定のジョブです」という身元を証明するために使います。

構造

JWT は . で区切られた 3 つの部分から構成されます。

eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL29pZGMuY2lyY2xlY2kuY29tL29yZy94eHgifQ.signature
      ▲                          ▲                                                      ▲
   Header                     Payload                                              Signature
部分 内容
Header 署名アルゴリズム(例:RS256)とトークン種別
Payload クレーム(誰が・どこから・いつまで有効か)
Signature Header + Payload を秘密鍵で署名したもの

各部分は Base64URL エンコードされているだけなので、デコードすれば中身を読めます(ただし改ざんは署名で検出できます)。

Payload のクレーム例(CircleCI)

{
  "iss": "https://oidc.circleci.com/org/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "sub": "org/xxxxxxxx/project/yyyyyyyy/user/zzzzzzzz",
  "aud": "sts.amazonaws.com",
  "exp": 1713800000,
  "iat": 1713796400
}
クレーム 意味
iss(Issuer) トークンの発行者(CircleCI の OIDC エンドポイント)
sub(Subject) トークンの主体(どの org/project/user か)
aud(Audience) トークンの受取先(AWS STS)
exp(Expiration) 有効期限(Unix タイムスタンプ)
iat(Issued At) 発行日時

AWS が JWT を信頼できる理由

AWS は事前に登録された CircleCI の OIDC プロバイダー公開鍵 で Signature を検証します。秘密鍵は CircleCI だけが持っているため、署名が正しければ「本物の CircleCI が発行したトークン」と確認できます。

CircleCI(秘密鍵で署名)→ JWT → AWS STS(公開鍵で検証)→ OK → 一時認証情報を発行

trust policy の Condition は、この Payload のクレーム値を使って「どの CircleCI プロジェクトからの実行か」を絞り込んでいます。