APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

GitHub x Azure OIDC Connect登録をBackstageで省力化する

GitHub Actionsを使用してAzureに接続する

GitHub ActionsからAzureに接続する場合、OIDC Connectionで実現することが多いと思います。

learn.microsoft.com

OIDC Connectionを利用するとパスワードなど秘匿情報を登録する必要もなく、安全性の高い方式です。 パスワードの代わりにGitHubとAzureの双方にそれぞれの情報を登録しておくことが必要です。

登録する内容は、Azure側(Entra ID Application登録側)にはGitHub側のOrganization名とリポジトリ名、および環境名といった情報を、GitHub側にはAzure Entra ID Appliation登録のテナントID、クライアントID、接続するサブスクリプションIDといった情報です。

一般的にはこうした情報を手作業で登録しています。リポジトリ1つに対して行っているだけならばそれほど大変ではありませんが、 複数のリポジトリに同じような作業を繰り返していると、ID情報などの取得と設定が意外と面倒な作業と感じるものです。

そこでBackstageを活用してこの作業を省力化することにしました。

BackstageによるOIDC Connection登録の省力化

以前にも紹介していますが、Backstageには(Scaffolder)Templateという機能があります。

techblog.ap-com.co.jp

techblog.ap-com.co.jp

この機能は事前に実行したい内容をテンプレートとして用意し、その内容を実行したいときに少数のパラメータ値を加えてテンプレートを実行することで繰り返し作業を楽にするというものです。

一般的にはGitリポジトリの新規作成や更新、Pull Request作成といった用途で利用していることが多いのですが、実はもっと様々な機能を実現することができます。また、Pluginを独自に開発することで必要な機能を追加していくことも可能です。今回は以下のような機能を用意・活用します。

  • GitHub Environmentの登録(OSSとして公開されています。アクション名は github:environment:create
  • Azure Entra ID OIDC登録(こちらは独自実装したものです)

テンプレートを作成するにあたって、入力作業をより簡略化できるようにするため、AzureサブスクリプションやAzure Entra ID Application登録を(Client ID等必要となる情報とともに)Backstage のResource Catalogとして登録することにしました。これによるテンプレートを実行する際にAzureのテナントIDなどをユーザーが入力しなくても済むようにしています。

処理の流れとしては以下のようなことを想定します。

入力パート

  • Entra ID Applcation登録とAzure Subscriptionを選択

  • 登録対象のGitHubリポジトリを選択

実行パート

  • GitHub EnvironmentsにAzureの認証必要情報を登録
  • Azure Application登録のフェデレーション情報としてGitHubの認証情報を登録

テンプレートとしては以下のような内容です。

apiVersion: scaffolder.backstage.io/v1beta3
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template
kind: Template
metadata:
  name: example-ms-app-federation
  title: Entra ID App Federation登録
  description: An example template for screating an MS Graph App federation
spec:
  owner: user:guest
  type: ops

  parameters:
    - title: App Registration Info
      require:
        - appReg
        - appId
        - name
      properties:
        signin:
          type: string
          ui:field: MicrosoftSignIn
          ui:options:
            requestUserCredentials:
              secretsKey: AZURE_USER_OAUTH_TOKEN
        appEntity:
          title: Pick Application Entity
          type: string
          ui:field: EntityPicker
          ui:options:
            catalogFilter:
              - kind: 'Resource'
                spec.type: 'entraid-application'
        subscriptionEntity:
          title: Pick Subscription Entity
          type: string
          ui:field: EntityPicker
          ui:options:
            catalogFilter:
              - kind: 'Resource'
                spec.type: 'azure-subscription'
        name:
          title: Federatoin name
          type: string
    - title: GitHub Environment
      required:
        - repoUrl
      properties:
        repoUrl:
          title: Repository Location
          type: string
          ui:field: RepoUrlPicker
          ui:options:
            allowedHosts:
              - github.com
            requestUserCredentials:
              secretsKey: GITHUB_USER_OAUTH_TOKEN
        environment:
          title: GitHub Environment
          type: string
  steps:
    - id: subscription
      name: Fetch Subscription
      action: catalog:fetch
      input:
        entityRef: ${{ parameters.subscriptionEntity }}
    - id: application
      name: Fetch App Registration
      action: catalog:fetch
      input:
        entityRef: ${{ parameters.appEntity }}
    - id: register-federation
      name: Register Federation
      action: msgraph:githubFederation:new
      input:
        applicationId: ${{ steps.application.output.entity.metadata.annotations | pick('azure.com/entraid-app-client-id') }}
        organization: ${{ (parameters.repoUrl |  parseRepoUrl).owner }}
        repository: ${{ (parameters.repoUrl  | parseRepoUrl).repo }}
        entityType: 
          type: 'environment'
          environment: ${{ parameters.environment }}
        name: ${{ parameters.name }}
        description: Federation created by PlaTT
        token: ${{ secrets.AZURE_USER_OAUTH_TOKEN }}
    - id: createGitHubEnvironment
      name: Create GitHub Environment
      action: github:environment:create
      input:
        repoUrl: ${{ parameters.repoUrl }}
        name: ${{ parameters.environment }}
        environmentVariables:
          AZURE_TENANT_ID: ${{ steps.subscription.output.entity.metadata.annotations | pick('azure.com/tenant-id') }}
          AZURE_SUBSCRIPTION_ID: ${{ steps.subscription.output.entity.metadata.annotations | pick('azure.com/subscription-id') }}
          AZURE_CLIENT_ID: ${{ steps.application.output.entity.metadata.annotations | pick('azure.com/entraid-app-client-id') }}
        token: ${{ secrets.GITHUB_USER_OAUTH_TOKEN }}
  output:
    links:
      - title: Repository Environment
        url: ${{ ('https://' ~ parameters.repoUrl | replace('?owner=', '/') | replace('&repo=', '/')) }}/settings/environments/
      - title: App Registration
        url: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Credentials/appId/${{ steps.application.output.entity.metadata.annotations | pick('azure.com/entraid-app-client-id') }}/isMSAApp~/false

実行すると、Azure側にはGitHubの情報が、GitHub側にはAzure Entra IDの情報が登録されます。入力情報がかなり削減され、またAzureとGitHubの双方に反映されるため、間違うこともありません。

さらにこのステップをリポジトリ作成テンプレートの中に追加することで、リポジトリ作成時点からGitHubリポジトリとAzureとのOIDC Connection登録が完了している状態とすることができます。

このように、BackstageのTemplate機能を利用することでOIDC Connection登録作業も省力化、簡略化することができます。

最後に

Backstageには他にも開発者の認知負荷を低減する様々な機能が存在します。その効果も使い方次第でより大きくなります。 弊社ではOSSであるBackstageをManaged Serviceとして提供させて頂いております。

techblog.ap-com.co.jp

今回紹介した機能についてはMicrosoft Entra ID関連の部分は独自に拡張したものです。

ご興味のある方がいらっしゃいましたらぜひ弊社までご連絡ください。よろしくお願いします。

www.ap-com.co.jp

www.ap-com.co.jp