public memo

エンジニア向け小ネタ書き溜め用。公開日記だけど親切な文章とは程遠いかもしれない。

GitHub ActionsからAWS利用時に永続的クレデンシャル情報を渡さないようにする

2022-02-14 by MasakiMisawa
Tweet
このエントリーをはてなブックマークに追加
Pocket
LINEで送る

GitHub ActionsのCI実行時に各種AWSサービスにアクセスする為に使用していたIAM Userのクレデンシャル情報を廃止して、OpenID Connect経由でIAM Roleを使用する方式で永続的なクレデンシャル情報を渡さないように変更しました。
今回は、変更手順をTerraformのコードサンプルを交えてまとめてみます。

変更前

これまでは、GitHub ActionsのCI実行環境から各種AWSサービスを利用する際は、非推奨な方法ではあるもののCI実行用に作成したIAM Userのクレデンシャル情報を使用してアクセスしていました。
AWSサービスのアクセス制御はIAMロールの一時認証情報を利用する方法が推奨されていますが、AWS環境外からアクセスする場合は実行環境にIAMロールを参照する為のインスタンスプロファイルが設定できない為です。

【変更前: GitHub Actionsから各種AWSサービスにアクセス】

何が課題だったか

この方式でもGitHub ActionsのCI実行環境から各種AWSサービスへのアクセスは可能でしたが、主に以下二つの問題を抱えている状態でした。

1. クレデンシャル情報漏洩時のセキュリティリスクが大きい

IAM Userのクレデンシャル情報はアクセスキーとシークレットアクセスキーの二つの文字列である事に加えて、開発者が破棄して新しいクレデンシャル情報にローテーションしない限り、文字列は有効であり続けます。
これはIAM Userの性質上仕方のない事ではありますが、万が一クレデンシャル情報の文字列が外部に漏洩してしまった場合のリスクが非常に高い為、AWSでも非推奨とされています。

2. キーローテーション時のオペレーションコストがかかる

上記リスク軽減の為に数ヶ月毎の頻度でクレデンシャル情報のキーローテを行う事になりますが、この作業は手動運用でしか対応できず毎回対応するのは面倒です。

IAM Userそれぞれに対して、

  1. クレデンシャル情報の新規発行
  2. 発行したクレデンシャル情報で各種CI環境などに登録されている情報を更新
  3. 更新後の情報で正しくアクセスできるかの動作確認
  4. 不要になった古いクレデンシャル情報を削除

をユーザ数分対応する必要がある為、結構なオペレーションコストがかかります。

どう解消したか

仕方ないとは分かりつつも何とかならないかなぁと思っていたところ、IAM Userのクレデンシャル情報を使わないでもGitHub ActionsからAWSサービスにアクセスできるようになった!という嬉しいニュースが昨年秋に飛び込んできました。

クラスメソッド発「やってみた」系技術メディア | DevelopersIO
 
111 Tweets
186 Users
81 Pockets
GitHub ActionsでAWSの永続的なクレデンシャルを渡すことなくIAM Roleが利用できる...
https://dev.classmethod.jp/articles/github-actions-without-permanent-credential/
アクセスキー、撲滅してますか? ナカヤマです。 目黒方面より、以下のような福音が聞こえてきました。 何がどのくらい最高かと言いますと! GitHub Actions に AWS クレデンシャルを直接渡さずに IAM ロー …

この時点ではまだ非公式な状態でしたが、それから約一ヶ月後にGitHub公式から正式にサポートがアナウンスされました。

The GitHub Blog
 
55 Pockets
GitHub Actions: Secure cloud deployments with OpenID Connect | GitHub Changelog
https://github.blog/changelog/2021-10-27-github-actions-secure-cloud-deployments-with-openid-connect
GitHub Actions: Secure cloud deployments with OpenID Connect

今回サポートされたOpenID Connectの認証方法は、

  1. aws_li 信頼関係を登録したGitHubリポジトリ用のIAM Roleを用意
  2. github_li OIDCプロバイダで認証トークンを発行してAWSサービスへのアクセスを許可する一時アクセストークンを要求
  3. aws_li 信頼関係を登録済のリポジトリから認証トークン付きでリクエストがあった場合に、AWSサービスへのアクセスを許可する一時トークンを発行
  4. github_li 一時トークンを使用して許可されたサービスにアクセス

という流れです。

【OpenID Connectを利用した認証(公式から引用)】

