👍

Terraform だけを使って GitHub Actions OIDC ID プロパイダの thumbprint を計算する方法

2022/01/13に公開3

GitHub Actions が提供する ID プロパイダのルート証明書が変更されて、OIDC を使った AWS への認証が通らなくなるという現象が起こりました。

https://github.com/aws-actions/configure-aws-credentials/issues/357

ドキュメントや多くのブログでは AWS 側の ID プロパイダに渡す thumbprint として固定値 a031c46782e6e6c662c2c87c76da9aa62ccabd8e が指定されていたので、新しい thumbprint を計算して更新する対応を迫られた方が多いのではないかと思います。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html

計算自体は上記公式ドキュメントに載っている通りに行えば問題ありませんが、せっかくなので Terraform だけを使って自動で thumbprint を取得する方法を紹介します。

なお、Terraform の実行結果は2022年1月13日時点のものです。

Terraform コード

data "http" "github_actions_openid_configuration" {
  url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration"
}

data "tls_certificate" "github_actions" {
  url = jsondecode(data.http.github_actions_openid_configuration.body).jwks_uri
}

resource "aws_iam_openid_connect_provider" "github_actions" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.github_actions.certificates[0].sha1_fingerprint]
}

ポイントとしては、tls_certificate という data source を使って証明書の取得 → thumbprint の計算まで実現しているところです。

Plan 結果

Terraform will perform the following actions:

  # aws_iam_openid_connect_provider.github_actions will be updated in-place
~ resource "aws_iam_openid_connect_provider" "github_actions" {
        id              = "arn:aws:iam::xxxxxxxxxxxx:oidc-provider/token.actions.githubusercontent.com"
        tags            = {}
      ~ thumbprint_list = [
          - "a031c46782e6e6c662c2c87c76da9aa62ccabd8e",
          + "6938fd4d98bab03faadb97b34396831e3780aea1",
        ]
        # (4 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Terraform 単体では Reconcile Loop が実現できないので thumbprint が自動で更新されることはない(= 何かしらのきっかけで terraform plan が走らないと差分が発覚しない)ですが、差分が出たタイミングで公式情報を確認することができる点はメリットと言えるかもしれません。

余談

公式ドキュメントでは openssl を使って一番下のルート証明書を取得していますが、Terraform だと data.tls_certificate.github_actions.certificates[0] とあるように配列の最初の要素を使っています。
これで確実にルート証明書を参照できると保証されているのか少し気になりましたが、特に問題ないようでした。

  • ドキュメント

    • with the root of the chain first. と書かれている
  • 実装

    • 証明書の配列を逆からループしている
      
        var certs []interface{}
        for i := len(state.PeerCertificates) - 1; i >= 0; i-- {
          certs = append(certs, parsePeerCertificate(state.PeerCertificates[i]))
        }
      
      

Discussion

ラグラグ

有力な記事ありがとうございます!公式ドキュメントに書いて欲しい限りです。

一つだけ改善点があるかもしれません。記事にも書いてあるように[0]だともしかして正しい証明書を参照できない可能性があると思います。GitHubの約束はどれかの証明書を使っていることで、全部有効だという約束ではないはずです。事実上ほとんどの場合大丈夫ですけどね。

でもSplat Expressionを使えば簡単に全部の証明証を参照できて、より安心です。

resource "aws_iam_openid_connect_provider" "github-oidc" {
  url = "https://token.actions.githubusercontent.com"
  client_id_list  = [sts.amazonaws.com"]
  thumbprint_list = data.tls_certificate.github_actions.certificates[*].sha1_fingerprint
}
Hirotaka MiyagiHirotaka Miyagi

記事とても参考になりました、ありがとうございました!
[0] として運用していたのですが、昨日AWSへの認証が通らなくなる問題が起き、サムプリントの変更が必要になりました。
関連するGitHub Issue: https://github.com/aws-actions/configure-aws-credentials/issues/357#issuecomment-1608522964

また本日GitHub Blogの方でもアナウンスが出ていました。

https://github.blog/changelog/2023-06-27-github-actions-update-on-oidc-integration-with-aws/

以下要約です。

  • 問題が起きているのは単一のサムプリントに固定している場合
  • GitHubは2つの中間証明書を持ち、どちらもGitHubのサーバーから返される可能性があるため、これは既知の挙動
  • 認証で問題が発生している既知のサムプリントは以下
    • 6938fd4d98bab03faadb97b34396831e3780aea1
    • 1c58a3a8518e8759bf075b76b750d4f2df264fcd

こちらの通り、単一のサムプリントだけを指定している場合に失敗する可能性があることは既知の挙動とのことなので、複数のサムプリントを設定しておく方が望ましそうです。

そのため、ラグさんの指摘いただいている Splat Expressionを利用する方法で解決できそうでした!参考になれば幸いです🙏

Hirotaka MiyagiHirotaka Miyagi

追記: https://token.actions.githubusercontent.com/.well-known/openid-configuration のリクエストを受けるのはおそらく2つのサーバーがあり、そのサーバーが返却するCA証明書は異なるかつランダムのようです。
そのためsplat expressionでも不十分で、planごとにサムプリントの差分が出てしまう問題がありました。

最終的には計算したサムプリントをハードコーディングすることにしました。経緯はこちらにチームメンバーが記載してくれています

https://tech.route06.co.jp/entry/2023/06/29/181610