Azure Pipelinesから別のAzure DevOps組織にあるAzure Reposを取得するために、PATをシークレット変数へ保存する必要はありません。同じMicrosoft Entraテナントに接続されたAzure DevOps Services組織であれば、Azure DevOps (preview)サービス接続と、サービスプリンシパルまたはマネージドIDを使用してチェックアウトできます。
ただし、サービス接続を作成するだけでは動作しません。先にMicrosoft Entra ID上でIDを用意し、そのIDを対象のAzure DevOps組織へユーザーとして追加したうえで、プロジェクトやリポジトリの読み取り権限を付与する必要があります。サービス接続の作成画面が、IDやAzure DevOpsユーザーを自動作成するわけではない点が重要です。([Microsoft for Developers][1])
Azure Pipelinesから別組織のAzure ReposをPATなしでチェックアウトできる仕組み
今回使用するのは、Azure DevOps Services向けの新しいサービス接続です。
このサービス接続は、Microsoft EntraのワークロードIDとして次のいずれかを使用します。
- サービスプリンシパル
- マネージドID
Azure Pipelinesは、サービス接続を通じてMicrosoft Entra認証を行い、そのIDに付与されたAzure DevOps上の権限で、別組織のリポジトリへアクセスします。
処理の流れは次のとおりです。
Azure Pipeline
↓
Azure DevOps (preview) サービス接続
↓
Microsoft Entra ワークロードID
↓
対象Azure DevOps組織のユーザー・権限
↓
別組織のAzure Repos
従来のようにPATを発行し、パイプラインのシークレット変数へ登録して、有効期限ごとに更新する必要がありません。フェデレーション資格情報を使うため、永続的なパスワードやPATをパイプラインへ保持せずに認証できます。認証試行はAzure DevOpsの監査ログにも記録されます。([Microsoft for Developers][1])
利用できる条件
この方法は、すべてのAzure DevOps環境で無条件に使えるわけではありません。
| 確認項目 | 必要な条件 |
|---|---|
| サービス | Azure DevOps Services |
| 組織間の関係 | 同じMicrosoft Entraテナントに接続されている |
| 認証ID | サービスプリンシパルまたはマネージドID |
| Azure DevOpsへの登録 | 認証IDをAzure DevOps組織のユーザーとして追加済み |
| リポジトリ権限 | 対象プロジェクト・リポジトリを読み取れる |
| サービス接続の権限 | 作成元プロジェクトでサービス接続を作成できる |
| 接続種別 | Azure DevOps (preview) |
別組織のリソースへアクセスする場合、認証に使うIDを対象組織へ明示的に追加する必要があります。Microsoft Entraにサービスプリンシパルが存在していても、それだけでAzure DevOps組織へアクセスできるようにはなりません。Azure DevOpsでは、Microsoft Entraのアプリケーション権限ではなく、Azure DevOps独自の権限設定が適用されます。([Microsoft Learn][2])
なお、異なるMicrosoft Entraテナントに属する組織へ、この構成のまま無条件にアクセスできるわけではありません。本記事で扱うのは、同一Entraテナント内の別Azure DevOps組織です。
構成に必要なもの
例として、次の構成を使用します。
| 項目 | 設定例 |
|---|---|
| パイプラインを実行する組織 | contoso-build |
| 参照先の組織 | contoso-source |
| 参照先プロジェクト | external-project |
| 参照先リポジトリ | external-repo |
| サービス接続名 | my-azdo-connection |
| ブランチ | main |
| YAML内のリポジトリエイリアス | external-repo |
YAMLのendpointには参照先組織のURLではなく、作成したAzure DevOpsサービス接続名を指定します。
Microsoft Entraで認証用IDを用意する
最初に、次のいずれかを用意します。
サービスプリンシパルを使う場合
Microsoft Entra IDでアプリを登録し、そのアプリに対応するサービスプリンシパルを使用します。
Azure DevOpsへ追加するときは、アプリ登録画面のアプリケーションオブジェクトIDではなく、Microsoft Entra管理センターの「エンタープライズアプリケーション」で確認できるサービスプリンシパルのオブジェクトIDを使用する点に注意してください。([Microsoft Learn][3])
サービスプリンシパルは、パイプライン専用のIDを組織的に管理したい場合に適しています。
マネージドIDを使う場合
Azure上に作成したユーザー割り当てマネージドIDなどを使用できます。
マネージドIDはAzure側でライフサイクルや資格情報を管理できるため、既にAzureリソース用のID管理基盤がある環境で使いやすい選択肢です。
どちらを選んだ場合も、サービス接続の作成画面がIDを新規作成するわけではありません。サービス接続を作る前にIDを用意しておく必要があります。([Microsoft for Developers][1])
認証用IDをAzure DevOps組織へ追加する
IDを作成したら、Azure DevOpsのユーザーとして追加します。
別組織のリポジトリへアクセスする構成では、少なくとも次の登録と権限設定を確認します。
- パイプライン側のAzure DevOps組織へIDを追加する
- 参照先のAzure DevOps組織へ同じIDを追加する
- 参照先プロジェクトへアクセスできるようにする
- 対象リポジトリの読み取り権限を付与する
Azure DevOpsポータルでは、対象組織の次の画面から追加します。
Organization settings
→ Users
→ Add users
追加するIDには、用途に合ったアクセスレベルとプロジェクトアクセスを設定します。Microsoftの構成例では、標準アクセスとしてBasicを選び、必要なプロジェクトのReadersグループなどへ追加しています。必要以上のプロジェクトやリポジトリへアクセスさせず、対象を限定するのが安全です。([Microsoft Learn][2])
リポジトリ権限で確認する項目
チェックアウトだけが目的なら、対象リポジトリを読み取れることが最低条件です。
次のような過剰な権限は、通常のチェックアウトには必要ありません。
- ブランチへの書き込み
- Pull Requestの作成
- リポジトリの削除
- Force push
- プロジェクト管理
サービスプリンシパルやマネージドIDを管理者グループへ追加するのではなく、対象プロジェクトのReadersグループや、対象リポジトリへの個別権限で最小化します。
Azure DevOpsサービス接続を作成する
認証用IDをAzure DevOpsへ追加したら、パイプラインを管理しているプロジェクトでサービス接続を作成します。
Project settings
→ Service connections
→ New service connection
→ Azure DevOps (preview)
作成画面では、事前に用意したサービスプリンシパルまたはマネージドIDを選択します。
別組織へ接続する場合は、画面上で別組織を指定する選択肢を選び、対象のAzure DevOps組織名を入力します。サービス接続名には、YAMLから参照しやすい分かりやすい名前を付けます。
設定例は次のとおりです。
| 設定項目 | 設定例 |
|---|---|
| 接続種別 | Azure DevOps (preview) |
| 接続先 | 別のAzure DevOps組織 |
| 対象組織 | contoso-source |
| Identity | 事前作成したサービスプリンシパルまたはマネージドID |
| Service connection name | my-azdo-connection |
作成元プロジェクトでは、サービス接続のCreatorまたはAdministrator相当の権限が必要です。初期状態では、Endpoint Creatorsグループのメンバーに作成権限が付与されます。([Microsoft Learn][2])
サービス接続の利用許可も確認する
サービス接続を作成できても、パイプラインから使用する許可がなければ実行時に停止することがあります。
運用方法は次のどちらかです。
- 対象パイプラインだけにサービス接続の利用を許可する
- すべてのパイプラインからの利用を許可する
安全性を優先するなら、対象パイプラインへ限定して許可します。複数の組織やプロジェクトで同じ接続を使い回すより、用途や接続先ごとにサービス接続を分ける方が、権限範囲と監査対象を明確にできます。Microsoftも、プロジェクトや組織ごとに接続を分ける運用を推奨しています。([Microsoft Learn][2])
FICを自動作成できない場合の対応
サービス接続では、Microsoft Entraのフェデレーション資格情報、FICを使用します。
通常はサービス接続の作成処理で構成されますが、操作しているユーザーに必要なMicrosoft Graph権限や対象IDの管理権限がない場合、自動作成に失敗することがあります。
その場合、作成画面に次の値が表示されます。
- Issuer
- SubjectまたはSubject Identifier
表示された値を、対象サービスプリンシパルまたはマネージドIDを管理できる管理者へ渡します。管理者が対象IDへフェデレーション資格情報を手動で追加したあと、サービス接続の作成を完了します。
権限不足時には、サービス接続が下書きとして保存され、IDの所有者へIssuerとSubject Identifierを渡すよう案内される場合があります。([Microsoft for Developers][1])
IssuerとSubjectは書き換えない
FICを手動作成するときは、サービス接続画面に表示されたIssuerとSubjectを正確に使用します。
次のような変更を加えると、Microsoft Entra側のフェデレーション資格情報とAzure DevOpsが発行する情報が一致せず、認証に失敗します。
- 組織名を推測して書き換える
- プロジェクト名を手入力で変更する
- サービス接続名を作成後に変更する
- 末尾の記号や大文字・小文字を変更する
組織、プロジェクト、サービス接続を改名した場合も、FIC側のSubjectとの不一致が起きる可能性があります。AADSTS70021やAADSTS700213が表示された場合は、IssuerとSubjectの一致を確認します。([Microsoft Learn][2])
YAMLで別組織のAzure Reposを指定する
サービス接続を作成したら、パイプラインYAMLのresources.repositoriesへ外部リポジトリを定義します。
resources:
repositories:
- repository: external-repo
type: git
endpoint: my-azdo-connection
name: 'external-project/external-repo'
ref: 'refs/heads/main'
steps:
- checkout: self
- checkout: external-repo
このYAMLでは、現在のパイプラインを保持しているリポジトリと、別組織のリポジトリの両方をチェックアウトします。別組織への接続情報は、endpointで指定したサービス接続から取得されます。([Microsoft for Developers][1])
YAMLの各項目が意味するもの
| 項目 | 役割 | 設定例 |
|---|---|---|
repository | YAML内で使用するリポジトリの別名 | external-repo |
type | リポジトリの種類 | git |
endpoint | Azure DevOpsサービス接続名 | my-azdo-connection |
name | 対象のプロジェクト名とリポジトリ名 | external-project/external-repo |
ref | チェックアウトするブランチやタグ | refs/heads/main |
checkout | 取得するリポジトリエイリアス | external-repo |
repositoryはYAML内の別名
次のrepositoryは、実際のAzure Repos名を直接指定する項目ではありません。
repository: external-repo
これは、後続のcheckoutなどから参照するためのエイリアスです。
そのため、次の値を一致させます。
repository: external-repo
- checkout: external-repo
実際のプロジェクト名とリポジトリ名は、nameへ指定します。
endpointはサービス接続名
endpointへ指定するのは、Azure DevOps組織名やURLではありません。
endpoint: my-azdo-connection
ここには、Project settingsのService connectionsで作成したAzure DevOpsサービス接続名を指定します。
次のような値を指定しても動作しません。
endpoint: https://dev.azure.com/contoso-source
endpoint: contoso-source
YAMLのサービス接続名と、Azure DevOps上の実際のサービス接続名が完全に一致しているか確認してください。
nameはプロジェクト名とリポジトリ名
nameには、対象組織内のプロジェクトとリポジトリを次の形式で指定します。
name: 'プロジェクト名/リポジトリ名'
今回の例では次のとおりです。
name: 'external-project/external-repo'
組織名は含めません。接続先の組織は、endpointで参照するサービス接続側に設定されています。
refは完全な参照名で指定する
mainブランチを指定する場合は、次のように完全な参照名を使用します。
ref: 'refs/heads/main'
タグを指定する構成では、通常は次の形式になります。
ref: 'refs/tags/v1.0.0'
ブランチ名やタグ名を取り違えると、認証が成功していてもチェックアウト対象を見つけられません。
Azure DevOps接続とAzure Resource Manager接続を混同しない
Azure DevOpsのサービス接続には複数の種類があります。
今回使用するのは、AzureサブスクリプションへデプロイするためのAzure Resource Manager接続ではありません。
| 接続種別 | 主な用途 |
|---|---|
Azure DevOps (preview) | Azure Repos、Azure Artifacts、Azure DevOps REST APIなどへのアクセス |
| Azure Resource Manager | Azureサブスクリプション内のリソースへデプロイ |
| Genericなどの汎用接続 | URLや資格情報を個別に設定する外部サービス接続 |
別組織のAzure Reposをresources.repositoriesから参照する場合、endpointにはAzure DevOps (preview)として作成した接続を指定します。
Azure Resource Manager接続を既に持っていても、それを今回のendpointとして流用する構成ではありません。
PATを使う構成との違い
| 比較項目 | PATを使う構成 | Azure DevOpsサービス接続 |
|---|---|---|
| 認証主体 | 通常はPATを発行したユーザー | サービスプリンシパルまたはマネージドID |
| シークレット保存 | PATの保存が必要 | PATの保存は不要 |
| 更新作業 | 有効期限ごとに更新 | フェデレーション認証を利用 |
| 個人への依存 | 発行者の異動・退職の影響を受けやすい | パイプライン用IDとして分離可能 |
| 権限管理 | PATのスコープとユーザー権限 | Azure DevOps上のID権限 |
| 監査 | PATの所有者を中心に確認 | サービス接続とワークロードIDを追跡可能 |
PATを使わない最大の利点は、単にシークレット変数を一つ減らせることではありません。
パイプラインの認証主体を個人ユーザーから分離し、対象プロジェクトやリポジトリだけに権限を限定できます。PATの作成、保管、失効、更新漏れといった運用作業も減らせます。([Microsoft for Developers][1])
チェックアウトできないときの確認ポイント
Azure DevOpsサービス接続を選択できない
サービス接続の一覧にAzure DevOps (preview)が表示されない場合は、次を確認します。
- Azure DevOps Servicesを利用しているか
- 対象プロジェクトで機能が利用可能になっているか
- サービス接続を作成する権限があるか
- プレビュー機能の展開状況に差がないか
この接続はプレビューとして提供されているため、画面表示や利用可否が組織ごとに異なる可能性があります。Microsoftのドキュメントでも段階的な展開について案内されています。([Microsoft Learn][2])
サービス接続の作成に失敗する
次を確認します。
- サービスプリンシパルまたはマネージドIDが存在する
- IDがAzure DevOps組織のユーザーとして追加されている
- 操作ユーザーにサービス接続の作成権限がある
- 対象IDを選択できる権限がある
- 必要なFICが作成されている
サービス接続の作成画面は、Microsoft EntraのIDやAzure DevOpsユーザーを自動作成しません。先にIDとユーザー登録を完了しておく必要があります。([Microsoft for Developers][1])
Pipeline fails to authenticateと表示される
認証エラーの場合は、次の順序で確認すると原因を切り分けやすくなります。
- YAMLの
endpointが実際のサービス接続名と一致しているか - サービス接続に設定した対象組織名が正しいか
- IDが対象組織へ追加されているか
- IDが対象プロジェクトへアクセスできるか
- 対象リポジトリの読み取り権限があるか
- サービス接続をパイプラインが使用できるか
- Azure DevOpsの監査ログに認証失敗が記録されていないか
Microsoftのトラブルシューティングでも、サービス接続名の不一致と、対象リソースへの権限不足が主な確認項目として挙げられています。([Microsoft Learn][2])
TF401444が表示される
次のようなエラーは、認証用IDがAzure DevOps組織のユーザーとして正しく追加されていない場合に発生します。
TF401444: Please sign-in at least once ...
サービスプリンシパルまたはマネージドIDを、対象組織のOrganization settingsから追加したか確認します。Microsoft Entraのセキュリティグループへ追加しただけでは、Azure DevOps組織へのアクセスが自動的に付与されるとは限りません。([Microsoft Learn][2])
VS800075が表示される
次のエラーは、IDが対象プロジェクトへ追加されていないか、プロジェクトを参照する権限がない場合に発生します。
VS800075: The project ... does not exist,
or you do not have permission to access it.
対象IDをプロジェクトのReadersグループへ追加するか、必要なプロジェクトアクセスを付与します。組織へユーザー登録しただけでは、すべてのプロジェクトを自動的に参照できるわけではありません。([Microsoft Learn][2])
AADSTS70021などが表示される
次を確認します。
- FICが対象IDに作成されているか
- Issuerがサービス接続画面の値と一致しているか
- Subjectが完全に一致しているか
- サービス接続、組織、プロジェクトを作成後に改名していないか
- FICを別のサービスプリンシパルへ作成していないか
FICの値を推測して作るのではなく、サービス接続画面に表示されたIssuerとSubjectを使用してください。([Microsoft Learn][2])
安全に運用するためのポイント
パイプライン専用のIDを使用する
既存アプリのサービスプリンシパルを安易に流用すると、Azure DevOps以外の用途と権限が混在します。
可能であれば、次の単位でIDやサービス接続を分けます。
- 接続先のAzure DevOps組織
- 利用するプロジェクト
- 本番用と検証用
- 読み取り専用と更新を伴う処理
障害発生時の影響範囲を限定でき、不要になった接続だけを停止しやすくなります。
リポジトリ読み取り権限に限定する
チェックアウトだけが目的なら、書き込み権限を付けないことが基本です。
将来、タグ作成やブランチ更新が必要になった場合も、最初から広い権限を与えるのではなく、必要になった操作だけを追加します。
サービス接続の名前で用途を判断できるようにする
connection1のような名前では、YAMLや監査ログから用途を判断できません。
例えば、次のように接続先と用途を含めます。
azdo-contoso-source-repo-read
これにより、次の情報を名前から判断できます。
- Azure DevOps向けの接続
- 接続先組織
- リポジトリアクセス用
- 読み取り専用
プレビュー機能として変更を追跡する
接続種別はAzure DevOps (preview)です。
正式提供までに、画面表示、作成手順、対応タスク、必要権限などが変更される可能性があります。本番運用へ組み込む場合は、サービス接続の状態とMicrosoftの公式ドキュメントを定期的に確認してください。
PATなしで別組織のAzure Reposを取得する手順のまとめ
Azure Pipelinesから別組織のAzure ReposをPATなしでチェックアウトするには、次の順序で構成します。
- Microsoft EntraでサービスプリンシパルまたはマネージドIDを用意する
- IDをパイプライン側と対象側のAzure DevOps組織へ追加する
- 対象プロジェクトとリポジトリの読み取り権限を付与する
Azure DevOps (preview)サービス接続を作成する- FICを自動作成できない場合は、IssuerとSubjectを使って管理者が手動作成する
- YAMLの
resources.repositoriesへ外部リポジトリを定義する checkout: external-repoでチェックアウトする
YAMLで特に間違えやすいのは、endpointとnameの役割です。
endpoint: my-azdo-connection
name: 'external-project/external-repo'
endpointはAzure DevOpsサービス接続名、nameは対象プロジェクトとリポジトリ名です。
最初にYAMLを変更するのではなく、認証用IDの作成、Azure DevOpsへのユーザー追加、リポジトリ権限、サービス接続の順に構成してください。この順番で進めることで、認証エラーと権限エラーを切り分けやすくなります。
[1]: https://devblogs.microsoft.com/devops/you-can-now-use-the-azure-devops-service-connection-instead-of-a-pat-or-build-session-token/ “You can now use the Azure DevOps Service Connection instead of a PAT or Build Session token – Azure DevOps Blog”
[2]: https://learn.microsoft.com/azure/devops/pipelines/library/add-devops-entra-service-connection?view=azure-devops “Access Azure DevOps with Microsoft Entra workload identity – Azure Pipelines | Microsoft Learn”
[3]: https://learn.microsoft.com/azure/devops/integrate/get-started/authentication/service-principal-managed-identity “Use Service Principals and Managed Identities – Azure DevOps | Microsoft Learn”

コメント