今回は GitHub Actions で Terraform を実行する際に、OIDC 認証を用いて Azure にリソースをデプロイします。OIDC を利用することで、GitHub 内に Azure アカウントのシークレットなどを保存しなくて良いため、セキュリティが向上します。
Azure は以前から OIDC 認証に対応していましたが、Terraform で Azure CLI の認証情報を利用したデプロイを実行しようとするときにサービス プリンシパルがサポートされていませんでした。そのため、Terraform で OIDC 認証を利用した Azure へのデプロイができませんでした。
しかし、つい最近サービス プリンシパルでの OIDC 認証がサポートされたため、他のクラウドと同じくシークレットを保持しないデプロイを実現できるようになりました。
公式ではこちらの手順が参考になります。
Azure でサービス プリンシパルの作成とロールを設定
まずは Azure 側に認証で利用するサービス プリンシパルを作成します。変数に使用する GitHub リポジトリの情報は、次のように設定します。
- AccountName : GitHub アカウント名 (組織名)
- RepositoryName : リポジトリ名
https://github.com/<AccountName>/<RepositoryName>
Azure CLI を使ってサービス プリンシパルを作成します。Azure AD での操作は時期に Graph API へと移行する計画が発表されていますので、今後この手順は見直す必要があるかもしれません。が、ひとまず慣れ親しんだ Azure CLI での操作をまとめます。
# 変数の定義
SUBSCRIPTION_ID='********-****-****-****-************'
OIDC_APP_NAME='GitHub Actions OIDC'
GITHUB_ACCOUNT='AccountName'
GITHUB_REPOSITRY='RepositoryName'
# Azure AD アプリの作成
OIDC_APP_ID=$(az ad app create --display-name $OIDC_APP_NAME --query appId -o tsv)
# サービス プリンシパルの作成
ASSIGNEE_OBJECT_ID=$(az ad sp create --id $OIDC_APP_ID --query objectId -o tsv)
# サービス プリンシパルへロールの付与 (例: 共同作成者[contributer])
az role assignment create --role contributor --subscription $SUBSCRIPTION_ID --assignee-object-id $ASSIGNEE_OBJECT_ID --assignee-principal-type ServicePrincipal
# OIDC 用リポジトリ識別情報の設定
az rest --method POST --uri "https://graph.microsoft.com/beta/applications/${CLIENT_ID}/federatedIdentityCredentials" --body "{\"name\":\"${OIDC_APP_NAME}\",\"issuer\":\"https://token.actions.githubusercontent.com\",\"subject\":\"repo:${GITHUB_ACCOUNT}/${GITHUB_REPOSITRY}:environment:production\",\"description\":\"OIDC\",\"audiences\":[\"api://AzureADTokenExchange\"]}"
# GitHub Actions 設定用パラメーターの取得
CLIENT_ID=$(az ad app show --id $OIDC_APP_ID --query objectId -o tsv)
TENANT_ID=$(az ad sp show --id $OIDC_APP_ID --query appOwnerTenantId -o tsv)
コマンドの中でサービス プリンシパルに対して共同作成者のロールを付与しています。ここは利用したいシチュエーションに合わせて権限をカスタマイズしてください。GitHub 側に設定するため、次の情報を取得しておきます。
- Azure AD アプリのクライアント ID (App ID)
- Azure AD テナント ID
- Azure サブスクリプション ID
export $CLIENT_ID
export $TENANT_ID
export $SUBSCRIPTION_ID
Azure AD アプリ (サービス プリンシパル) あたりの ID は色々と混在していてややこしいのですが、GUI で確認できるものだと [アプリケーション (クライアント) ID]と表示されている部分が今回利用する情報です。

OIDC の認証に関する設定は、[証明書とシークレット]>[フェデレーション資格情報] から行えます。

組織とリポジトリはそれぞれ GITHUB_ACCOUNT
と GITHUB_REPOSITORY
に設定した内容になります。アクセス元を制限するためにエンティティ型と選択範囲を指定します。上述のコード内で言うと subject
に示されている部分の後半です。これをゆるくすると不正なアクセスが発生してしまうので注意します。
なお、エンティティには次のものを指定できます。
- Environment
- Brunch
- PullRequest
- Tag

GitHub Actions ワークフロー
Azure に OIDC 認証するための手順を GitHub Actions ワークフローに組み込みます。
シークレットの作成
GitHub Actions のシークレットに、上述のコードで設定した ID の情報を設定します。シークレットがなくなっても流石にサブスクリプションやテナントの ID からは逃れられませんね。
シークレット名 | 変数名 | 説明 |
ARM_CLIENT_ID | CLIENT_ID | Azure AD アプリのクライアント ID (App ID) |
ARM_SUBSCRIPTION_ID | SUBSCRIPTION_ID | Azure サブスクリプション ID |
ARM_TENANT_ID | TENANT_ID | Azure AD テナント ID |

権限設定の追記
ワークフローから OIDC トークンのリクエストを行えるように権限の設定を追加します。次のような内容をワークフローに追記します。
permissions:
id-token: write
contents: read
Azure アクセス情報の設定
OIDC での Azure への認証には Azure CLI を利用しないため、必要な情報を環境変数に渡しておくだけで大丈夫です。GitHub Actions ワークフロー内での環境変数は、注意しないとステップ間での受け渡しができません。ステップ間を超えて利用できる環境変数を利用するには、$GITHUB_ENV
に変数定義の値を送ります。
steps:
- name: "Deifne environment variables for Azure"
run: |
echo ARM_CLIENT_ID="${{ secrets.ARM_CLIENT_ID }}" >> $GITHUB_ENV
echo ARM_TENANT_ID="${{ secrets.ARM_TENANT_ID }}" >> $GITHUB_ENV
echo ARM_SUBSCRIPTION_ID="${{ secrets.ARM_SUBSCRIPTION_ID }}" >> $GITHUB_ENV
ワークフロー ファイルの例
上述の内容を踏まえ、次のような内容になります。
name: 'Terraform'
on:
push:
branches:
- main
pull_request:
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
environment: production
# 権限設定の追記
permissions:
id-token: write
contents: read
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
# Azure での認証情報を定義するステップ
- name: "Deifne environment variables for Azure"
run: |
echo ARM_CLIENT_ID="${{ secrets.ARM_CLIENT_ID }}" >> $GITHUB_ENV
echo ARM_TENANT_ID="${{ secrets.ARM_TENANT_ID }}" >> $GITHUB_ENV
echo ARM_SUBSCRIPTION_ID="${{ secrets.ARM_SUBSCRIPTION_ID }}" >> $GITHUB_ENV
- name: Terraform Init
run: terraform init
- name: Terraform Format
run: terraform fmt -check
- name: Terraform Plan
run: terraform plan
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve
Terraform プロバイダーの指定
Terraform プロバイダー側でも少し設定が必要になります。OIDC への対応は 3.7.0 以上の AzureRM プロバイダーなので、required_provides
にてバージョンを指定します。
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "= 3.7.0"
}
}
}
あとは Terraform ファイルを用意して Azure リソースを作成します。また、プロバイダーの指定は次のようになります。
provider "azurerm" {
features {}
use_oidc = true
}
これで Azure・GCP・AWS の主要クラウドに対してGitHub Actions で OIDC 認証できるようになりました!
コメント