目次
はじめに
こんにちは、半田(@handy)です。
以前、Azure DevOpsからAWS BeanstalkやAWS Lambdaへのデプロイを行った記事を書きました。
上記記事ではAWS側の認証認可にIAMユーザーを利用していましたが、実運用を考えたときにアクセスキー・シークレットアクセスキーの管理は極力避けたいという方は多いのではないかと思います。
そこで今回は、Open ID Connect(OIDC)を利用してキーの管理を行わずにAzure DevOpsからAWSへデプロイを行う構成の検証を行っていきます。
Open ID Connect自体の説明はわかりやすい記事を出されている方が他に多くいらっしゃいましたので、本記事では詳しく説明しません。
また、Azure DevOpsを利用したAWSへのデプロイというよりは、Azure DevOpsにおけるOIDC設定が本記事の主旨になりますので、細かいコードの説明なども省略しております。
構築構成
実際に構築した構成は以下になります。(細かい部分は敢えて省略しています)
デプロイするAWSリソースはこちらの過去記事のLambda関数のコードを流用し、デプロイのための認証・認可部分だけ変更しました。
また、今回はトリガー実行ではなく、手動でパイプラインを実行します。
前提
以下の作業は既に実施済みになります。
AWS側
- Lambda関数作成(Python3.11)
Azure側
- Azure DevOps OrganizationとProjectの作成
- 「AWS Toolkit for Azure DevOps」Extentionsのインストール
- Azure Reposにlambda-functionsリポジトリの作成とコードのアップロード
- azure-pipelines.ymlファイルの作成(=Azure Pipelineの作成)
実作業
実作業に入る前に
Azure DevOpsでAWSとのOIDCを利用する場合、「AWS Toolkit for Azure DevOps」Extentionsの機能を利用する必要があります。
もう少し正確に言うと「AWS Toolkit for Azure DevOps」Extentionsのv1.15.0バージョン(2024年8月リリース)でAWSとのOIDC認証に対応したので、現在であればOIDCが利用できるようになりました。
v1.15.0バージョンのリリースに合わせて以下GitHubのREADMEにOIDC設定の記述も追加されていますので、今回はこちらをベースに設定していきます。
参考までに対象のGitHub Issueは以下になります。
READMEを見ると以下のような記載があります。
AWS サービスエンドポイントの設定
AWS サービスエンドポイントを使用するには、使用する AWS サブスクリプションを追加するためにアカウント管理画面(画面右上にある歯車アイコン)を開き、[サービス] タブをクリックします。各 Azure DevOps プロジェクトには、独自の認証情報セットが関連付けられていることに注意してください。サービスエンドポイントはプロジェクト間で共有されません。必要に応じて、ビルド内のすべての AWS タスクで使用する単一のサービスエンドポイント、または複数のエンドポイントを関連付けることができます。
Azure DevOpsのWebポータル上はREADMEに記載されている"AWSサービスエンドポイント"という設定項目が中々見つからないので、慣れていないとどこを設定したら良いかわかりにくいかと思いますが、これはProject Settingsの"Service connections"項目のことを指しています。
"Service connections"項目に設定する種類とそれぞれで最低限必要な設定項目についてもREADMEに記載されています。
現在はOpen ID Connect、アクセスキー/シークレットアクセスキー、ロール(インスタンスプロファイル利用)の3種類があります。
OIDC フェデレーション
- AWS タスクの設定時に認証情報を参照する際に使用する名前
- 想定するロールの ARN
- useOIDC オプションをチェック
静的認証情報
アクセスキーについて」を参照してください。
- AWS タスクの設定時に認証情報を参照する際に使用する名前
- AWS アクセスキー ID
- AWS シークレットアクセスキー
ロールの想定
タスクは、エンドポイントの設定時に、想定するロールのAmazonリソース名(ARN)とオプションの識別子を追加することで、想定ロールの認証情報も使用できます。指定したアクセスキーとシークレットキーは、ビルドエージェントによって実行される際に、タスク用の一時的な認証情報を生成するために使用されます。一時的な認証情報は、デフォルトでは最大15分間有効です。より長い有効期間を有効にするには、ビルドまたはリリース定義で「aws.rolecredential.maxduration」変数を設定し、15分(900秒)から12時間(43200秒)までの有効期間を秒単位で指定します。
公式としてはOIDCの利用が推奨されているようです。
注
静的な認証情報を維持する必要性を避けるため、OIDCフェデレーションの使用を強くお勧めします。ビルドおよびリリース定義で使用する予定のタスクをサポートするために必要なサービスおよびリソースのみにアクセスを許可する権限を持つIAMロールを設定できます。
[AWS側作業]IAM ID Providerの作成
ではさっそくREADMEに従ってサービスコネクションの作成、、、といきたいところなのですが、サービスコネクションの作成にはAWSのIAM ID Providerと紐付いたIAMロールのARN値が必要になるので、先にID ProviderとIAMロールの作成から行っていきます。
マネジメントコンソールにログインし、IAM>ID Providerページに遷移して「プロバイダを追加」ボタンを押下すると設定項目が確認できます。
以下をみると"プロバイダのURL"と"対象者"の2項目を設定する必要があることがわかります。
この2つに何を設定するかですが、実はMicrosoft公式のドキュメントを漁っても中々出てきません。
また、AWS公式の記事(Use OpenID Connect with AWS Toolkit for Azure DevOps to perform AWS CodeDeploy deployments)を見るとそれっぽい設定は確認できますが、そちらはAzure VMとManaged IDを利用してOIDCを設定する場合の設定項目になります。
「AWS Toolkit for Azure DevOps」ExtentionsのOIDC機能を利用する場合はそれとは違う設定内容にする必要があります。
では、どうやって確認したら良いのかですが、ヒントは以下のAzure DevOps Blogに記載されています。
具体的には以下の箇所になります。
Issuer URL:これは、https://vstoken.dev.azure.com/<organisation-id>という形式のURLで、organisation-idはお客様のAzure DevOps組織のGUIDです。
例えば、https://vstoken.dev.azure.com/f66a4bc2-08ad-4ec0-a25e-e769dab3b294。Subject identifier: これは、組織名がAzure DevOpsの組織名、プロジェクト名がAzure DevOpsのプロジェクト名、サービス接続名がサービス接続の名前である、sc://<組織名>/<プロジェクト名>/<サービス接続名>という形式の、お客様のサービス接続へのマッピングです。
例えば、sc://my-organisation/my-project/my-service-connection。Audience:これは常にapi://AzureADTokenExchangeです。
基本的には書いてあるとおりですが、Issuer URLが"プロバイダのURL"、Audienceが"対象者"に該当します。
Subject identifierはIAM ID Providerではなく、紐付け先のIAMロールの信頼ポリシーで利用します。
上記設定項目の内、Subject identifierはAzure DevOpsのWebポータルから確認できる内容で、Audienceは api://AzureADTokenExchange で固定なので問題ないのですが、Issuer URLの "<organisation-id>"だけは設定時に注意が必要です。
Organizationと聞いてAzure DevOps Organization Settingsの以下の部分が真っ先に思いつくかと思いますが、これはOrganization "Name"なのでOrganization "ID"とは別物になります。
では、どうやって自組織の"Organization ID"を特定するかですが、実はAzure PortalやAzure CLIではOrganization IDは確認できません。
私も色々調べてみましたがOrganization IDだけ確認する方法が見つからず、途方に暮れたタイミングで以下の記事を見つけました。
端的に言うと、Organization SettingsのMicrosoft Entra項目の「Download」ボタンを押下すると組織に紐付くOrganization一覧が取得できるので、その一覧からIDを確認することができます。
ダウンロードしたファイルを開くと、以下のようにいくつかのヘッダーとOrganizationが一覧で確認できます。
この一覧からOIDC設定をしたいOrganizationの1列目の"Organization ID"をメモしておきます。
ここまで確認できたらIAM ID Providerを作成していきます。
以下のように設定できたら「プロバイダを追加」ボタンを押下してID Providerを作成します。
※プロバイダのURL項目の<organisation-id>部分は先ほど確認した"Organization ID"に置き換えます
※プロバイダURLの末尾に"/"(スラッシュ)を入れるとうまくOIDC認証されないので、付けないように気をつけてください
問題なければID Providerが作成されます。
[AWS側作業]IAMロールの作成
ID Providerが作成できたら、それに紐付くIAMロールを割り当てしていきます。
Azure DevOpsからはこのIAMロールの権限を利用してデプロイを行われるため、それを考慮して作成する必要があります。
今回は新規で作成するので"新しいロールを作成"を選択します。
IAMロールを作成する画面に遷移します。
ここでは遷移した時点で以下の2項目が設定された状態になっているかと思うので、
- アイデンティティプロバイダー
- Audience
「条件の追加」ボタンからConditionの設定欄を増やします。各項目には以下の内容を入力します。
- キー(リストから選択)
- "vstoken.dev.azure.com/<organisation-id>:sub"
- 条件(リストから選択)
- "StringEqueals"
- 値(手動入力)
- "sc://<organization-name>/<project-name>/<service-connection-name>"
<organization-name>、<project-name>はAzure DevOpsのWebポータルを確認して入力します。
<organisation-id>ではなく<organization-name>なので間違えないようにご注意ください。
<service-connection-name>はこのあとの手順で作成するサービスコネクション名を設定します。この時点では作成していなくても問題ないので、一旦"aws-oidc-user"と設定します。
次にIAMロールにアタッチするIAMポリシーを選択します。
今回は検証用なのでマネージドポリシーのAdministratorAccessをアタッチします。
適当なロール名を入力(ここではazure-deploy-roleと設定)して、信頼ポリシーとアタッチしたIAMポリシーを確認して問題なければ「ロールを作成」ボタンを押下します。
作成できたら後続作業で使うので、IAMロールのARN値をメモしておきます。
[Azure側作業]サービスコネクション作成
ここまで来たらようやくサービスコネクションの作成作業に入ります。
冒頭のREADMEに記載があった通り、Azure DevOpsでAWSのOIDCを利用するには以下の3つが設定された"Service connections"を作成する必要があります。
- AWS タスクの設定時に認証情報を参照する際に使用する名前
- 想定するロールの ARN
- useOIDC オプションをチェック
Azure DevOpsの"Service connections"画面の「New service connection」ボタンから新しくサービスコネクションを作成します。
「AWS Toolkit for Azure DevOps」Extentionsをインストール済みであればAWSが出てくると思うので、選択して「Next」ボタンを押下します。
次の画面では以下の11項目が入力できる状態になっているかと思います。(画像は一部見切れています)
OIDCを利用する場合はREADMEに従って4番、7番、8番を入力します。11番は必要性に応じて設定します。
4番目の"Role to Assume (optional)"項目には一つ前の手順でメモしたIAMロールのARNを入力します。
一通り入力できたら「Save」ボタンを押下します。
- Access Key ID (optional)
- Secret Access Key (optional)
- Session Token (optional)
- Role to Assume (optional)
- Role Session Name (optional)
- External ID (optional)
- Use OIDC (optional) ※Checkbox
- Service connection name
- Service Management Reference (optional)
- Description (optional)
- Grant access permission to all pipelines ※Checkbox
設定内容に問題なければサービスコネクションが作成されます。
[Azure側作業]Azure Pipeline設定
サービスコネクションの作成までできたら、あとはAzure Pipeline側での利用設定になります。
ソースコードやazure-pipelines.ymlは過去の記事で利用したものを流用し、認証の部分だけ書き換えます。
実際に設定したazure-pipelines.ymlファイルの内容が以下になります。
task: LambdaDeployFunction@1タスクの"awsCredentials"パラメータだけ先ほど作成したサービスコネクション名に修正します。
これであとはPipelineを実行するとAzure DevOpsとAWSでOIDC認証後、発行された一時認証情報を利用してデプロイされます。
ちなみにこのコードでやっていることとしては、コードをZip化して対象のLambda関数にデプロイをしているだけです。
# Docker
# Build a Docker image
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker
trigger:
- release
pool:
vmImage: ubuntu-latest
resources:
- repo: self
strategy:
matrix:
Python311:
python.version: '3.11'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
displayName: 'Use Python $(python.version)'
- script: |
python -m pip install --upgrade pip
pip install --target ./myfunction -r ./requirements.txt
displayName: 'Install dependencies'
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: 'myfunction/'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/myfunction.zip'
- task: LambdaDeployFunction@1
inputs:
awsCredentials: 'aws-oidc-user' ★この項目を作成したサービスコネクション名に修正
regionName: 'ap-northeast-1'
deploymentMode: 'codeonly'
functionName: 'azure-deploy-func1'
codeLocation: 'localfile'
localZipFile: '$(Build.ArtifactStagingDirectory)/myfunction.zip'
[Azure側作業]Azure Pipeline手動実行
手動でPipelineを実行してみると無事正常に終了しました。
AWS Lambdaコンソールから対象のLambda関数を確認すると最終更新項目が変更されていることがわかります。
CloudTrailからログを確認してみると、aws-vsts-toolsというユーザーでUpdateFunctionCodeイベントが記録されていることがわかります。
20241009追記
単一のAzure DevOps Organizationで複数のデプロイに利用するIAMロールを使い分けたいとなった場合、ID Providerに紐付けた新しいIAMロールを作成することで使い分けが可能です。
具体的には、IAMロール作成時に信頼ポリシーの「"<id-provider>:sub": "sc://<organization-name>/<project-name>/<service-connection-name>"」の部分を対象のAzure DevOpsのプロジェクト名、サービスコネクション名に変更します。
その後Azure DevOpsのProject Settingsから新しいサービスコネクションを作成します。
最後にAzure Pipelineファイルの「awsCredentials」パラメータで作成したサービスコネクション名を指定します。
Azure Pipelineを実行して、CloudTrailからイベントを確認すると、新しく作成したIAMロールでデプロイされていることが確認できます。
以上のように実装することで、単一のAzure DevOps Organizationで複数のIAMロールを使い分けることが可能です。
複数のAzure DevOps Organizationを利用する場合は、Organization毎にAWS側のIAM ID Providerの作成が必要になるので、その点だけご注意ください。
おわりに
本記事の構成ではIAMユーザーを利用しないAzureからのデプロイを試してみました。
冒頭でも少し書きましたが、アクセスキー・シークレットアクセスキーを利用するとキーローテーション作業や管理作業、払い出しから削除フロー等の様々な運用作業やセキュリティ漏洩のリスク等も発生してしまうので、可能であれば極力使わない方が良いです。
GitHubやTerraform Cloudを利用できるならOIDC認証も利用できるので問題ないかと思いますが、最近AWS CodeCommitの新規受付を停止されたことでAWS以外のコード管理サービスとデプロイパイプラインサービスを検討していて、かつ現在Microsoft AzureとAWSのどちらも利用されている環境であれば一度検討してみても良いのではないかと思います。
最後に余談ですが、前回の記事を書いたときもそうでしたが、Azure-AWS間の連携構成だと日本語の記事はほとんど見つからず、どうしても海外の記事を漁るしかないので中々つらいところがあります。
だからこそ、こうして日本語の記事を書いているのですが、もっと日本語記事が増えないかなぁと常日頃から思ってるので、興味がある方が入れば是非書いてもらえると嬉しいです。
この記事がどなたかの参考になれば幸いです。