0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Azureの権限周りがすべてわかる

0
Posted at

Azure 権限周りの全体像

権限管理構造

ユーザー / アプリ / VM / Functions
↓
Microsoft Entra ID
↓
認証
↓
Azure RBAC
↓
認可
↓
Azure Resource / Data Plane

権限の階層構造

Tenant
↓
Management Group
↓
Subscription
↓
Resource Group
↓
Resource

tenant

最上位。
Azureを契約すると作られる組織そのもの。
イメージ:株式会社A

中身

ユーザー
グループ
認証
MFA
Entra ID

Management Group

Subscriptionをまとめる箱

  • 共通ポリシー適用
    東京リージョンのみ
    Public IP禁止
  • 共通RBAC適用
    全SubscriptionにReader付与

Subscription

課金単位

イメージ
株式会社A(tenant)
├ 案件A(Manegemnt Group)
  └開発環境(Subscription)
  └本番環境(Subscription)
  └検証環境(Subscription)
├ 案件B(Manegemnt Group)
  └開発環境(Subscription)
  └本番環境(Subscription)
  └検証環境(Subscription)

Resource Group

リソースをまとめる箱

開発環境(Subscription)
 ├rag-dev-rg(Resource Group)
    ├ OpenAI(Resource)
    ├ AI Search(Resource)
    ├ Storage(Resource)
    ├ Function(Resource)
    └ Key Vault(Resource)
 ├function-dev-rg(Resource Group)
    ├ Azure Functions(Resource)
    └ S3(Resource)

Resource

AWSのサービス

Azure OpenAI
Storage
VM
AKS
AI Search
Key Vault

Azure Resource Manager

Azureの司令塔

構造

Portal
CLI
Terraform
Bicep
↓
ARM
↓
Azure Resource

役割

RBAC評価
Resource作成
Resource削除
Provider呼び出し

RBAC (Role-Based Access Control)

Roleベースで権限を管理する仕組み

実際の構成は

RBAC
├ Role Definition
└ Role Assignment
    ├ Principal
    ├ Role
    └ Scope

Role Assignment

実際の権限付与

Principal(付与対象)
+
Role(権限セット)
+
Scope(どこまでの権限か)

RBACとRoleAssignmentの関係

RBAC
├ Role Definitions
│   ├ Reader
│   ├ Contributor
│   └ Owner
│
└ Role Assignments
    ├ Alice(Principal) → Contributor(Role) → RG-A(Scope)
    ├ Bob(Principal) → Reader(Role) → Subscription(Scope)
    └ SP(Principal) → Owner(Role) → RG-B(Scope)

実行順序

1. Role Assignment検索
   ↓
2. AliceはContributor
   ↓
3. ContributorのRole Definition取得
   ↓
4. VM作成権限あり
   ↓
5. 実行

ARMとRBACとRole Assignmentの関係

Azure CLI
    ↓
ARM
    ↓
RBAC確認
    ↓
Role Assignment検索
    ↓
許可なら実行
    ↓
VM作成

Azure Policy

Role内で大きく分けられたOwner/Contributor/Readerに対して、細かい権限を付与する
Role = 権限
Policy = 制約

ARMとRBACとRole AssignmentとAzure Policyの関係

Azure CLI
    ↓
ARM
    ↓
RBAC確認
    ↓
Role Assignment検索
    ↓
許可
    ↓
Policy確認
    ↓
ルール違反なし
    ↓
VM作成

Role Assignmentの中身

Principal

  • 権限を与える対象
    User
    Group
    Service Principal
    Managed Identity

Service Principal

アプリ用アカウント

  • 用途
    Terraform
    GitHub Actions
    Python
    CI/CD

Managed Identity

Azureリソース専用IAM

Function App
↓
Managed Identity
↓
Storageアクセス

Role

  • Reader
    閲覧のみ
  • Contributor
    作成
    更新
    削除
  • Owner
    作成
    更新
    削除
    権限付与
  • User Access Administrator
    RBAC付与
    RBAC削除
    専用。

