Azure RBACの「落とし穴」を埋める:カスタムロールによる最小権限の徹底管理
「Contributorロールをとりあえず付与しておけば、開発は止まらない」。
もし君のチームでそんな運用が横行しているなら、それは時限爆弾を抱えているのと同じだ。
インシデントの現場に立つと、攻撃者は決まって「広すぎる権限」を悪用する。例えば、Webアプリのバックエンドが侵害された際、そのサーバーに割り当てられたマネージドIDが Contributor 権限を持っていれば、攻撃者は即座にサブスクリプション内の他のリソースを列挙し、データストアを削除し、あるいはバックアップを消去してランサムウェアの交渉材料にする。
今日は、Azureにおける「最小権限の原則」を形骸化させないための、カスタムロール定義の実践知を共有する。
—
1. なぜ「組み込みロール」だけでは不十分なのか
Azureの組み込みロールである Contributor や Owner は便利だが、これは「特権」の塊だ。攻撃者は、Webアプリの脆弱性(RCE等)を突いた後、真っ先に az resource list や az role assignment list を叩き、自身の権限範囲を確認する。
もし君のアプリが「特定のストレージアカウントのBLOBを読み書きするだけ」でいいなら、そのアプリにはそれ以外の権限を一切与えてはならない。これを実現するのが「カスタムロール」だ。
—
2. カスタムロール設計の鉄則:アクションの「ホワイトリスト化」
カスタムロールを作る際、初心者は *(ワイルドカード)を多用しがちだが、これはNGだ。必要な Action だけをピンポイントで定義する。
以下は、Azureストレージに対して「読み込みと書き込み」のみを許可し、削除や権限変更を一切許さないカスタムロール定義(JSON)だ。
{
"Name": "Storage-Data-Operator",
"IsCustom": true,
"Description": "BLOBの読み書きのみを許可。削除と権限変更は拒否。",
"Actions": [
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/add/action"
],
"NotActions": [
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete/action"
],
"AssignableScopes": [
"/subscriptions/{サブスクリプションID}/resourceGroups/{リソースグループ名}"
]
}
ポイント:
NotActionsを活用して、絶対にやってはいけない操作(deleteなど)を明示的に除外する。AssignableScopesを特定のスコープに絞ることで、万が一の漏洩時にも影響範囲を物理的に隔離する。
—
3. 実装:Pythonでの安全なリソースアクセス
IAMの設定が完了したら、アプリケーション側でもその権限を正しく扱う必要がある。DefaultAzureCredential を使用する際も、必要最小限のクライアントのみをインスタンス化するように心掛ける。
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
# 認証情報の取得:この環境変数はマネージドID等から安全に注入される
credential = DefaultAzureCredential()
def upload_to_secure_storage(blob_name, data):
# 特定のサービスに絞ったクライアントを作成
blob_service_client = BlobServiceClient(
account_url="https://<your-account-name>.blob.core.windows.net",
credential=credential
)
blob_client = blob_service_client.get_blob_client(
container="my-container",
blob=blob_name
)
# 権限範囲内でデータをアップロード
try:
blob_client.upload_blob(data, overwrite=True)
print(f"成功: {blob_name} をアップロードしました。")
except Exception as e:
# 権限不足の場合、ここで403エラーがキャッチされる
# ログを監視していれば、即座に攻撃の兆候として検知可能
print(f"セキュリティアラート: アクセス拒否が発生しました: {e}")
# 実行
upload_to_secure_storage("report.pdf", b"Sensitive Data")
—
4. 現場のエンジニアへ:運用の泥臭いコツ
カスタムロールを導入すると、開発時に「あれもこれも動かない」という不満が必ず出る。だが、そこで妥協して Contributor を与えてはいけない。
1. 監査ログの活用: Azure Monitor や Log Analytics で「403 Forbidden」が多発している箇所を特定し、そこに必要な Action だけを少しずつ追加する。
2. Infrastructure as Code (IaC) の徹底: カスタムロール定義は手動でポータルから作らず、TerraformやBicepで管理すること。誰がいつ、どんな権限を追加したのか、Gitのコミット履歴が唯一の正当な証跡になる。
3. 定期的な棚卸し: 半年に一度は az role assignment list を吐き出し、現在アクティブなロールが本当に必要かを確認する。「以前は使っていたが、今は不要な権限」が、将来の攻撃経路になる。
セキュリティは「魔法のツール」を導入することではない。こうした、地味で泥臭い「不要な権限を削ぎ落とす作業」の積み重ねこそが、最高峰の防御壁を作るんだ。
君たちの手元にあるそのクラウド環境が、攻撃者にとって「どこを突いても塞がれている」難攻不落の要塞になることを願っている。健闘を祈る。
コメント