クラウドプロバイダ側で信頼元を登録して一時トークンを発行する形に変更されたことでIAM Userが不要になり、クレデンシャル情報の漏洩リスクやキーローテーションを行うオペレーションコストの課題が解決されていますね。

変更手順

という事で、新しい認証方法へ変更していきます。

0. 変更前の状態を再現

変更の流れを書いていく上での、変更前の状態を再現する下準備です。
対象リポジトリとアクセスしたいAWSリソースが既に存在する場合は、この手順はSKIPしてください。

  • 対象GitHubリポジトリ: MasakiMisawa/ci-cd-test
  • 今回の流れ説明では、ci-cd-testというリポジトリを使用して進めます。

    このリポジトリのGitHub Secretsに、別途用意するAWSリソースへのアクセスが許可されたIAM UserのAWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEYの二つが登録されています。

  • アクセス先AWSサービス: S3/masakimisawa-ci-cd-test
  • CI環境からアクセスする先のAWSリソースは、S3のmasakimisawa-ci-cd-testというバケットを用意しました。
    もちろん、プライベートバケットなのでアクセスが許可されたIAMポリシーがアタッチされた状態でないとアクセスが拒否されます。

  • GitHub Actionsで実行するワークフロー: test-workflow
  • CI実行用という事で、今回はdevelopブランチへのPull Request作成時にトリガーされるtest-workflowというワークフローを実行させます。

    test.yml before
    YAML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    name: test-workflow
    on:
      pull_request:
        branches:
          - develop
     
    jobs:
      TestS3Upload:
        name: S3 upload
        runs-on: ubuntu-latest
        steps:
          - name: Checkout
            uses: actions/checkout@v2
     
          - name: "Configure AWS credentials"
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ap-northeast-1
          - name: upload
            run: aws s3 cp ./README.md s3://masakimisawa-ci-cd-test/${{ github.head_ref }}/

    実開発時はCI環境のビルド結果成果物をS3にアップロードするなどもう少し長い処理になると思いますが、今回は作成したS3バケットへのアクセスが確認できれば十分だったので、リポジトリルートのREADME.mdファイルをPR作成元ブランチのパスにアップロードするだけの簡単な処理にしています。
    今回は記事の説明用ということで分かり易くする目的でS3バケット名を通常文字列にしていますが、実開発用リポジトリなどではGitHub Secretsの環境変数に置き換えてください。

    CI環境の環境変数でaws-access-key-idとaws-secret-access-keyを使用する為に、GitHub SecretsにIAM Userのクレデンシャル情報を登録していますね。
    この情報を削除した上でAWSサービスにアクセス可能にするのが今回の目的です。

1. OpenID Connect Providerの作成

準備ができたところで、OpenID Connect Providerから作成していきます。

open id connect provider
1
2
3
4
5
resource "aws_iam_openid_connect_provider" "github_oidc" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

OpenID Connect Providerのリソース作成はこれで終わりです。
サムプリントは、2022年1月にGitHub ActionsのID プロパイダのルート証明書が変更された影響で、それ以前に使用されていたサムプリントを使用しているとAWSの認証が通らなくなっているようなのでご注意ください。
サムプリントに「a031c46782e6e6c662c2c87c76da9aa62ccabd8e」の更新前の値が記載された情報が多く出回っているので、AWSの認証が通らない場合は最新の値に更新してみてください。

GitHub
 
10 Users
7 Pockets
OpenIDConnect provider's HTTPS certificate doesn't match configured...
https://github.com/aws-actions/configure-aws-credentials/issues/357
Hey, For the past hour or so I’ve been getting this error while using this action: Error: OpenIDConnect provider's HTTPS certificate doesn't match configured thumbprint I’ve checked the thu...

また、2022年2月現在では記載した値がGitHub ActionsのID プロバイダのルート証明書の最新の値になっていますが、中間証明書の有効期限的に今後も定期的にサムプリントの値は更新されていく事が予想される為、認証が通らなくなった場合は公式ドキュメントを参考にサムプリントの値を取得して更新してください。

docs.aws.amazon.com
 
1 User
4 Pockets
OpenID Connect ID プロバイダーのサムプリントの取得 - AWS Identity and Access ...
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html
IAM によって自動的に取得された証明書が適切なものであることを確認するために、OIDC ID プロバイダーのサーバー証明書のサムプリント (署名) を手動で取得します。

