【Developer Hub 実践|第2回】GitHubを使用した認証を実装しよう

こんにちは、Red HatでOpenShift関連のプリセールスをしている北村です。

前回の記事でDeveloper Hubのインストールが完了したので、今回はGitHubと連携してDeveloper Hubの認証を実装します。

前回の状態

前回ログイン画面まで表示されることを確認しましたが、この状態でGitHubの"Sign In"を選択すると、以下のようなエラーが表示されます。

これはまだGitHubとの連携情報がDeveloper Hubに設定されていないために発生しています。 ではGitHub認証を実装していきましょう。

Developer Hub GitHub 認証 実装手順

GitHubでの認証を実現するために、GitHub Appの作成を行います。

ここでGitHubの個人アカウントでGitHub Appを設定するとそのユーザーのみ認証可能になりますが、Organizationで登録することで、そのOrganization配下のユーザー全員が認証可能になります。

Developer Hubは複数の開発メンバーでの利用を想定されるケースが多いので、ここでは新たにOrganizationを作成して、そのGitHub Appを登録します。

GitHubの設定

GitHub Organizationは以下の公式URLを参考に作成してください。おそらくすでにOrganizationが存在するケースが多いので、ここでは手順を割愛します。

新しい Organization をゼロから作成 - GitHub Docs

今回は"rhdh-practice"というOrganizationを作成しました。

次にGitHub Appを作成していきます。OrganizationのページからSetttings→Developer settings→GitHub Apps→New GitHub Appを選択します。

以下の内容を入力します。

GitHub App name 任意の値
Homepage URL https:// (Developer HubのURL)
Callback URL https:// (Developer HubのURL) /api/auth/github/handler/frame
Webhook URL https:// (Developer HubのURL)
(Webhook) Secret 任意の値
Permissions 以下の項目にRead-onlyを付与
Repository permissions
- Administration
- Commit statuses
- Contents
- Dependabot alerts
- Deployments
- Pull Requests
- Webhooks
Organization permissions
- Members
Where can this GitHub App be installed? Only on this account

入力が完了したらCreate GitHub Appを選択します。

するとGitHub Appが作成され、App ID , Client IDが払い出されます。

そのままGenerate a new client secretを選択すると画面上にClient Secretが払い出されるため、App ID, Client ID , Client Secret をコピーして手元に残しておきましょう。

そして画面の下の方にいき、Generate a private key を選択すると、Private Keyが払い出され、pemファイルがダウンロードされます。この中身を後ほど使います。

ここまで完了したら、最後に作成したGitHub appをOrganizationにインストールします。左側のメニューからInsatall Appを選択してインストールを実行します。

これでGitHub側の準備は完了しました。

Developer Hub の設定

GitHub側の設定が完了したので、次にDeveloper Hub側の設定を行います。 まずはGitHub Appの情報を、前回の記事で作成した secrets-rhdh.yaml に反映します。GITHUB_PRIVATE_KEY_FILEにはpemファイルの中身を記載します。

secrets-rhdh.yaml

apiVersion: v1
kind: Secret
metadata:
  name: secrets-rhdh
  namespace: rhdh
stringData:
  BASE_URL: "https://backstage-developer-hub-rhdh.apps.<ROSAドメイン>"
  BACKEND_SECRET: "<バックエンド認証キー>"
  GITHUB_HOST_DOMAIN: "github.com"
  AUTH_GITHUB_APP_ID: "<GitHub App ID>"
  AUTH_GITHUB_CLIENT_ID: "<GitHub App Client ID>"
  AUTH_GITHUB_CLIENT_SECRET: "<GitHub App Client Secret>"
  GITHUB_WEBHOOK_URL: "https://backstage-developer-hub-rhdh.apps.<ROSAドメイン>"
  GITHUB_WEBHOOK_SECRET: "<Webhook Secretに設定した任意の値>"
  GITHUB_PRIVATE_KEY_FILE: |
    -----BEGIN RSA PRIVATE KEY-----
    [PRIVATE_KEY_PLACEHOLDER]
    -----END RSA PRIVATE KEY-----

このSecretをデプロイします。

oc apply -f secrets-rhdh.yaml

次にDeveloper Hubの設定ファイル app-config-rhdh.yaml を編集します。以下のように、auth , integrations , signInPage の設定を追加します。

  • auth : Developer Hubの認証に関する設定
  • integrations : GitHubなどの外部システムとの統合(連携)に関する設定
  • signInPage : ログインするときに表示されるサインインページを指定する設定

app-config-rhdh.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: app-config-rhdh
  namesapce: rhdh
  annotations:
    rhdh.redhat.com/backstage-name: developer-hub
data:
  app-config-rhdh.yaml: |
    app:
      title: Red Hat Developer Hub
      baseUrl: ${BASE_URL}
    backend:
      auth:
        externalAccess:
        - type: legacy
          options:
            secret: “${BACKEND_SECRET}”
            subject: legacy-default-config
      baseUrl: ${BASE_URL}
      cors:
        origin: ${BASE_URL}
    auth:
      environment: production
      providers:
        github:
          production:
            clientId: ${AUTH_GITHUB_CLIENT_ID}
            clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
    integrations:
      github:
        - host: ${GITHUB_HOST_DOMAIN}
          apps:
            - appId: ${AUTH_GITHUB_APP_ID}
              clientId: ${AUTH_GITHUB_CLIENT_ID}
              clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
              webhookUrl: ${GITHUB_WEBHOOK_URL}
              webhookSecret: ${GITHUB_WEBHOOK_SECRET}
              privateKey: |
                ${GITHUB_PRIVATE_KEY_FILE}
    signInPage: github

