Azure Pipelinesから別組織のAzure ReposをPATなしでチェックアウトする方法

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のユーザーとして追加します。

別組織のリポジトリへアクセスする構成では、少なくとも次の登録と権限設定を確認します。

  1. パイプライン側のAzure DevOps組織へIDを追加する
  2. 参照先のAzure DevOps組織へ同じIDを追加する
  3. 参照先プロジェクトへアクセスできるようにする
  4. 対象リポジトリの読み取り権限を付与する

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 namemy-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の各項目が意味するもの

項目役割設定例
repositoryYAML内で使用するリポジトリの別名external-repo
typeリポジトリの種類git
endpointAzure 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 ManagerAzureサブスクリプション内のリソースへデプロイ
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と表示される

認証エラーの場合は、次の順序で確認すると原因を切り分けやすくなります。

  1. YAMLのendpointが実際のサービス接続名と一致しているか
  2. サービス接続に設定した対象組織名が正しいか
  3. IDが対象組織へ追加されているか
  4. IDが対象プロジェクトへアクセスできるか
  5. 対象リポジトリの読み取り権限があるか
  6. サービス接続をパイプラインが使用できるか
  7. 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なしでチェックアウトするには、次の順序で構成します。

  1. Microsoft EntraでサービスプリンシパルまたはマネージドIDを用意する
  2. IDをパイプライン側と対象側のAzure DevOps組織へ追加する
  3. 対象プロジェクトとリポジトリの読み取り権限を付与する
  4. Azure DevOps (preview)サービス接続を作成する
  5. FICを自動作成できない場合は、IssuerとSubjectを使って管理者が手動作成する
  6. YAMLのresources.repositoriesへ外部リポジトリを定義する
  7. 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”

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次