New Relicでは、インシデント対応やインフラストラクチャ管理の自動化をする Workflow Automation という機能を提供しています。この Workflow Automation の中には、JSON Web Token(JWT)を生成するための アクション が用意されています。

外部サービスの中には、APIを呼び出す前にJWTによる認証を求めるものがあります。GitHub App もそのひとつで、APIを利用するにはまずJWTを生成し、それを使って一時的なアクセストークンを取得する、という手順を踏む必要があります。

本記事では、この Auth JWT actions の Create a JSON Web Token を使って、GitHub App による Issue の作成を実際に行っていきます。それでは、順番にみていきましょう。

事前準備1: GitHub Appの作成とインストール

まず、Issueを作成するためのGitHub Appを用意します。下記のドキュメントを参考に、Issue の Read/Write 権限を持ったGitHub Appを作成します。

作成後、そのGitHub Appを任意のOrganizationまたはユーザーにインストールし、対象のリポジトリに対してIssueを作成できる状態にしておきます。 この後の手順で、以下の3つの値を利用しますので、あわせて控えておきます。

  1. App ID(GitHub Appの設定画面で確認できます)
  2. 秘密鍵(GitHub Appの設定画面から生成・ダウンロードします)
  3. Installation ID(Appをインストールした際のURL、またはGitHubのAPIから取得できます)

事前準備2: 秘密鍵をNew Relicのシークレットに登録

次に、JWT認証で必要となる秘密鍵をNew RelicのSecrets Management Serviceに登録します。 シークレットの登録に、今回はNerdGraphのsecretsManagementCreateSecretを使用します。 詳細については、下記のドキュメントを参照してください。

また、秘密鍵は1行の文字列としてシークレットに保存する必要があります。ダウンロードした秘密鍵ファイルには改行が含まれているため、改行を \n に置き換えて1行の文字列に整形してから保存します。

登録したシークレットは、ワークフロー内から ${{ :secrets:ネームスペース:キー名 }} の形式で参照します。

ワークフローの作成

事前準備が整ったら、ワークフローを作成していきます。今回は次の3つのアクションを順番につなげます。

  1. Auth JWT アクションでJWTを生成する
  2. HTTPアクションで、JWTから一時的なアクセストークンを発行する
  3. HTTPアクションで、そのトークンを使ってIssueを作成する

では、実際に1つずつ設定していきます。

1. JWTの生成(Auth JWT アクション)

まず、Auth JWT アクションでJWTを生成します。GitHub AppのJWTを生成する際に要求されるパラメータは、下記のドキュメントにあるとおり、alg(アルゴリズム)、iat(発行時刻)、exp(有効期限)、iss(発行者)です。

Workflow Automation の Auth JWT アクションでは、これらをUI上でそれぞれ指定できます。今回は次のように設定します。

  • algorithm: RS256 を指定します。GitHub App は RS256 での署名を要求します。
  • privateKey: 事前準備2で登録した秘密鍵を指定します。
    • 例。${{:secrets:github:nhashigithubappsecret}}
  • includeIssuedAt: true を指定します。これによりiat(発行時刻)が自動で付与されます。
  • expirationTimeMinutes: exp(有効期限)を分単位で指定します。GitHub App のJWTは最大10分までのため、ここでは 5 としています。
  • Claims: iss に App ID を指定します。これがJWTの発行者を表します。

このアクションが成功すると、出力として jwt に生成されたJWT文字列が格納されます。次のアクションでこの値を参照します。

2. アクセストークンの発行(HTTPアクション)

次に、生成したJWTを元に一時的なアクセストークンを発行します。GitHub App では、JWTそのものでIssueを作成するのではなく、JWTを使ってインストールアクセストークンを取得し、そのトークンでAPIを呼び出す流れになります。

ここでは Workflow AutomationのHTTPアクション(POST)を使います。設定内容は次のとおりです。

  • リクエスト先URL: https://api.github.com/app/installations/{Installation ID}/access_tokens
  • ヘッダー Authorization: Bearer に続けて、前のアクションで生成したJWTを参照します。
    • 例。Bearer ${{ .steps.auth_jwt_create_1.outputs.jwt }}
  • ヘッダー Accept: application/vnd.github+json を指定します。

レスポンスのボディには発行されたトークンが含まれます。そのままでは後続で扱いにくいため、セレクター(selectors)を使って必要な値だけを抽出します。ここではレスポンスボディをJSONとして解釈し、token フィールドを取り出して、次のアクションから参照できる名前を付けておきます。

3. Issueの作成(HTTPアクション)

その後、抽出したアクセストークンを元にIssueの発行を行います。ここでもう一度 HTTPアクション(POST)を使い、GitHubのREST APIを呼び出します。

設定内容は次のとおりです。

  • リクエスト先URL: https://api.github.com/repos/{owner}/{repo}/issues
  • ヘッダー Authorization: Bearer に続けて、前のアクションで抽出したトークンを参照します。
    • 例。Bearer ${{ .steps.http_post_2.outputs.token }}
  • ヘッダー Accept: application/vnd.github+json を指定します。
  • ボディ: 作成したいIssueの titlebody をJSONで指定します。

ここまで設定できたら、ワークフローを実行します。指定したリポジトリに、設定したタイトルと本文でIssueが作成されていれば成功です。

まとめ

GitHub Appを用いたissueの作成を例に、Workflow Automation 上でJWT認証を使用する方法を紹介しました。

今回は例として、GitHub Appを取り上げましたが、JWT認証を求める外部サービスは他にもあります。Auth JWT アクションでJWTを生成し、HTTPアクションでAPIを呼び出すという同じ考え方で、さまざまな連携に応用できます。Workflow Automation から外部サービスとの認証連携を検討する際の参考にしてみてください。