マネージド ID を 使って Azure VM から CLI で Azure を操作する。

こんにちは、アーキテクトのやまぱんです。
補足コメントや質問、<font color="red">いいね</font>は是非お願いします🥺！
間違ってたら<font color="red">優しく</font>教えてください！

今回はマネージド ID を使って、Azure VM 上から Azure を操作してみます。
操作といっても Azure VM の情報を取得するだけです。

# やりたいこと
既に書いた通り、今回はマネージド ID を使って、Azure VM 上から Azure を操作してみます。
具体的には以下の通り
+ Azure VM から Azure を操作する。
+ 具体的な今回の Azure 操作 Azure VM が属するリソースグループのAzure VM 一覧を取得する。
+ Azure PowerShell (Get-AzVM コマンド) と Azure CLI (Az restコマンドによる API リクエスト)をつかう2 種類で実行する。

# そもそもマネージド IDとは
簡単にいうと、「マネージド ID を使うことによって資格情報をハードコーディングする必要がなくなるため、セキュアに Azure にログイン、 Azure リソースを操作することができるようになるモノ」

Azure VM にマネージド IDを付与してそのマネージドに紐づいたサービスプリンシパルに割り当てられた RBAC の権限内で Azure リソースを操作することができます。
⚡再三にはなりますが、スクリプトなどに明示的にパスワードなどを書く必要がありません⚡＜素晴らしい！＞

マネージド ID は Azure Instance Metadata Service や Microsoft Entra ID、サービスプリンシパルの機能によって実現しています。
Azure Instance Metadata Service は Azure 上で リンクローカルアドレス(169.254.169.254)に対して通信することで利用できます。


+ マネージド ID の詳細はこれらの記事をご確認ください。
非常にわかりやすく書かれています。

https://qiita.com/Shinya-Yamaguchi/items/edd75f7ee47471a98670

https://tech-lab.sios.jp/archives/27461


# Azure Instance Metadata Service って？
上記で記載した通り、Azure Instance Metadata Service は 169.254.169.254 に対して通信することで機能が利用できます。
マネージド ID はこの Azure Instance Metadata Service の機能を利用しています。

Azure Instance Metadata Service（IMDS）は、Azure VM（仮想マシン）が自身に関するランタイムデータを取得できるようにする REST エンドポイントです。これには、ネットワーク、ストレージ、SKU などのメタデータ情報が含まれます。このサービスは、特定のルーティング不可能な IP アドレス (169.254.169.254) からアクセスできます。

こちらも下記で非常にわかりやすく書かれています。
Azure Instance Metadata Service でできることとして以下が具体的に挙げられています。
> インスタンス メタデータ
構成証明済みデータ
Load Balancer メタデータ
**マネージド ID**
スケジュールされたイベント

https://qiita.com/ussvgr/items/f993cf48b29147d30767

公式ドキュメントは下記です。

https://learn.microsoft.com/ja-jp/azure/virtual-machines/instance-metadata-service?tabs=windows

# マネージド ID を使うメリット
マネージド IDを使うことで通常のユーザーのような認証が不要になります。
例えば、実際のユーザーのIDとパスワードをスクリプトにベタ書きするのはセキュリティ上よくないですし(\*)、MFA (Multi Factor Authetification) が有効されている場合は、MFAに対応できない (できるパターンもあるかもしれないですがたぶん面倒) のでそもそも Azure にログインすることができません。
(\*)例えば該当のスクリプトのソースコードを Github に上げてPublic Repositoryで管理していた場合などは誰でもアクセスできるようになる可能性があります。

じゃあ、一般のユーザーであらかじめ認証だけしておこう！として定期実行をしている場合でもトークンの有効期限が切れると Azure に対する操作ができなくなるため定期的 (およそ90日毎) にログインするという運用が必要になったりもすると思います。
トークンの有効期間については下記をご覧ください。

+ Azure AD が発行するトークンの有効期間について-日本マイクロソフトサポートブログ

https://jpazureid.github.io/blog/azure-active-directory/aad-token-lifetime/

# Az rest コマンド / Invoke-AzRestMethod コマンド
Azure CLI の場合は ```Az rest```で、Azure PowerShell の場合は ```Invoke-AzRest``` です。
これらは通常の Azure CLI や Azure PowerShell のコマンドとは異なり、 Azure に API を直接リクエストできる コマンド / サブコマンドです。