Scope

RBACの適用範囲

イメージ

誰に
何を
どこまで

の

どこまで

部分。

Provider

サービスのAPI名前空間

AI SearchはMicrosoft.Searchの配下
OpenAIはMicrosoft.CognitiveServicesの配下

他にも
Microsoft.Storage
Microsoft.Compute
Microsoft.Web
Microsoft.KeyVault

ARMとRBACとRole AssignmentとAzure PolicyとProviderの関係

Azure CLI
    ↓
ARM
    ↓
RBAC確認
    ↓
Role Assignment検索
    ↓
許可
    ↓
Policy確認
    ↓
ルール違反なし
    ↓
Provider(Microsoft.Compute)
    ↓
VM作成

EntraID

Azureにおける「認証」の中心です。

誰がログインするか
誰がアプリとして動くか
どのテナントに属するか
MFAを使うか
条件付きアクセスを使うか

Key Vault

秘密情報管理サービス。

保存対象

APIキー
DBパスワード
証明書
暗号鍵
接続文字列

Management Plane(管理プレーン)

リソースを管理するAPI

Storage作成
Storage削除
OpenAI作成
AI Search作成

操作元

Portal
CLI
Terraform
ARM

Data Plane(データプレーン)

実データ操作

例1 Storage

  • 管理プレーン
    Storage作成
  • データプレーン
    Blob読む
    Blob書く

例2 OpenAI

  • 管理プレーン
    OpenAI作成
  • データプレーン
    client.chat.completions.create()

Conditional Access

ログイン制御。

RBACとは別。

MFA必須
日本国外禁止
管理者は社給PC限定
危険サインイン遮断

理解

Conditional Access
=
ログイン可能か

RBAC
=
ログイン後に何ができるか

PIM(Privileged Identity Management)

  • 目的
    管理者権限を常時持たせない。

普段 Reader

必要時だけ

Owner
Contributor
User Access Administrator

を有効化。

実践

構成図

storage_function_mi_via_funcapp.png

Tenant (Entra ID)
│
├─ Human Principal(人間)
│   │
│   ├─ Developers Group
│   │   └─ Alice
│   │
│   └─ Operators Group
│       └─ Bob
│
├─ Application Principal(アプリ)
│   │
│   └─ Service Principal
│       └─ Terraform / GitHub Actions
│
└─ Resource Principal(Azureリソース)
    │
    └─ Function Managed Identity
        └─ Function App専用ID


Management Group
│
└─ Azure Policy
    ├─ Japan Eastのみ
    └─ Public IP禁止


Subscription
│
└─ azure-rbac-lab-rg
    │
    ├─ Storage Account
    │
    └─ Function App
         │
         └─ Managed Identity


──────────────────────────────────────────
RBAC
──────────────────────────────────────────

Role Assignments
│
├─ Human Principal
│   │
│   ├─ Developers
│   │   └─ Reader
│   │       └─ Resource Group
│   │
│   └─ Operators
│       └─ Contributor
│           └─ Resource Group
│
├─ Application Principal
│   │
│   └─ Service Principal
│       └─ Contributor
│           └─ Resource Group
│
└─ Resource Principal
    │
    └─ Function Managed Identity
        └─ Storage Blob Data Contributor
            └─ Storage Account


──────────────────────────────────────────
Management Plane
──────────────────────────────────────────
Alice/Bob/Service Principal

Storage Account作成
Storage Account削除
Function App作成
Function App削除


──────────────────────────────────────────
Data Plane
──────────────────────────────────────────

Function App
      │
      ▼

Managed Identity

      │

Storage Blob Data Contributor

      │

Storage Account

      │

Blob読込
Blob書込
Blob削除

──────────────────────────────────────────
実行結果
──────────────────────────────────────────

Alice
↓
Developers
↓
Reader
↓
Storage作成失敗


