Azure DevOps サービスコネクション周りのハマりどころ

# はじめに
今回は、Azure DevOpsのパイプライン実行に必要な「サービスコネクション」に関するハマりどころを書きました。個人の備忘として書いているので汎用性は低いと思いますが、同じ悩みを持っている方がいたら参考になれば幸いです。

# Azure DevOps のサービスコネクションとは

私が関わっているシステムでは、Azure DevOps のパイプラインから、Azure上のAppServiceにアプリデプロイする運用を行っています。この際、パイプラインからAppServiceに向けて更新操作できるようにするため、DevOps上で「サービスコネクション」というオブジェクトを作成する必要があります。「サービスコネクション」はDevOpsのパイプラインからAzureリソースを含めた様々な外部サービスに接続するためのインターフェイスです。

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

## サービスコネクションの実体

サービスコネクションの実体は __AzureADアプリ__ です。サービスコネクションを作成すると、操作対象の環境にAzureADアプリが作成されます。そして、AzureADアプリのサービスプリンシパルが対象のサブスクリプションもしくはリソースグループに付与されるため、結果、配下のAzureリソースに向けた更新ができるようになります。

![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/5266090a-40c1-8548-a58d-a817e9424fa9.png)

## サービスコネクションの作り方（同一テナント）

Azure DevOpsの環境と操作対象のAzure環境が同一AADテナントである場合、サービスコネクションはとても簡単に作成することができます。サービスコネクションの作成方法について紹介します。

__1. サービスコネクション作成画面に進みます。__
Azure DevOpsポータルから、<プロジェクト名>→[Project Settings]→[Service connections]に進み、[New-service connection]を押下します。

![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/f81e5347-1be9-ddee-00e4-4cdbf6f46065.png)

__2. どのサービスに接続するかを選択します。__
今回はAzureリソースへの操作を行うため、「Azure Resoure Manager」を選択し、[Next]に進みます。

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/b3573462-caf2-b16f-594b-9bcf100e2d18.png)

__3. 認証方式を選択します。__
”推奨”とされている「Service Principal (automatic)」を選択し、[Next]に進みます。

![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/f2e3f32c-c3ff-0f4a-02a1-639528ab566b.png)