+ Invoke-AzRestMethod の 例
https://learn.microsoft.com/ja-JP/cli/azure/reference-index?view=azure-cli-latest#az-rest

```PowerShell:Azure PowerShell
 Invoke-AzRest -Path "/subscriptions/eXXXXXXXX-eXXX-4XXX-bXXX-afXXXad26e83/resourceGroups/RG-TEST-16/providers/Microsoft.Compute/virtualMachines?api-version=2022-03-01" -Method GET
```

公式ドキュメント

https://learn.microsoft.com/ja-jp/powershell/azure/manage-azure-resources-invoke-azrestmethod?view=azps-10.4.1

+ az rest の 例
```az rest:Azure CLI 
az rest --method get --url "/subscriptions/eXXXXXXXX-eXXX-4XXX-bXXX-afXXXad26e83/resourceGroups/RG-TEST-16/providers/Microsoft.Compute/virtualMachines?api-version=2022-03-01"
```
公式ドキュメント

https://learn.microsoft.com/ja-jp/cli/azure/use-cli-effectively?tabs=bash%2Cbash2#rest-api-commands-az-rest


+ ⚡これらの REST 系のコマンドが無いとき⚡
下記のブログで紹介されている ”直接実行” という方法で API にリクエストすることもできます。

https://techeng-study.com/azure-rest-api-methods/


# やってみる
## やりたいこと(再掲)
+ Azure VM から Azure を操作する。
+ 具体的な今回の Azure 操作 Azure VM が属するリソースグループの Azure VM 一覧を取得する。
+ Azure PowerShell (Get-AzVM コマンド) と Azure CLI (Az restコマンド) の 2 種類の方法で実行する。


## 前提
・Azure VM名：Vnet-Hun-Win /　リソースグループ：RG-TEST-16
・Azure CLI  / Azure PowerShell をインストール済
・Windows Server 環境
・今回使った コンソールは PowerShell
 ```
$PSVersionTable.PSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      17763  5328
 ```
 

参考
Azure PowerShell のインストール
+ PowerShellGet を使用して Azure PowerShell をインストールする | Microsoft Learn
https://learn.microsoft.com/ja-jp/powershell/azure/install-az-ps?view=azps-0.10.0#install-offline

Azure CLI のインストール
+ Windows 用 Azure CLI をインストールする | Microsoft Learn
https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli-windows?tabs=winget#install-or-update

## マネージド ID を設定する
下記を参考にして対象のAzure VM 割り当てられているマネージドIDに権限を割り当てます。
今回の権限設定、Azure ロールは Subscription スコープに対して 閲覧者ロールを割り当てます。

:::note warn
一度無効化すると再度有効化すると新たなマネージド IDが作成されるため再設定が必要になります。
下記のようなメッセージが無効化する際に現れます
> システム割り当てマネージドIDを無効にすると、サービスエラーが発生する可能性があります。この手順は元に戻すことができません。今後 IDを再度有効にすると、Azure によって新しい IDが作成されます。続行しますか?
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/6c603306-cea1-83b2-c27d-99bf8ce57d8e.png)

![2024-01-17_00h07_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/b1344835-d4e4-5e1e-dbf9-be1be3553a46.png)


マネージド ID に権限を設定しただけでは、マネージドIDによる認証を使って Azure PowerShell や Azure CLI  を実施できません、出来てはいけません。
想定通りできないかを確認します。
Azure CLI /az rest コマンド の Subscription ID 部分は一部 X として伏字にしています。

```PowerShell:Azure PowerShell
Get-AzVM -ResourceGroupName RG-TEST-16
```

```PowerShell:Azure CLI 
az rest --method get --url "/subscriptions/eXXXXXXXX-eXXX-4XXX-bXXX-afXXXad26e83/resourceGroups/RG-TEST-16/providers/Microsoft.Compute/virtualMachines?api-version=2022-03-01"
```
結果は下記のように Error Message が出てきて、期待通りの動作になりました。
簡単にいうとログインしろよーってことです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/1939e492-718d-2410-a870-84c7ed396d3d.png)

## マネージド ID でログインして実行する
結論から言えば 、Azure PowerShell の場合は ``Connect-AzAccount -Identity`` 、Azure CLI の場合は``az login --identity
``を使うことでマネージド ID を使ったログインが可能です。

