aws-actions/configure-aws-credentialsがOIDCプロバイダを介したSwitchRoleに対応していたので実装を辿ってみた

OIDCプロバイダを介したSwitchRoleの紹介記事をみて「いつか実際に使えるようになるといいなぁ」と思っていたところ、いつのまにか aws-actions/configure-aws-credentials に実装されてました。使い方はさておき、気になった実装について追っかけてみました。
2021.09.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

先日注目が集まった、OIDCプロバイダを用いることによって実現した AWS Credentials 不要でのSwitchRole は記憶に新しいところです。ただ、正直どうやって業務利用すべきかというところでした。肝のWebIdentityTokenの扱いに困ったわけです。

そして先程GitHub ActionsでAWSを使う際に必須とも言える aws-actions/configure-aws-credentials のREADMEを見ていたところ、OIDCを用いたSwitchRoleの仕組みが追加されていました。

特にニュースとして上がっているわけではなく、いつの間に、といった感想です。同様の速報記事は多数上がるだろうと想定の元、ではどういった形で入っているのか辿ってみました。

Actionsへの変更詳細

追加は以下のPRによるものです。

WebIdentityTokenについて、特にリクエストしているコードがありません。aws-actions/configure-aws-credentials ではこのパラメータを他のライブラリから取得しています。 actions/toolkit です。

actions/toolkitからのToken取得

AssumeRoleWithWebIdentityは以下のパラメータを揃えてリクエストを行う必要があります。

  • DurationSeconds
  • Policy
  • PolicyArns.member.N
  • ProviderId
  • RoleArn
  • RoleSessionName
  • WebIdentityToken

他のパラメータを見る限り、やはりネックはWebIdentityToken 1点。実際の取得過程を見ていきます。

先ず ACTIONS_ID_TOKEN_REQUEST_TOKENACTIONS_ID_TOKEN_REQUEST_URL がGitHub Actions実行時に環境変数へセットされているようですが、この2つの環境変数に関した公式ドキュメントは見当たらず。

  private static getRequestToken(): string {
    const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN']
    if (!token) {
      throw new Error(
        'Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable'
      )
    }
    return token
  }


  private static getIDTokenUrl(): string {
    const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL']
    if (!runtimeUrl) {
      throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable')
    }
    return runtimeUrl
  }

次に ACTIONS_ID_TOKEN_REQUEST_TOKEN を Header にセットしつつ、ACTIONS_ID_TOKEN_REQUEST_URL へリクエスト。

    return new HttpClient(
      'actions/oidc-client',
      [new BearerCredentialHandler(OidcClient.getRequestToken())],
      requestOptions
    )

返ってきたtokenが WebIdentityToken として利用されることになります。

  static async getIDToken(audience?: string): Promise<string> {
    try {
      // New ID Token is requested from action service
      let id_token_url: string = OidcClient.getIDTokenUrl()
      if (audience) {
        const encodedAudience = encodeURIComponent(audience)
        id_token_url = `${id_token_url}&audience=${encodedAudience}`
      }


      debug(`ID token url is ${id_token_url}`)


      const id_token = await OidcClient.getCall(id_token_url)
      setSecret(id_token)
      return id_token
    } catch (error) {
      throw new Error(`Error message: ${error.message}`)
    }
  }

実装としては動くのですが、肝心の2つの環境変数については特にコメント等もないという状態でした。

あとがき

OIDCプロバイダを使った、認証不要になるという点で驚かせてくれた以下記事ですが、問題は $ACTIONS_ID_TOKEN_REQUEST_TOKEN$ACTIONS_ID_TOKEN_REQUEST_URL の2点が不明瞭であること。

既にMarketPlace上ではOIDCプロバイダを前提とした認証でサンプルも掲載されています。正直もやっとしますが、動作に問題がなければ差し替えておくことでアクセスキー漏洩の心配も減りそうです。