__4. どの環境に対するサービスコネクションかを設定します。__
操作しているDevOpsアカウントが権限を有するAzure環境が選択可能です。（(リソースグループまで選択可能）
「Grant access permission to all pipelines」にチェックし、[Save]に進みます。

![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/fa223508-e159-044d-b5c1-9ba932d85d7b.png)

すると[Save]ボタンあたりが下記のようになりまして、、、

![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/23db5e83-f8b3-5afb-18b1-91c3c877eb85.png)

サービスコネクションの一覧に追加されました！

![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/0b426b82-7f0e-1fe3-aa55-4e9ad3245dc3.png)


先の説明で、サービスコネクションの実体は　__AzureAアプリ__ と書きました。見てみましょう。操作対象となるAzure環境の[Azure Active Directory]→[アプリの登録]→[すべてのアプリケーション]に進むと出てきます。名前の先頭（青字部分）がDevOpsの組織名、次（緑字部分）がプロジェクト名です。残りの文字列は自動で付与されます。

![8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/1a7ff7c0-2c78-aedf-37c5-81b9402695c7.png)

そしてリソースグループへのロールも自動で付与されます。デフォルトで __「共同作成者」__ が設定されます。

同一テナントの場合はこの作り方で作業は完了です。

## サービスコネクション作成で気にしておくこと
サービスコネクションを作成するためには様々な権限が必要です。サービスコネクション自体を作成する権限も当然必要ですが、その他にAzureADアプリを作成する権限とAzureリソースのRBAC操作できる権限が必要です。設定箇所もバラバラですので注意してください。

#### ■ サービスコネクションが作成可能な権限
こちらはAzure DevOps側の設定になります。ロールとスコープが複雑ですのでご注意ください。ユーザレベルでは __Endpoint Creatorロール__ を持っていればよいですが、組織スコープかプロジェクトスコープか運用に合わせて設定しましょう。詳細は下記サイトを参照ください。（組織管理者やプロジェクト管理者が使えるならそれが一番楽です。）

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

#### ■ AzureADアプリを作成可能な権限
上記に加えて、AzureAD側ではAzureADアプリが作成できるディレクトリロールを付与しておく必要があります。 __グローバル管理者__ 、または、 __アプリケーション管理者__ になるかと思います。

#### ■ AzureリソースにRBAC設定可能な権限
さらに、Auzre側では、RBAC操作が可能な権限を付与しておく必要があります。RBACは共同作成者でも設定することができないため、 __所有者__ 相当の権限が必要になります。

ということで、サービスコネクションを作成するには一時的にでも相当協力な権限を持つアカウントを用意する必要があります。通常このようなアカウントは”特権アカウント”として管理されていますので、あらかじめ特権アカウント利用調整を進めておきましょう。


## サービスコネクションの作り方（テナント跨ぎ）

さて、サービスコネクション作成ですが、同一テナントであればそこまで複雑な手順ではありません。しかし、お客様環境によっては、1つのAzure DevOps環境から複数のAzure環境（異なるAzureADテナント）にデプロイをするといったケースもあります。この時、作成手順については同一テナントでの方法と基本的には同じですが、ここがよくハマりますので留意すべき点を挙げていきます。

### ゲストユーザ招待

先にも書いた通り、サービスコネクションを作成するDevOpsアカウントは、サービスコネクションを作成できる権限に加えて、対象Azure環境側の権限も持っている必要があります。そのため、DevOpsアカウントを対象Azure環境にゲストユーザとして登録し、対象Azure環境側の権限をつけることになります。
![9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/751837f3-5e30-0e5d-239d-f36951d02ed8.png)
※逆に対象Azure環境側の高権限アカウントをDevOps側の環境にゲスト招待する方法でも良いと思います。

#### Tips1：ゲストユーザ招待の承諾操作

ゲストユーザの招待は、対象Azure環境側のAzureADで招待操作を行うだけですが、招待された後は、DevOpsアカウントの方で招待の受け入れ（承諾）をする必要があります。通常ゲストユーザの招待を行うと、そのゲストユーザのメールアドレスに招待用URLが送られるのですが、必ずしも有効なメールアドレスが登録されている訳ではありません。この場合URLは不明なままです。~~（以前はゲストユーザのプロフィール画面から招待リンクを取得することができましたが、現在その機能は使えません。）~~（2023/03/31削除）

そんな時は、
__https://portal.azure.com/<招待先のテナントID>__
というURLでアクセスしましょう。そして、ゲストユーザのアカウントでサインインをすると承認ページにリダイレクトされ、承認することができます。（この画面がでればOKです！）

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/0d6785e9-54fe-b4a1-6fcc-8260596ff19b.png)

（2023/03/31追記）招待用URLですが、ポータルから取得することができました。招待したユーザの概要画面にある「B2Bコラボレーション」の「招待の再送信」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/3ac3b3a6-6908-e08b-d109-695e2786d81c.png)
すると、「招待の再送信」というダイアログが出るので、ここで「再送信」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/bc73bb94-8d64-ef32-d0f7-748e4147cb13.png)

すると再度招待メールが送信されますが、あわせて「受入URLのコピー」というダイアログがでてきます。ここから招待用URLを取得することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/18ebd5c8-aea8-56bb-1687-303936b72c51.png)

（2023/03/31ここまで）

### ゲストユーザへの権限付与

ゲストユーザには、先に説明した下記のAzure環境側の権限を付与する必要があります。ゲストユーザに付与する権限としては極めて高権限ですが、ここは割り切って付与するしかありません。

__■ AzureADアプリの作成ができる権限__
__■ AzureリソースのRBAC操作ができる権限__




### サービスコネクションの作成

サービスコネクションの作成手順については同一テナントの作成手順を変わりません。しかし、同一テナントの時とは異なる点としてサービスコネクション作成画面で、子ウィンドウが立ち上がりAzureログオンを要求されます。これは、対象Azure環境の権限を改めて確認するためのものと思われますが、この認証がとにかく曲者です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/e1424de8-0b0c-1120-48e4-8bb2a2ba9d2c.png)


