🍂

Azure DevOpsでサービスコネクションを作ってAzureテナントを跨いでAzureのリソースを使用する

2023/11/13に公開
1

テナントを跨いでAzure DevOpsからAzureのリソースにアクセスしたい

Azure DevOpsでサービスコネクションを作ってAzureテナントを跨いでサービスプリンシパルを使用する方法を紹介します。

こんな感じでソースコードを管理しているAzure DevOpsをホストしているAzureテナントと、Azureのリソースを管理しているテナントが違うのでコンテナアプリのデプロイができなかったりCD piepleineが作れなくて困ってる(´;ω;`)というご相談を頂きました。

  • ソースコードを管理しているAzure DevOpsのProject Alpha, BravoはテナントAというAzureのテナントでホストされている
  • Azure DevOps以外のAzureリソースはテナントBという別のAzureのテナントでホストされている
  • テナントAでは色んな事情で権限がなくて、サービスプリンシパルが作れない。
  • ソースコード管理&コラボレーションをしているAzure DevOpsのテナントとAzureリソースを管理&運用しているテナントが違うので、コンテナアプリのリビジョン作成とかデプロイができないとか、CD pipeline作れなくて困ってるのでどうにかしたい

Azure DevOpsでAzureのリソースを使う:同一テナントの場合

Azure DevOpsでAzureのリソースを使用するには、ざっくり以下のようなステップでサービスプリンシパルを作成してAzure DevOpsのpipelineで利用したりすることができます。

  1. Azureでサービスプリンシパルを作成する
  2. Azure DevOpsのOrganization Settingsで作成したサービスプリンシパルをUserとして登録する
  3. Pipelineの中でサービスプリンシパルに対してアクセストークンをリクエストして、そのトークンを使ってサービスプリンシパルが作成されているAzureのリソースにアクセスする

Azure DevOpsでのサービスプリンシパルの利用については、こちらのdocsを参考にして下さい。
https://learn.microsoft.com/ja-jp/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?view=azure-devops

また、こちらの記事ではサービスプリンシパルをAzure DevOpsで利用する方法と、C#でサービスプリンシパルを利用してAzure DevOps REST APIを操作する方法がめちゃくちゃわかりやすく記載されています。
https://zenn.dev/yutakaosada/articles/1a61b2741e0644

※Azureでサービスプリンシパルを作成するには、最低でもEntraの管理者からEntraでのアプリの登録が許可されている必要があります。
アプリの登録と必要な権限に関して、詳細はこちらのdocsをご覧ください。
https://learn.microsoft.com/ja-jp/entra/identity-platform/how-applications-are-added

Azure DevOpsのテナントの向き先を変えてみよう

Azure DevOpsのOrganization Settings > General > Azure Active Directoryにいけば今接続されていAzure ADのテナントの確認と、Swtich directoryで変更ができるので、これでAzure DevOpsをホストしているテナントの向き先を変えればよいのでは?ともなりましたが、今回のご相談では現在のテナントで権限がなくてテナントの向き先変えるのはダメでした。

いっそのことテナントを寄せてしまう?

一番いいのはAzure DevOpsをテナントBに移して、Azureのリソース管理・運用とAzure DevOpsのホストも全部テナントBでやってしまうのが一番構成としてはすっきりしますが、その場合Azure DevOpsの全リソース(ソースコード、Boards、etc...)のお引越しが必要になり、結構大変です。
work itemをお引越しさせるツールはあるものの、結構インパクトが大きい、、、
https://learn.microsoft.com/ja-jp/shows/devops-lab/moving-work-items-around-using-the-azure-devops-migration-tools

サービスコネクションを使ってテナント跨ぎでサービスプリンシパルを使う

今回はこんな感じでサービスコネクションとサービスプリンシパルを作成して、Azure DevOpsでテナントを跨いでテナントBのAzureリソースにアクセスするようにしてみます。

  • Azureのリソース管理・運用を行っているテナントBで、テナントBのAzureリソースにアクセス
    できるサービスプリンシパルを作成
  • テナントAでホストされているAzure DevOpsのProject Alphaで、テナントBのサービスプリンシパルへのサービスコネクションを作成して、それを経由してテナントを跨いでAzureリソースにアクセス

テナントBでサービスプリンシパルを作成する

ではまずAzureのリソース管理・運用をしているテナントBでサービスプリンシパルを作ります。
Azure portalにサインインして、Microsoft Entra IDを選択

左メニューで「アプリの登録」を選択

「アプリケーションの登録」で「名前」でサービスプリンシパルの名称を入力して、「登録」を押下

サービスプリンシパルができます。
「証明書とシークレット」を選択して、このサービスプリンシパルを使用するためのシークレットを定義します。

「クライアントシークレット」を選択して、「新しいクライアントシークレット」を選択

クライアントシークレットの説明と有効期限を設定して「追加」を押下
※Max2年まで設定可能

クライアントシークレットが作成される。
この「値」をシークレットキーとしてAzure DevOpsでサービスコネクションを作成する際に使用するので、コピーして大事に保存してください。

アクセス許可を設定する

作成したサービスプリンシパルにリソースへのアクセス許可を与えます。
サービスプリンシパルの「APIのアクセス許可」にいって、「アクセス許可の追加」を選択します。

「APIアクセス許可の要求」で使用したいリソースへのアクセス許可を構成します。

これで、サービスプリンシパルに対してリソースのアクセス許可を与えることができます。

サブスクリプションにサービスプリンシパルに対する使用権限を与える

サービスプリンシパルを作成したので、それを使えるようにサブスクリプションに対して権限を与えてサービスプリンシパルを使用できるようにします。
Azure portal > サブスクリプション > 使用中のサブスクリプションを選択 > アクセス制御(IAM) > ロールの割り当て に移動

「+追加 」から「ロールの割り当て」を選択

「特権管理者ロール」のタブを選択。
ここでの与えるロールは、以下の記事に従って「共同作成者(Contributer)」しておきます。
※サービスプリンシパルにはContributorロールが割り当てられるから、サブスクで権限与える場合もContibutorがいいでしょう


https://stackoverflow.com/questions/44705427/azure-app-service-deployments-minimum-role-for-service-principal-account

「アクセスの割り当て先」で「ユーザー、グループ、またはサービスプリンシパル」を選択

「メンバーを選択」を押下、作成したサービスプリンシパルを検索して選択し、「選択」を押下

「レビューと割り当て」を押下

これでサービスプリンシパルにContributor(共同作成者)のロールの割り当てが完了しました。
このサービスプリンシパルを使うことによって、テナントBのAzureリソースへのアクセスができるようになります。

Other Option: Resource Group単位でサービスプリンシパルに対する権限を与える

Infra Engineerの方から「サブスク単位だと権限が広すぎるのでリソースグループ単位で権限付与はできますか?」というお問い合わせがあったので検証してみました。
サブスク単位ではなくRG単位でロールの割り当てをしたい場合、サブスクにロールを与えたときと同じステップで、対象のリソースグループの「アクセス制御(IAM)」で「ロールの割り当て」を選択して、サービスプリンシパルに共同作成者のロールを与えてください。

Azure DevOpsでARMのサービスコネクションを作成してサービスプリンシパルと接続する

テナントBでのサービスプリンシパルの作成と権限割り当てまでいけたので、テナントAのAzure DevOpsでテナントBに作ったサービスプリンシパルへのサービスコネクションを作成します。

用意するもの:

  1. テナントBで作ったサービスプリンシパルのアプリケーションID
  2. サービスプリンシパルのID
  3. サービスプリンシパルのシークレット(作ったときに大事に保存しないと二度と表示されないやつ)
  4. サービスプリンシパルの作成を行ったAzureのサブスクリプションのIDと名前
  5. テナントBのテナントID

Microsoft Entra > アプリの登録 > すべてのアプリケーション > 作成したサービスプリンシパルを選択。1, 5は概要の箇所で取得できる

2はサービスプリンシパルの 証明書とシークレット> クライアントシークレットの箇所で取得できる。

4はAzure portal > サブスクリプションで、使用中のサブスクリプションを選択すると表示されるのでここから取得

Azure DevOpsのProject Settings > Piepelines > Service Connectionsに移動

New Service Connectionを押下

Azure Resource Managerを選択して次へ

Service principal(manual)を選択して次へ

以下のように設定する

Service connection nameでサービスコネクションの名称を、
Descriptionにサービスコネクションの説明を記載。
全て設定したら、Verifyで接続を検証します。

成功するとこうなります!
verify and Saveで保存してください。

できました。

サービスコネクションの使用

実際テナント跨いでApp Serviceにデプロイの検証、まで行きたかったですが力尽きたのでまた今度、、、<m(__)m>

とりあえずこちらのdocsに使い方が書いてあったので置いておきます
https://learn.microsoft.com/ja-jp/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#use-a-service-connection

こんな感じでサービスコネクション名をpipelineのymlのazureSubscriptionでサービスコネクション名指定して使うみたいです。

ちなみに、サービスプリンシパルを使う場合は、こんな感じでサービスコネクションに対してリクエストを投げて、返ってきたトークンを使うことによってリソースへのアクセスができます。

curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token \ #サービスプリンシパルがいるテナントのIDを指定
-d 'client_id=<client-id>' \ #サービスプリンシパルのIDを指定
-d 'grant_type=client_credentials' \
-d 'scope=2ff814a6-3304-4ab8-85cb-cd0e6f879c1d%2F.default' \
-d 'client_secret=<client-secret>' #サービスプリンシパルのキーを指定

https://learn.microsoft.com/ja-jp/azure/databricks/dev-tools/service-prin-aad-token

これのレスポンスで、こんな感じでaccess_tokenでtokenが返ってくるので、これを使います。

サービスコネクションを作らないでテナント跨いでサービスプリンシパルの使用はできないんですか?

できます。できますが、それをするにはサービスプリンシパルをゲストユーザーとしてAzure DevOpsのOrganizationに追加する必要があります。
(同一テナントでサービスプリンシパルをAzure DevOpsで使用する際にもそうする。このステップによってサービスプリンシパルはmanaged identityとして機能し、Azure上のサービスプリンシパルとAzure DevOpsとの連携が実現される。詳しくはこちらをCheck)
https://devblogs.microsoft.com/devops/introducing-service-principal-and-managed-identity-support-on-azure-devops/

そのためには、両方のテナントでそこそこ強い権限(おそらく最低でもアクセス許可管理の管理者)が必要になります。

別テナントにいるサービスプリンシパルを使って、Azure DevOpsのOrganization/Projectにいるソースの同期はできますか?

この部分ですね。

理論的には、ソースがいるOrganizationにUserとしてサービスプリンシパルを追加することができれば、他のユーザーと同様にAzure DevOpsのアイデンティティとして機能します。
ユーザー追加の際に、Basic、Project Contribuorのアクセス権を与えれば、そのサービスプリンシパルはソースコードへの貢献ができます。

https://learn.microsoft.com/ja-jp/azure/devops/repos/git/set-git-repository-permissions?view=azure-devops

以上のステップで、ユーザー登録の際の権限でもってPAT(Personal Access Token)と同様に同期をすることができるでしょう。
※PATを使ったreposの同期については、過去のこちらの記事を参照してください。
https://zenn.dev/yuriemori/articles/7a6097654f2afc
https://zenn.dev/yuriemori/articles/8e287a1fe1342c

こちらのMSのdevlogで記載されているように、PATには漏洩のリスクや管理のコストがあるため、サービスプリンシパルを用いた認証に移行することをお勧めします。
https://devblogs.microsoft.com/devops/introducing-service-principal-and-managed-identity-support-on-azure-devops/

Additionally, PATs are bearer tokens, which can be leaked easily and fall into the wrong hands. (Remember to always secure your secrets in a key management solution, like Azure Key Vault!) This leaked PAT can then be used to wreak havoc for the remaining duration of the PAT’s lifetime, or until revoked.

テナント跨ぎの場合、別のテナントにいるサービスプリンシパルをそのまま追加することはできないので、上述のようにゲストユーザーとして登録することが必要になります。

結論:Azure-Azure DevOpsのテナント跨ぎはそもそもしんどい

ということがわかりました(´;ω;`)