Bob
↓
Operators
↓
Contributor
↓
Storage作成成功


az cli
↓
Service Principal
↓
Contributor
↓
Storage作成成功


Function App
↓
Managed Identity
↓
Storage Blob Data Contributor
↓
Blob読込/書込成功

共通変数

az login

TENANT_ID=$(az account show --query tenantId -o tsv)
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
MGMT_GROUP_ID="test-manager-group"
RG_NAME="test-resource-group"
LOCATION="japaneast"
STORAGE_ACCOUNT="teststorage$RANDOM"
FUNCTION_APP="test-func-$RANDOM"

AliceとBob

# Developers グループ作成
# Microsoft Entra ID(旧 Azure AD)にグループを作成するコマンド
# Display Name
# Mail Nickname
# Object ID
# を持っており、Display Nameは重複可能だが、Mail Nicknameは一意のものを指定しなければならない
az ad group create \
  --display-name "Developers" \
  --mail-nickname "developers"

DEVELOPERS_GROUP_ID=$(az ad group show --group "Developers" --query id -o tsv)

# Operators グループ作成
az ad group create \
  --display-name "Operators" \
  --mail-nickname "operators"

OPERATORS_GROUP_ID=$(az ad group show --group "Operators" --query id -o tsv)

# domain取得
DOMAIN=$(az rest \
  --method GET \
  --url "https://graph.microsoft.com/v1.0/domains" \
  --query "value[?isDefault==\`true\`].id | [0]" \
  -o tsv)

# Alice ユーザー作成
az ad user create \
  --display-name "Alice" \
  --user-principal-name "alice@$DOMAIN" \
  --password "P@ssw0rd1234!" \
  --force-change-password-next-sign-in true

ALICE_ID=$(az ad user show --id "alice@$DOMAIN" --query id -o tsv)

# Bob ユーザー作成
az ad user create \
  --display-name "Bob" \
  --user-principal-name "bob@$DOMAIN" \
  --password "P@ssw0rd1234!" \
  --force-change-password-next-sign-in true

BOB_ID=$(az ad user show --id "bob@$DOMAIN" --query id -o tsv)

# グループへメンバー追加
az ad group member add --group "Developers" --member-id $ALICE_ID
az ad group member add --group "Operators" --member-id $BOB_ID

Service Principal 作成(Application Principal)

# Azure Resource Group(リソースグループ)を作成するコマンド
az group create --name $RG_NAME --location $LOCATION
# Terraform/GitHub Actions 用 Service Principal(アプリ用のAzureログインID を作っています)
az ad sp create-for-rbac \
  --name "sp-terraform-github-actions" \
  --role "Contributor" \
  --scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RG_NAME" \
  --years 1

# 出力される appId / password / tenant を控える
SP_APP_ID="<出力されたappId>"
SP_OBJECT_ID=$(az ad sp show --id $SP_APP_ID --query id -o tsv)

Management Group と Azure Policy 設定

# Management Group 作成
az account management-group create \
  --name $MGMT_GROUP_ID \
  --display-name "Azure RBAC Lab MG"

# サブスクリプションをMGに紐付け
az account management-group subscription add \
  --name $MGMT_GROUP_ID \
  --subscription $SUBSCRIPTION_ID
# ポリシー1: Japan East のみ許可(許可されたロケーション)
az policy assignment create \
  --name "allowed-japaneast" \
  --display-name "Allowed Locations - Japan East Only" \
  --scope "/providers/Microsoft.Management/managementGroups/$MGMT_GROUP_ID" \
  --policy "e56962a6-4747-49cd-b67b-bf8b01975c4c" \
  --params '{ "listOfAllowedLocations": { "value": ["japaneast"] } }'
# ポリシー2: パブリックIP禁止(Public IP の作成を拒否)
az policy assignment create \
  --name "deny-public-ip" \
  --display-name "Deny Public IP Address Creation" \
  --scope "/providers/Microsoft.Management/managementGroups/$MGMT_GROUP_ID" \
  --policy "83a86a26-fd1f-447c-b59d-e51f44264114"