#### Tips2：ポップアップブロック
意外に盲点なのが、この子ウィンドウがブラウザのポップアップブロックに引っ掛かり表示されないことです。「変だ変だ」と色々調べていたら、実はブラウザのアドレスバーの右あたりが赤くなっていた。みたいなオチを喰らうことがあります。ここを開くと”ポップアップがブロックされました”というポップアップがでますので、「常に許可」の方を選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/cf5eb27d-25d8-694b-415d-9e8034e3596e.png)

#### Tips3：サインイン認証後の404エラー
子ウィンドウで認証情報を入力してサインインすると、404エラー画面になることがあります。この原因は特定できないのですが、ゲストユーザの招待と承諾が上手くいっていないか、権限不足、あとは後述するブラウザのキャッシュが悪さしている可能性があります。落ち着いて手順を見直し、リトライしましょう。（私は以前ここで詰まってMS問い合わせしましたが、時間だけかかって結局原因が分からず仕舞いでした。）
上手く認証が通れば、子ウィンドウが閉じられ、サービスコネクション作成画面から対象のAzure環境が参照できるようになります。
![子ウィンドウログオン後エラー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/865dbc33-8d52-aa72-1024-e74f7c7cd764.png)

#### Tips4：ブラウザのキャッシュ問題

一番ハマるのがブラウザのキャッシュです。このあたりの操作をする際、DevOpsアカウントのセッションやAzureのセッション（ついでに言うと業務で使っているO365のセッション）というように複数のセッションが混在していることがあります。これが悪さをして、エラーメッセージがでる、うまく子ウィンドウが開かない、等々想定外の挙動となります。

これまでにこの操作で何度もハマリましたが、大体の原因はこのセッション問題だったと思います。（原因不明だがリトライしたらできた、みたいなことがよくありました。）

リトライの際には、以下を試してみてください。
* __認証済みのセッションがあればブラウザを閉じる前に明示的にサインアウトする__
* __全てのブラウザを閉じる__
* __InPrivate または シークレットモードでブラウザーを開き１からリトライする__

### サービスコネクション更新時の留意点
サービスコネクションはAzureADアプリなので __2年__ というシークレット有効期限があります。隔年作業になりますがこのシークレットを更新する必要があります。更新操作としては、まず既存のサービスコネクションを選択して[Edit]に進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/b0cbdccf-925e-7315-91e3-4ea7405f58f8.png)

続いて[Verify]を押して、問題なければ[Save]押せばOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/fd0ad82c-cc3a-09fd-6a9f-42b8f56a55d2.png)

ただ、この時も先に書いたようなトラブルが発生することがあります。（キャプチャ取れていませんが、）過去にはこのようなエラーメッセージが出ることがありました。この点についてもやはり原因は権限の問題やブラウザキャッシュの問題と思われますので、エラーが出た場合は落ち着いて設定・手順を再確認しリトライするようにしましょう。
__tf400898: an internal error occurred. activity id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.__

また、サービスコネクションの更新ですが、__うまく更新ができても何も出ません。__ そのため、AzureADアプリの方に進みシークレットが2年延長されたことを確認するようにしましょう。

### サービスコネクション削除時の留意点
使わなくなったサービスコネクションはDevOps側から削除することができます。既存のサービスコネクションを選択して[Edit]の隣にある3点のアイコンをクリックするとコンテキストメニューがでますので、ここから[Delete]を選択すればOKです。ここも権限次第だと思いますが、上手くいけば、サービスコネクション、AzureADアプリ、Azureロールの全てを削除することが可能です。権限不足の場合の挙動は試せていませんが、もしサービスコネクションが削除できたとしても、AzureADアプリやAzureロールは残ったままである可能性があるので、よく確認するようにしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/bcf18c99-6365-8ad2-9ba4-f8cd75d0ac5e.png)

## MSのトラブルシューティングサイト

この辺りのトラブルが沢山あったのか、今ではMSの方でトラブルシューティングを公開しています。上記Tips以外にも確認すべき設定が解説されているので是非ご一読ください！（これが当時からあれば、、私の苦労は・・・）

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/release/azure-rm-endpoint?view=azure-devops

# おわりに
今回はサービスコネクションにまつわる知見やハマりどころについて紹介しました。特にAzureADテナントを跨ぐ場合はよくよく手順を確認してミスのないようにすると共に、もしエラーが発生しても落ち着いてリトライするように心がけましょう。それでは！