ユーザー割り当てマネージドIDによるAzureリソースへのアクセス権限付与

ユーザー割り当てマネージドIDを作成しAzureリソースへのアクセス権限を付与する手順を解説します。  
作成したユーザー割り当てマネージドIDは、**Azure VM** や **Azure コンテナー インスタンス**へ適用することができます。  
これらの手順は[関連記事](#関連記事)で解説します。

## ユーザー割り当てマネージドIDの作成

👇ユーザー割り当てマネージドIDを作成します。  

```text
az identity create^
 --resource-group sampleResourceGroup^
 --name user_managed_id_01
```

上記コマンドを発行すると下記の出力が得られます。  
出力の中の`id`(ユーザー割り当てマネージドID)と`principalId`(プリンシパルID)を後で利用しますのでメモしておきます。  

```text
{
  "clientId": "00000-00000-00000-00000",
  "id": "/subscriptions/99999-99999-99999-99999/resourcegroups/sampleResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/user_managed_id_01",
  "location": "japaneast",
  "name": "user_managed_id_01",
  "principalId": "*****-*****-*****-*****-*****",
  "resourceGroup": "sampleResourceGroup",
    .....
}
```

## グループの作成

👇Azureリソースへのアクセス権限付与のため、グループを作成します。  

```text
az ad group create^
 --display-name SampleRoleGroup^
 --mail-nickname SampleRoleGroup
 ```

下記出力が得られます。  
出力の中の`id`(グループID)を後で利用しますのでメモしておきます。  

```text
{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
  "classification": null,
  "createdDateTime": "2024-01-26T09:17:58Z",
  "creationOptions": [],
  "deletedDateTime": null,
  "description": null,
  "displayName": "SampleRoleGroup",
  "expirationDateTime": null,
  "groupTypes": [],
  "id": "00000000-0000-0000-0000-000000000000",
  "isAssignableToRole": null,
  "mail": null,
  .....
```

## グループメンバーにユーザー割り当てマネージドIDを追加

👇上記手順でメモしておいた`プリンシパルID`を使ってグループメンバーにユーザー割り当てマネージドIDを追加します。

```text
az ad group member add^
 --group ResourceControlGroup^
 --member-id "*****-*****-*****-*****-*****"
```

## グループへの権限付与

例１）  
グループに対してリソースグループのフルアクセス権限を割り当てます。  
**assignee**には上記でメモした`グループID`を設定します。  

```text
az role assignment create^
 --assignee "00000000-0000-0000-0000-000000000000"^
 --role "Owner"^
 --resource-group "resource_group_sample"
```

例２）  
グループに対してリソースへのアクセス権限を割り当てます。（下記はVM Imageに権限を割り当てる例）  
**assignee**には上記でメモしたグループIDを設定します。  

```text
az role assignment create^
 --assignee "00000000-0000-0000-0000-000000000000"^
 --role "Owner"^
 --scope "/subscriptions/*****-*****-*****-*****/resourceGroups/resource_group_for_python/providers/Microsoft.Compute/galleries/shared_image_gallery_01/images/vm-image_01"
```

👇ロールの割り当て状況を確認する

```text
az role assignment list^
 --scope "/subscriptions/*****-*****-*****-*****/resourceGroups/resource_group_for_python/providers/Microsoft.Compute/galleries/shared_image_gallery_01/images/vm-image_01"
```

```text
az role assignment list^
 --all^
 --assignee "00000000-0000-0000-0000-000000000000"
```

## ユーザー割り当てマネージドIDをVMに適用(CLI)

👇vm起動時に`--assign-identity`パラメータに上記`ユーザー割り当てマネージドID`を指定することでユーザー割り当てマネージドIDに割り当てた権限をVMに付与することができます。  
Azure VM起動については、関連記事参照下さい。  
[Azure CLI で Ubuntu のVMを起動/削除する](https://docs.saurus12.com/azure/ubuntu_vm)

```text
az vm create --location japaneast^
 --resource-group sampleResourceGroup^
 --name ubuntu-vm^
 --image Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest^
 --size Standard_B1ms^
 --public-ip-address public_ip_01^
 --public-ip-sku Standard^
 --data-disk-delete-option Delete^
 --os-disk-delete-option Delete^
 --nic-delete-option Delete^
 --nsg nsg_01^
 --vnet-name vnet_01^
 --priority Regular^
 --nsg-rule SSH^
 --admin-username admin01^
 --admin-password SampleVM!123^
 --assign-identity /subscriptions/99999-99999-99999-99999/resourcegroups/sampleResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/user_managed_id_01
 ```

## ユーザー割り当てマネージドIDをAzure コンテナー インスタンスに適用(CLI)

👇Azure コンテナー インスタンス作成時に`--assign-identity`パラメータに上記`ユーザー割り当てマネージドID`を指定することでユーザー割り当てマネージドIDに割り当てた権限をAzure コンテナー インスタンスに付与することができます。  
Azure コンテナー インスタンスについては、関連記事参照下さい。  
[Azure コンテナー インスタンスでコンテナー レジストリ に登録したDockerイメージを起動する](https://docs.saurus12.com/azure/docker_container_create)

```text
az container create^
 --resource-group sampleResourceGroup^
 --name webservercontainer^
 --image containerregistory01.azurecr.io/webserver:latest^
 --assign-identity /subscriptions/99999-99999-99999-99999/resourcegroups/sampleResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/user_managed_id_01^
 --dns-name-label webserver^
 --ports 80^
 --registry-username containerregistory01^
 --registry-password **********
```

## ユーザー割り当てマネージドIDを Azure SDK for Python から利用するための準備

以下内容は、[ローカル開発環境でAzure SDK for Pythonを利用するための認証設定](https://docs.saurus12.com/azure/azure_sdk_python_certificate)を前提とします。  
ユーザー割り当てマネージドIDを Azure SDK for Python から利用するためにはユーザー割り当てマネージドID自体への権限付与が必要です。  

```text
az role assignment create^
 --assignee "00000000-0000-0000-0000-000000000000"^
 --role "Owner"^
 --scope "/subscriptions/*****-*****-*****-*****/resourcegroups/sampleResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/user_managed_id_01"
```

## ユーザー割り当てマネージドIDをVMに適用(Azure SDK for Python)

`user_assigned_identities`のところで設定しています。  

```python
from azure.identity import DefaultAzureCredential
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.network import NetworkManagementClient

from azure.mgmt.network.models import SecurityRule
from azure.mgmt.network.models import NetworkSecurityGroup

# credential object
credential = DefaultAzureCredential()

SUBSCRIPTION_ID = "****-****-****-****-****"
RESOURCE_GROUP_NAME = "vm_resource_group"
LOCATION = "japaneast"

VNET_NAME = "python-example-vnet"
SUBNET_NAME = "python-example-subnet"
IP_NAME = "python-example-ip"
IP_CONFIG_NAME = "python-example-ip-config"
NIC_NAME = "python-example-nic"

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.networkmanagementclient?view=azure-python
network_client = NetworkManagementClient(credential, SUBSCRIPTION_ID)

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.operations.virtualnetworksoperations?view=azure-python
poller = network_client.virtual_networks.begin_create_or_update(
    RESOURCE_GROUP_NAME,
    VNET_NAME,
    {
        "location": LOCATION,
        "address_space": {"address_prefixes": ["10.0.0.0/16"]},
    },
)
vnet_result = poller.result()
print(f"Provisioned virtual network {vnet_result}")

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.operations.subnetsoperations?view=azure-python
poller = network_client.subnets.begin_create_or_update(
    RESOURCE_GROUP_NAME,
    VNET_NAME,
    SUBNET_NAME,
    {"address_prefix": "10.0.0.0/24"},
)
subnet_result = poller.result()
print(f"Provisioned virtual subnet {subnet_result} ")

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.operations.publicipaddressesoperations?view=azure-python
poller = network_client.public_ip_addresses.begin_create_or_update(
    RESOURCE_GROUP_NAME,
    IP_NAME,
    {
        "location": LOCATION,
        "sku": {"name": "Standard"},
        "public_ip_allocation_method": "Static",
        "public_ip_address_version": "IPV4",
    },
)
ip_address_result = poller.result()
print(f"Provisioned public IP address {ip_address_result} ")
print(f"ip address : {ip_address_result.ip_address}")

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.models.securityrule?view=azure-python
nsg_rule = SecurityRule(
    name="AllowSSH",
    access="Allow",
    protocol="Tcp",
    destination_port_range="22",
    destination_address_prefix="*",
    direction="Inbound",
    source_port_range="*",
    source_address_prefix="*",
    priority=100
)

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.models.networksecuritygroup?view=azure-python
nsg = NetworkSecurityGroup(
    location=LOCATION,
    security_rules=[nsg_rule],
)

NSG_NAME = "python-example-nsg"

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.operations.networksecuritygroupsoperations?view=azure-python#azure-mgmt-network-operations-networksecuritygroupsoperations-begin-create-or-update
poller = network_client.network_security_groups.begin_create_or_update(
    RESOURCE_GROUP_NAME,
    NSG_NAME,
    nsg,    
)
nsg_result = poller.result()
print(f"Provisioned network security group {nsg_result} ")

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-network/azure.mgmt.network.operations.networkinterfacesoperations?view=azure-python
poller = network_client.network_interfaces.begin_create_or_update(
    RESOURCE_GROUP_NAME,
    NIC_NAME,
    {
        "location": LOCATION,
        "network_security_group": nsg_result,
        "ip_configurations": [
            {
                "name": IP_CONFIG_NAME,
                "subnet": {"id": subnet_result.id},
                "public_ip_address": {"id": ip_address_result.id},
            }
        ],
    },
)
nic_result = poller.result()
print(f"Provisioned network interface client {nic_result}")

VM_NAME = "ExampleVM"
USERNAME = "azureuser"
PASSWORD = "admin!12345"
DISK_NAME = "python-example-disk"

USER_MANAGED_ID = "/subscriptions/99999-99999-99999-99999/resourcegroups/sampleResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/user_managed_id_01"

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-compute/azure.mgmt.compute.computemanagementclient?view=azure-python
compute_client = ComputeManagementClient(credential, SUBSCRIPTION_ID)

# https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-compute/azure.mgmt.compute.v2023_07_01.operations.virtualmachinesoperations?view=azure-python
poller = compute_client.virtual_machines.begin_create_or_update(
    RESOURCE_GROUP_NAME,
    VM_NAME,
    {
        "location": LOCATION,
        "storage_profile": {
            "image_reference": {
                "publisher": "Canonical",
                "offer": "0001-com-ubuntu-server-jammy",
                "sku": "22_04-lts-gen2",
                "version": "latest",
            },
            "os_disk": {
                "create_option": "FromImage",
                "name": DISK_NAME
            }
        },
        "hardware_profile": {"vm_size": "Standard_B1ms"},
        "os_profile": {
            "computer_name": VM_NAME,
            "admin_username": USERNAME,
            "admin_password": PASSWORD,
        },
        "network_profile": {
            "network_interfaces": [
                {
                    "id": nic_result.id,
                }
            ],
        },
        "identity":{
            "type": "UserAssigned",
            "user_assigned_identities":{
                USER_MANAGED_ID: {}
            }
        }

    },
)
vm_result = poller.result()
print(f"Provisioned virtual machine {vm_result}")

```

## ユーザー割り当てマネージドIDをAzure コンテナー インスタンスに適用(Azure SDK for Python)

`user_assigned_identities`のところで設定しています。  

```python
from azure.identity import DefaultAzureCredential
from azure.mgmt.containerinstance import ContainerInstanceManagementClient


SUBSCRIPTION_ID = "****-****-****-****-****"
RESOURCE_GROUP_NAME = "container_resource_group"
LOCATION = "japaneast"

CONTAINER_GROUP_NAME = "webservercontainer"

USER_MANAGED_ID = "/subscriptions/99999-99999-99999-99999/resourcegroups/sampleResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/user_managed_id_01"
IMAGE = "containerregistory01.azurecr.io/skypesample:latest"
COMMAND_LINE = ["nginx", "-g", "daemon off;"]

REGISTORY_SERVER = "containerregistory01.azurecr.io"
REGISTORY_USER_NAME = "containerregistory01"
REGISTORY_USER_PASSWORD = "************"

client = ContainerInstanceManagementClient(credential=DefaultAzureCredential(), subscription_id=SUBSCRIPTION_ID)

poller = client.container_groups.begin_create_or_update(resource_group_name=RESOURCE_GROUP_NAME \
    ,container_group_name=CONTAINER_GROUP_NAME \
    ,container_group={
        "identity":{
            "type": "UserAssigned",
            "user_assigned_identities":{
                USER_MANAGED_ID: {}
            }
        },
        "containers":[{
            "name":CONTAINER_GROUP_NAME,
            "image":IMAGE,
            "command":COMMAND_LINE,
            "resources":{
                "requests":{
                    "memory_in_gb":1.5,
                    "cpu":1,
                }
            }

        }],
        "image_registry_credentials":[{
            "server":REGISTORY_SERVER,
            "username":REGISTORY_USER_NAME,
            "password":REGISTORY_USER_PASSWORD
        }],
        "restart_policy":"Never",
        "location":LOCATION,
        "os_type": "Linux",
    })

container_result = poller.result()
print(f"Provisioned container {container_result}")

```

## 👇関連記事

- [Azure CLI で Ubuntu のVMを起動/削除する](https://docs.saurus12.com/azure/ubuntu_vm)
- [Azure コンテナー インスタンスでコンテナー レジストリ に登録したDockerイメージを起動する](https://docs.saurus12.com/azure/docker_container_create)
- [ローカル開発環境でAzure SDK for Pythonを利用するための認証設定](https://docs.saurus12.com/azure/azure_sdk_python_certificate)

## 👇参考URL

- [ユーザー割り当てマネージド ID の管理](https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/how-manage-user-assigned-managed-identities?pivots=identity-mi-methods-azcli)
- [az ad group member add](https://learn.microsoft.com/ja-jp/cli/azure/ad/group/member?view=azure-cli-latest#az-ad-group-member-add)
- [Azure VM の作成中にユーザー割り当てマネージド ID を割り当てる](https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/qs-configure-cli-windows-vm#assign-a-user-assigned-managed-identity-during-the-creation-of-an-azure-vm)
- [コンテナー グループでユーザー割り当て ID を有効にする](https://learn.microsoft.com/ja-jp/azure/container-instances/container-instances-managed-identity#enable-user-assigned-identity-on-a-container-group)
- [Azure-Samples/compute-python-msi-vm](https://github.com/Azure-Samples/compute-python-msi-vm/blob/master/example.py)
- [azure-mgmt-containerinstance](https://learn.microsoft.com/ja-jp/python/api/overview/azure/mgmt-containerinstance-readme?view=azure-python)
- [ContainerGroupsOperations クラス](https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.operations.containergroupsoperations?view=azure-python)
- [Container クラス](https://learn.microsoft.com/ja-jp/python/api/azure-mgmt-containerinstance/azure.mgmt.containerinstance.models.container?view=azure-python)

[keywords]  
Azure CLI ユーザー割り当てマネージドID アクセス権限 ロール

[ユーザー割り当てマネージドIDによるAzureリソースへのアクセス権限付与](https://docs.saurus12.com/azure/user_manage_id)

更新日:2024年01月29日