*e56962a6-4747-49cd-b67b-bf8b01975c4cや83a86a26-fd1f-447c-b59d-e51f44264114 は組み込みの "Public IP addresses should be reused" 等、環境によっては該当するDeny系ビルトインポリシー(例: "Network interfaces should not have public IPs")のIDに置き換えてください。完全な禁止には Deny effect を持つカスタムポリシーまたは適切な組み込みポリシー定義IDを選定する必要があります。

RBAC ロール割り当て(Human / Application(Service) Principal)

# Developers グループ → Reader (Resource Group)
az role assignment create \
  --assignee-object-id $DEVELOPERS_GROUP_ID \
  --assignee-principal-type Group \
  --role "Reader" \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RG_NAME"

# Operators グループ → Contributor (Resource Group)
az role assignment create \
  --assignee-object-id $OPERATORS_GROUP_ID \
  --assignee-principal-type Group \
  --role "Contributor" \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RG_NAME"

# Service Principal → Contributor (Resource Group)
# ※ create-for-rbac 時に --scopes で割り当て済みの場合は不要
az role assignment create \
  --assignee-object-id $SP_OBJECT_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Contributor" \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RG_NAME"

結果確認

結果確認の前に重要なコマンドを実行

  • 下記を実行しておかないと、Storage作成の際、SubscriptionNotFoundエラーが返る
az provider register --namespace Microsoft.Storage
az provider register --namespace Microsoft.Web
  • 理由
    新しく作成されたサブスクリプション、あるいは特定の操作(VM作成、Storage作成など)を一度も行っていないサブスクリプションでは、よく使うプロバイダー(Microsoft.Compute, Microsoft.Storage, Microsoft.Networkなど)は通常Azure Portal経由の操作で自動登録されますが、CLIだけで操作している環境やクリーンな新規サブスクリプションでは未登録のままということがあります。なぜエラーメッセージが SubscriptionNotFound になるのか(誤解しやすい部分)
    本来、Azureが正確にエラーを返すなら、MissingSubscriptionRegistration
    「このサブスクリプションでMicrosoft.Storageは登録されていません」という分かりやすいエラーになるべきです。しかし、Microsoft.Storage の checkNameAvailability という特定のAPI(ストレージアカウント名が使用可能か事前確認するAPI)については、APIの実装やバージョンによって、プロバイダー未登録時に「サブスクリプションそのものが見つからない」という、より汎用的な404エラー(SubscriptionNotFound)を返してしまうことがある、というのが今回のケースです。これは「本当はサブスクリプションが存在しない」のではなく、「Microsoft.Storage機能の文脈において、このサブスクリプションは認識されていません」という意味合いの404であり、エラーメッセージとしては不正確・誤解を招くエラーが返ってくる

Alice失敗

# Alice として az login
az login
# ブラウザでAliceのメアドとパスワードでログイン

# Storage Account 作成試行 → Reader 権限のため失敗
az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RG_NAME \
  --location $LOCATION \
  --sku Standard_LRS
# => エラー: AuthorizationFailed (Reader権限のため作成不可)

Bob 成功

# Bob として az login
az login
# ブラウザでAliceのメアドとパスワードでログイン

# Storage Account 作成 → 成功
az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RG_NAME \
  --location $LOCATION \
  --sku Standard_LRS \

service principal 成功

# Service Principal でログイン
az login --service-principal \
  -u $SP_APP_ID \
  -p "rMQ8Q~pSlt13P19eAriOWTNHW2WroGL6Eft3wcWN" \
  --tenant $TENANT_ID

# Storage Account 作成 → 成功
az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RG_NAME \
  --location $LOCATION \
  --sku Standard_LRS \
  --allow-blob-public-access false