このConfigmapをデプロイします。

oc apply -f app-config-rhdh.yaml

するとDeveloper Hub Podが再起動されるので、立ち上がるまで待ってからDeveloper Hubにアクセスしてみましょう。

こんな感じで、Guestのログイン項目がなくなり、GitHubのみでのログイン画面になりました。

Sign Inを選択してログインしてみると...

エラーが出るのだが😡

はい、実はまだ他に対応しなければならないことがあります。

GitHubからUser情報を取得する

Developer Hubではユーザー認証の際、Auth Provider(先述で設定してきたもの)による認証行為に加えて、Developer Hub内に紐付け可能なUser Entityが存在するかどうかもチェックします。

先ほどのエラーはGitHubとの認証連携自体はできたものの、Developer Hub側で紐づけるべき User という エンティティ(Entity) が存在しないために発生しているエラーになります。

(なおDeveloper Hubにおける Entity については、次回の記事で詳しく説明していきます。)

そしてこのUser Entityというのは、Developer HubのPluginを活用することで、GitHubのOrganizationからユーザー情報を取得することができます。

イメージとしては以下のような形になります。

では設定していきましょう。

まず、GitHub Organizationから User / Team 情報を読み取り、Developer HubにUser / Group Entity を作成するGitHub Org というPluginを導入します。

前回の記事でしれっと作成したdynamic-plugins-rhdh.yamlにdynamic pluginのインストール設定を記入します。

  • plugins : Developer HubにインストールするPluginの情報を記載する。
    • packageにはdynamic pluginのパスを記載する
    • disabldedfalse にすることで、Podのinit処理時にdynamic pluginをインストールする。

今回は GitHub Org Pluginをインストールするので、GitHub Org Pluginが格納されているパスを指定しています。

Developer Hubにあらかじめ格納されているdynamic pluginの一覧やパスは以下の公式ドキュメントに記載があります。

動的プラグイン参照 | Red Hat Product Documentation

dynamic-plugins-rhdh.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: dynamic-plugins-rhdh
  namespace: rhdh
  annotations:
    rhdh.redhat.com/backstage-name: developer-hub
data:
  dynamic-plugins.yaml: |
    includes:
      - 'dynamic-plugins.default.yaml'
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic
        disabled: false

次にapp-config-rhdh.yamlに設定を追記します。

Developer Hubではapp-configに適切な設定を記述すると、連携先のシステム(今回で言うとGitHubそのもの)やGitリポジトリ内にあるyamlファイルから、内部に登録するEntity情報を取得することができます。

なお、このEntityを登録するための仕組みをDeveloper HubではCatalogといいます。CatalogEntityは厳密には別物ですが、ほぼ同じものと捉えてもらって構いません。

今回は以下の項目を追記しましょう。

  • catalog : Developer HubにさまざまなEntity(Catalog)を登録するための設定
  • catalog.providers : Entity(Catalog)のデータを取得するための Provider(GitHubやGitLabなど) に関する設定
  • catalog.providers.githubOrg : 特定のGitHub Organization内のUserやTeam情報をもとにDeveloper Hub側にUser / Group Entityを作成するための設定

app-config-rhdh.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: app-config-rhdh
  namesapce: rhdh
  annotations:
    rhdh.redhat.com/backstage-name: developer-hub
data:
  app-config-rhdh.yaml: |
    app:
    ...omit...
    backend:
    ...omit...
    auth:
    ...omit...
    integrations:
    ...omit...
    signInPage: github
    catalog:
      providers:
        githubOrg:
          githubUrl: https://${GITHUB_HOST_DOMAIN}
          orgs:
            - ${GITHUB_ORGANIZATION}
          schedule:
            frequency: PT60S
            initialDelay: PT30S
            timeout: PT120S

scheduleフィールドは、GitHubへ定期的にアクセスしてOrganizationの情報を取得するためのパラメータです。

ここはpluginによって記述方法が変わります。今回のGitHub Org PluginではISO 8601 Duration 形式で記述する必要があります。

ISO 8601 Duration 形式の書き方は以下を参照ください。

P2Y3DT6H8M!? この暗号を解読するための ISO 8601 duration specification とは | 株式会社AMG Solution

今回は実装中のため、1分ごとにGitHub Organizationの情報を取得するような設定にしています。

安定稼働後は1時間に一回程度に変更することをおすすめします。

最後にsecrets-rhdh.yamlも修正してGITHUB_ORGANIZATIONを追加しておきましょう。

secrets-rhdh.yaml

apiVersion: v1
kind: Secret
metadata:
  name: secrets-rhdh
  namespace: rhdh
stringData:
  ...omit...
  GITHUB_ORGANIZATION: "<今回使うGitHub Organization名>"

これらをデプロイします。

oc apply -f app-config-rhdh.yaml -f secrets-rhdh.yaml -f dynamic-plugins-rhdh.yaml

これらの設定によって、Developer Hubが定期的にGitHubへアクセスし、GitHub Organization内のUserやTeamの情報を User GroupEntityとして内部に登録する処理が行われます。

Podの再起動後、ログインしてみると、無事にHOME画面が表示されます。

ちなみにこの状態で画面左下のSettingsを選択すると、ちゃんとGitHubのユーザーでDeveloper Hubにログインできていることがわかります。

おわりに

今回はGitHubと連携してDeveloper Hubの認証を実装する方法を解説しました。

次回の記事では、同様の認証作業をGitLabを使って実装してみます。乞うご期待!

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。