Azure DevOpsでタスク管理のAzure Boardsとかソースコード管理ツールとしてAzure ReposでRepos作ってSrcバージョン管理してチーム開発できるようにして、、、ぐらいの局面で使ってると意識しないけど、今回のご相談のようにCD pipeline作りたいとか、Application InsightとAzDOを連携してダッシュボードにメトリック構成したいとか、DevOpsのリリース→運用→feedbackの取得 らへんをまじめに考え出すと、Azureと連携したいっていうのは避けられないし、その過程でAzDOとAzureリソース切り離していちいち鍵(認証)ないとアクセスできない、みたいなのはしんどいな、、、と思いました。

というわけで、Azure DevOpsを使って上記のようなことまでやりたいなって場合は、AzureのリソースがいるテナントでAzure DevOpsを作成するのがベストなんだろうなと思います。

To.yutakaosadaさん
検証お手伝いしてくださってありがとうございます!!!

クロステナントの場合のユースケース ※2023/12/11 追記

と書いたものの、Azure-Azure DevOpsで連携する場合、必ずしも同一テナントにするのがべスプラであるというわけでもなく、場合によってはクロステナントで運用することも想定されます。

例えば、

ただ、特にマルチテナント構成にする意図がない場合はAzure, Azure DevOpsは同一テナントで構成するのをおすすめします(今回のようなテナント跨ぎの作業が必要になるので)。

クロステナント構成にした場合、この記事でご紹介したサービスコネクションを使用してみてください。

Other References

https://learn.microsoft.com/ja-jp/azure/devops/release-notes/2023/sprint-228-update#general-1

https://qiita.com/hiro10149084/items/08e579ed5893acf902bc#サービスコネクションの作り方テナント跨ぎ

https://sdpf.ntt.com/docs/solution-guide/rsts/IoT_Device_Automatic/tc_temp/tc_temp_azure_devops_setup.html#/

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml

Discussion