# (今回はいらない)Function Appを動かすための料金プラン/実行基盤作成
az functionapp plan create \
  --name $APP_PLAN_NAME \
  --resource-group $RG_NAME \
  --location $LOCATION \
  --sku B1 \
  --is-linux

# (今回はいらない)実際の Function App 本体
az functionapp create \
  --name $FUNCTION_APP \
  --resource-group $RG_NAME \
  --plan $APP_PLAN_NAME \
  --storage-account $STORAGE_ACCOUNT \
  --runtime python \
  --runtime-version 3.11 \
  --functions-version 4 \
  --os-type Linux

# Flex Consumptionは直接作る
az functionapp create \
  --resource-group $RG_NAME \
  --name $FUNCTION_APP \
  --storage-account $STORAGE_ACCOUNT \
  --flexconsumption-location $LOCATION \
  --runtime python \
  --runtime-version 3.11

Managed Identity の設定と結果確認

Function App
│
└─ Managed Identity
      │
      └─ Storage Blob Data Contributor
             │
             └─ Storage Account

設定

# Managed Identity を有効化Function App専用のService Principalを自動作成
az functionapp identity assign \
  --name $FUNCTION_APP \
  --resource-group $RG_NAME
# Principal ID取得
FUNC_PRINCIPAL_ID=$(az functionapp identity show \
  --name $FUNCTION_APP \
  --resource-group $RG_NAME \
  --query principalId -o tsv)
# Storage AccountのResource ID取得
STORAGE_ACCOUNT_ID=$(az storage account show \
  --name $STORAGE_ACCOUNT \
  --resource-group $RG_NAME \
  --query id -o tsv)

# Storage権限付与
az role assignment create \
  --assignee-object-id $FUNC_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Storage Blob Data Contributor" \
  --scope $STORAGE_ACCOUNT_ID

結果

下記のコードを対象のFunctionにデプロイしてブラウザアクセスで確認する

from azure.identity import ManagedIdentityCredential
from azure.storage.blob import BlobServiceClient

account_name = "<STORAGE_ACCOUNT>"

credential = ManagedIdentityCredential()

blob_service_client = BlobServiceClient(
    account_url=f"https://{account_name}.blob.core.windows.net",
    credential=credential
)

containers = list(blob_service_client.list_containers())

return {
    "container_count": len(containers)
}
mkdir mi-storage-test
cd mi-storage-test

cat > requirements.txt << 'EOF'
azure-functions
azure-identity
azure-storage-blob
EOF

cat > host.json << 'EOF'
{
  "version": "2.0"
}
EOF

cat > function_app.py << EOF
import os
import azure.functions as func
from azure.identity import ManagedIdentityCredential
from azure.storage.blob import BlobServiceClient

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="mi-storage-test")
def mi_storage_test(req: func.HttpRequest) -> func.HttpResponse:
    account_name = os.environ["STORAGE_ACCOUNT_NAME"]

    credential = ManagedIdentityCredential()
    client = BlobServiceClient(
        account_url=f"https://{account_name}.blob.core.windows.net",
        credential=credential
    )

    containers = [c["name"] for c in client.list_containers()]

    return func.HttpResponse(
        f"Managed Identity OK. containers={containers}",
        status_code=200
    )
EOF

zip -r app.zip .

# Function Appに環境変数を設定
az functionapp config appsettings set \
  --name $FUNCTION_APP \
  --resource-group $RG_NAME \
  --settings STORAGE_ACCOUNT_NAME=$STORAGE_ACCOUNT
  
# CLIでデプロイ
az functionapp deployment source config-zip \
  --name $FUNCTION_APP \
  --resource-group $RG_NAME \
  --src app.zip

# URLを取得して実行確認
az functionapp function show \
  --name $FUNCTION_APP \
  --resource-group $RG_NAME \
  --function-name mi_storage_test \
  --query invokeUrlTemplate -o tsv

curl "https://$FUNCTION_APP.azurewebsites.net/api/mi-storage-test"
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?