GitHub Actions で OIDC を使用して AWS 認証ってどういう仕組みなん?

いやー久しぶりってレベルじゃないぐらいのレベルでブログ書いてます。

みなさんはGithub Actionsを使って、AWSにデプロイしたり、ファイルをアップロードしたりってしますかね?

その際にこんなこと思ったことありませんか?

これどういう仕組みでAWSとやりとりしてんだろ?

GitHub Actionsではロール名だけ教えればAWSと連携できちゃうなんて、そんなに簡単に認証できていいわけ!?

このように思ったのは私だけ?

というわけで、GitHub Actions で OIDC を使用したAWS認証の仕組みの謎を追っていきたいと思います🧭


ちょっとその前に

そもそもOIDCってなんだっけ?

OIDC(OpenID Connect)は OAuth 2.0 を拡張した仕様

OAuth 2.0は認可の仕組みで、認証に使われちゃったり問題(認可情報を認証としてつかってしまう問題)がでてきたので、ちゃんと認証の仕組みいれようで出てきた仕組み。(雑な説明ですいません)

OAuth 2.0がアクセストークンで認可をするのに対して、OIDCではIDトークンで認証を行う。

参考:
https://www.sakimura.org/2012/02/1487/

AWS AssumeRole(アシュームロール)ってよく聞くどあんま理解できてない

AssumeRole(アシュームロール)は簡単にいうと「一時的に他の役割を借りる」ことです。
特定の権限を持つIAMロールを引き受けることができます。

例えば、GitHub ActionsがAWSのS3とかLambdaとかにアクセスする権利が一時的に与えられます。

STSもよくきけどなんなん?

STSもよく聞くけど、これは「AWS Security Token Service」の略で、AWSのサービスの一つです。
STSは一時的なセキュリティ認証情報(トークン)を生成するために使用されます。これにより、ユーザーやアプリケーションは一時的なアクセス権を持つことができ、長期的なアクセスキーを使用する必要がなくなります。

OIDCトークンというものがある

OIDCトークンはJSON Web Token (JWT) 形式で発行されている。

今回の場合はGithub Actionsから払い出されるトークンで、ジョブ実行時の情報やレポジトリの情報も含まれる。

GithubActionsのOIDCトークンの仕様は以下
https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token


事前設定

1. AWS: Github Actionsのフィンガープリントを設定

フィンガープリント(TLS証明書の一意なハッシュ値)を事前に設定することで、AWSはGitHub以外の第三者が偽の公開鍵を提供しても、それが正当な公開鍵でないことを判別できます。これにより、公開鍵のなりすましを防ぎます。

公開鍵は後のOIDCトークンの署名(Github Actionsが署名したOIDCトークンかをチェック)に利用。

フィンガープリントの設定不要になってました。
https://github.com/aws-actions/configure-aws-credentials/issues/357#issuecomment-1626357333

信頼性の高いCAライブラリで通信を保護してるから改善されないってことでしょうかね。

2. AWS: クライアント IDの設定

AWS側で「クライアントID」を設定することで、GitHub ActionsからAWSに送られてくるトークンが、AWSで利用されることを確認します。
具体的には、GitHub Actionsが発行するOIDCトークンの「aud」(オーディエンス)クレームに「sts.amazonaws.com」というクライアントIDが含まれているかをAWSでチェックします。

3. AWS: Githubのレポジトリーを設定

GitHub ActionsがAWSリソースへアクセスできるようにするには、AWS側でどのGitHubリポジトリを信頼するか設定します。これにより、特定のリポジトリだけがAWSのリソースにアクセスできるように制限できます。

OIDCトークンに含まれるレポジトリ名が一致するか検証するのに利用

1
2
3
4
5
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref/heads/main"
}
}

4. Github Actions用のロール作成

GitHub ActionsがAWSリソースにアクセスするためのIAMロールを作成します。このロールには、GitHub Actionsが利用する特定のリソースや操作に対するアクセス権限を設定します。

例)S3バケットへの読み書き権限をあたえるなど


Github Actionsのジョブ実行

それでは、おおまかな流れを見ていきましょう!

1. GitHub Actions: OIDCトークンの署名

GitHub Actionsは、ジョブの実行中にOIDCトークンを取得します。このトークンはJWT形式で、ヘッダー、ペイロード、署名の3つの部分から構成されています。
GitHubは、トークンのヘッダーとペイロードを自身の秘密鍵で署名(ハッシュ化)して、署名部分を作成します。

2. GitHub Actions: OIDCトークンの送信

GitHub Actionsは、作成したOIDCトークン(ヘッダー、ペイロード、署名)をAWSに送信します。

3. AWS: 公開鍵の取得

AWSは、事前に設定されたTLS証明書のフィンガープリントを使用して、GitHubの公開鍵を取得します。この公開鍵は、GitHubのOIDCエンドポイントから取得したTLS証明書に含まれています。

信頼性の高いCAライブラリでtokens.actions.githubusercontent.comから安全に公開鍵を取得。

4. AWS: 署名の検証

AWSは、受信したOIDCトークンのヘッダーとペイロードをBase64URLデコードします。
AWSは、GitHubの公開鍵を使用して、トークンの署名を検証します。具体的には、トークンのヘッダーとペイロードを再度ハッシュ化し、その結果がトークンの署名部分と一致するかどうかを確認します。

[個人的重要ポイント]

公開鍵で検証できるのは、**GitHubしか秘密鍵を持っていないからこそ可能**な仕組みです。

5. AWS: トークンの検証

署名が一致する場合、AWSはトークンが改ざんされていないことを確認します。
AWSは、トークンのペイロードに含まれるクレーム(例:発行者、受信者、有効期限など)を検証します。

AWSは、トークンのaudクレームが「sts.amazonaws.com」であることを確認し、それがAWS用のトークンであることを認識します。また、token.actions.githubusercontent.com:subが事前に設定したリポジトリーと一致するかを確認し、許可されたリポジトリーからのトークンであることをチェックします。

6. AWS: 一時的な認証情報の発行

トークンが有効であることが確認された場合、AWS STSは指定されたIAMロールを引き受けるための一時的な認証情報(アクセスキー、シークレットアクセスキー、セッショントークン)を発行します。

7. GitHub Actions: 一時的な認証情報の使用

GitHub Actionsは、取得した一時的な認証情報を使用して、指定されたAWSリソースにアクセスします。

%%{init: {'theme':'forest', 'primaryColor': '#ff0000'}}%%
sequenceDiagram
    participant GitHub_Actions as GitHub Actions
    participant AWS as AWS
    participant AWS_Secrets as AWS STS

    GitHub_Actions->>GitHub_Actions: 1. OIDCトークンの署名\n(ヘッダー, ペイロード, 署名)
    GitHub_Actions->>AWS: 2. OIDCトークンの送信\n(ヘッダー, ペイロード, 署名)

    AWS->>GitHub_Actions: 3. 信頼性の高いCAライブラリで安全に公開鍵を取得

    AWS->>AWS: 4. OIDCトークンの署名の検証\n(Base64URLデコードして確認)
    AWS->>AWS: 5. トークンの検証\n(発行者, 受信者, 有効期限)

    AWS->>AWS_Secrets: 6. 一時的な認証情報の発行\n(IAMロールを引き受け)
    AWS_Secrets-->>GitHub_Actions: アクセスキー, シークレットアクセスキー, セッショントークン

    GitHub_Actions->>AWS: 7. 一時的な認証情報の使用\n(AWSリソースにアクセス)

という感じでOIDCの仕組みを使ってうまいことやりとりをしていましたというお話でした。

では👋

参考サイト