以下に今回実行したコマンドをそれぞれ示します。
パスワードなどを記載していないことが分かります。✨

```PowerShell:Azure PowerShell
# Azureにマネージドアイデンティティを使用してログイン
Add-AzAccount -identity

# Azureリソースマネージャーを呼び出して、VM のAzureリソースのマネージドアイデンティティのサービスプリンシパルIDを取得 (省略可)
$vmInfoPs = Get-AzVM -ResourceGroupName RG-TEST-16 -Name Vnet-Hub-Win
$spID = $vmInfoPs.Identity.PrincipalId

# 取得したサービスプリンシパルIDを表示 (省略可)
echo "The managed identity for Azure resources service principal ID is $spID"

# Azureの仮想マシンの情報を取得
Get-AzVM　-ResourceGroupName RG-TEST-16

# Azureからログアウト(省略可)
Logout-AzAccount

```

```PowerShell:Azure CLI
# Azureにマネージドアイデンティティを使用してログイン
az login --identity

# 指定したリソースのサービスプリンシパルIDを取得 (省略可)
$spID=$(az resource list -n Vnet-Hub-Win --query [*].identity.principalId --out tsv)

# 取得したサービスプリンシパルIDを表示 (省略可)
echo "The managed identity for Azure resources service principal ID is $spID"

# REST APIを使用して仮想マシンの情報を取得
az rest --method get --url "/subscriptions/XXXXXec1-XXXX-XXX0-XXX1-aXXXXad26XXX/resourceGroups/RG-TEST-16/providers/Microsoft.Compute/virtualMachines?api-version=2022-03-01"

# Azureからログアウト (省略可)
az logout
```

実行結果は以下の通りです。
正しく取得できていることが分かります。
(英語 OS 環境で実施したので日本語部分が文字化けしております🚀)

![2024-01-16_23h22_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/6a5aaaca-7b5d-74f1-9fda-4d9061d1cab0.png)

## マネージド ID では別テナントに対する操作はできない
マネージド ID で使われる RBAC は Microsoft Entra ID に紐づく設定であるため、別テナントのリソースに対する操作ができません。
以下公式ドキュメントの抜粋です。

> ・マネージド ID を使って違うディレクトリやテナント内のリソースへアクセスできますか?
いいえ。 マネージド ID は現在、クロスディレクトリ シナリオをサポートしていません。

https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/managed-identities-faq#can-i-use-a-managed-identity-to-access-a-resource-in-a-different-directorytenant

## 番外編：Azure VM 以外から試してみる

手元の物理マシン(Azure VMではない) でマネージドIDを利用してログインを実施した結果、下記のようなError Message がでました。
Az コマンドの方が詳しくError Message が出てますね。 Azure 上の特殊な IP (Azure Instance Metadata Service = 169.254.169.254) にアクセスできないのでエラーになっていることが分かります。
**Azure Instance Metadata Service は Azure 上のリソースからしかアクセスできないので想定通りの結果となりました。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/83931ebf-b8fc-52a0-3ef4-7bc2f7f54080.png)

```Azure CLI :Azure CLI の Error Message
Failed to connect to MSI. Please make sure MSI is configured correctly and check the network connection.
Error detail: HTTPConnectionPool(host='169.254.169.254', port=80): Max retries exceeded with url: /metadata/identity/oauth2/token?resource=https%3A%2F%2Fmanagement.core.windows.net%2F&api-version=2018-02-01 (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x00000272BA37B850>, 'Connection to 169.254.169.254 timed out. (connect timeout=None)'))
```
# その他参考

https://learn.microsoft.com/en-us/rest/api/azure/#register-your-client-application-with-azure-ad


https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/how-managed-identities-work-vm

https://ascii.jp/elem/000/004/107/4107695/#:~:text=%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%89ID%E3%81%A7%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%20%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%89ID%E3%81%AF%E4%B8%8A%E8%A8%982%E3%81%A4%E3%81%AE%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%AF%E7%95%B0%E3%81%AA%E3%82%8A%E3%80%81VM%20%28Automation%2C%20Functions%E3%81%AA%E3%81%A9%29%E5%86%85%E3%81%AE%E3%81%BF%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82,az%20login%20--identity%20Connect-AzAccount%20-Identity

# まとめ
Azure VM 上から Azure リソースを操作するスクリプトを組んだりする際はできるだけマネージド ID を使いましょう！

以上です。