最新のサムプリントの値は動的に取得する事も可能なので、cronトリガーの日時実行処理などで最新の値を取得して更新していくと運用が楽になりそうですね。

ZSH
1
2
openssl s_client -servername token.actions.githubusercontent.com -showcerts -connect token.actions.githubusercontent.com:443 < /dev/null 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sed "0,/-END CERTIFICATE-/d" > certificate.crt
openssl x509 -in certificate.crt -fingerprint -noout | cut -f2 -d'=' | tr -d ':' | tr '[:upper:]' '[:lower:]'

尚、今回は2022/02時点での最新の値を固定文字列で登録する形で進めます。

2. IAM Roleの作成

続いて、信頼関係を登録してAWSサービスへのアクセスの一時トークンを発行するIAM Roleを作成していきます。
作成するリソース量が少しだけ増えますが、IAM Roleを作成するコード例です。

oidc iam role
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
data "aws_iam_policy_document" "principal_policy" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]
 
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github_oidc.arn]
    }
 
    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = ["repo:MasakiMisawa/ci-cd-test:*"]
    }
  }
}
 
resource "aws_iam_role" "oidc_test_iam_role" {
  name               = "GitHubActionsOIDCTestRole"
  assume_role_policy = data.aws_iam_policy_document.principal_policy.json
}
 
data "aws_iam_policy_document" "allowed_action_policy" {
  statement {
    effect = "Allow"
    actions = [
      "s3:ListBucket",
      "s3:GetObject",
      "s3:PutObject"
    ]
    resources = [
      "arn:aws:s3:::masakimisawa-ci-cd-test",
      "arn:aws:s3:::masakimisawa-ci-cd-test/*"
    ]
  }
}
 
resource "aws_iam_policy" "oidc_test_iam_policy" {
  name   = "GitHubActionsOIDCTestPolicy"
  policy = data.aws_iam_policy_document.allowed_action_policy.json
}
 
resource "aws_iam_role_policy_attachment" "oidc_test_iam_role_policy_attachment" {
  role       = aws_iam_role.oidc_test_iam_role.name
  policy_arn = aws_iam_policy.oidc_test_iam_policy.arn
}

IAM Roleにアタッチするプリンシパルのポリシーで、conditionの条件で信頼関係を登録するリポジトリを絞った状態でGitHub ActionsのID プロバイダに対してSTS.AssumeRoleWithWebIdentityの実行用の一時トークン発行を許可します。
今回はci-cd-testリポジトリの全ブランチに一時トークンの発行を許可しましたが、デプロイ時はmainブランチのみを許可などリポジトリ名の後の「:*」の部分で条件を指定すれば、更に細かく設定することも可能です。

一時トークンの中身は、作成したS3のmasakimisawa-ci-cd-testバケットに対してcpコマンドを実行する為の最小権限を与えています。

3. GitHub Actions Workflowの修正

AWS側の準備が整ったので、最後にGitHub Actions側で実行するCIのワークフロー定義を変更します。
IAM Userのクレデンシャル情報を環境変数に使用していた部分を、IAM RoleのロールArnを指定する形に変更する作業です。

test.yml after
YAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
name: test-workflow
on:
  pull_request:
    branches:
      - develop
 
permissions:
  id-token: write
  contents: read
 
jobs:
  TestS3Upload:
    name: S3 upload
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
 
      - name: "Configure AWS credentials"
        uses: aws-actions/configure-aws-credentials@master
        with:
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GitHubActionsOIDCTestRole
          aws-region: ap-northeast-1
      - name: upload
        run: aws s3 cp ./README.md s3://masakimisawa-ci-cd-test/${{ github.head_ref }}/

secretsから取得しているAWS_ACCOUNT_IDの部分は、自身のAWSアカウントIDに置き換えてください。

変更点は以下になります。

  1. Configure AWS credentials欄からクレデンシャル情報を削除
  2. 今回やりたかった事で、AWS_ACCESS_LEY_IDとAWS_SECRET_ACCESS_KEYの二つを削除しています。

  3. Configure AWS credentials欄にrole-to-assume情報を追加
  4. 先程作成したGitHubActionsOIDCTestRoleのIAM Role ARNです。
    アカウントIDだけSecretsに登録するも良し、ARN毎登録するも良しですね。

  5. permissions欄を追加
  6. 一時トークン引き受け用に、IDトークンの書き込み権限が必要になります。
    また、permissionsを明示的に書くとデフォルトで有効な権限(今回はactionsのcheckoutに必要な contents: read)も無効になってしまうようなので、必要な権限を明示的に追記します。

  7. aws-actions/configure-aws-credentialsをv1からmasterに変更
  8. 自分はこれが抜けていて結構ハマってしまいました。。。

    GitHub
    Create new release? · Issue #302 · aws-actions/configure-aws-credentials
    https://github.com/aws-actions/configure-aws-credentials/issues/302
    Hi, Really excited to see the OIDC support 🎉 . It looks like this action is also recommended by GitHub themselves, which is great because it means we can deprecate one of our repositories that achi...

4. 動作確認

AWS側とGitHub Actions側両方の作業が完了した為、正常にアクセス可能になっているかを確認します。

OpenID Connectを信頼元に登録したIAM Roleの一時権限を使用してアクセスが無事に成功しています。

5. お片づけ

これでIAM Userのクレデンシャル情報は不要になったので、これまでの感謝の気持ちを込めつつお別れします。

まずは、GitHubリポジトリに登録してある二つのSecretsのキーを削除。

最後に、AWS側でIAM Userごと削除。

無事にクレデンシャル情報を消せましたという事で、今回は終わりです。
ここまで読んでいただきありがとうございました!

Tweet
このエントリーをはてなブックマークに追加
Pocket
LINEで送る

カテゴリー: AWS, Git, GitHub, GitHub Actions, IAM, OpenId Connect, Terraform タグ: AWS, GitHub Actions, IAM Role, OpenId Connect, Terraform

profile

profile_img Web系のソフトウェアエンジニアです。
野球観戦(横浜DeNAベイスターズ)、格闘ゲーム、カメラ、ランニング、愛犬、インテリア、美味しいものの食べ歩き、などなどが好き。

  • twitter MasakiMisawa
  • facebook MisawaMasaki
  • github MasakiMisawa
  • instagram masakimisawa
  • follow us in feedly

search

recent entry

  • M1 MacでAppleシリコンとIntelプロセッサのバイナリ管理を分離して共存させる
  • M1 MacでtfenvからTerraform1.0.2未満のダウンロードに失敗する問題を無理矢理解決する
  • GitHub ActionsからAWS利用時に永続的クレデンシャル情報を渡さないようにする
  • TerraformでAuroraのエンジンバージョンアップグレードをする時は、対象リソースをクラスターだけに絞る
  • CloudWatch Logsに出力されたエラーログ本文のSlackへの転送

category

  • AWS (17)
    • ACM (1)
    • AWS CLI (1)
    • Chatbot (2)
    • CloudWatchAlarm (1)
    • CloudWatchLogs (1)
    • CodeBuild (3)
    • DynamoDB (1)
    • IAM (1)
    • Kinesis (2)
    • Lambda (5)
    • OpenId Connect (1)
    • RDS (1)
    • S3 (2)
    • SNS (2)
    • SSM (2)
    • STS (1)
  • CI (2)
  • GCP (1)
    • PageSpeedInsights (1)
  • Git (3)
    • GitHub (2)
      • GitHub Actions (1)
  • M1 Mac (2)
  • Python (2)
  • Redis (1)
  • selenium (1)
  • Slack (3)
  • Terraform (3)
  • その他 (1)

archive

  • 2022年2月 (3)
  • 2021年1月 (1)
  • 2020年12月 (1)
  • 2020年11月 (1)
  • 2020年9月 (2)
  • 2020年8月 (1)
  • 2020年7月 (1)
  • 2020年6月 (1)
  • 2020年5月 (2)
  • 2020年4月 (1)
  • 2020年3月 (1)
  • 2020年1月 (1)
  • 2019年1月 (1)
  • 2017年12月 (1)
  • 2017年9月 (1)
  • 2017年8月 (1)
  • 2017年7月 (1)
  • 2017年2月 (1)
  • 2016年10月 (1)

tag cloud

ACM Aurora AWS AWS CLI Billing CI CloudWatchAlarm CloudWatch Logs CodeBuild Code Format Docker DynamoDB EC2 env find firehose Git GitHub GitHub Actions Homebrew husky IAM Role Java kinesis KinesisFirehose Lambda lint-staged M1 Mac Node.js OpenId Connect PHP Python RDS Redis RI S3 Selenium Slack SNS SSM Terraform tfenv セッションマネジャー リモートワーク 生産性

Copyright © 2025 public memo.