🔐

Azureで作る Key Vault と Managed Identity — パスワードレスなシークレット運用

に公開

概要

この記事では、Azure Key VaultをBicepでプロビジョニングし、Managed Identityを使って仮想マシンや Azure Functions から安全にシークレットへアクセスする手順を紹介します。私が普段行っている手順をベースにしています。

本記事で扱うこと:

  • Key VaultのBicep定義(RBACベースアクセス)
  • リソースに対するマネージドIDの割り当てとアクセス付与
  • 動作検証(Azure CLIを使ったシークレットの取得)
  • 運用上の注意点(アクセスポリシー vs RBAC、監査)

対象読者: Azureのインフラをコードで管理するエンジニア。私も同じ立場で運用・検証しています。

前提: Azure CLIとBicepがローカルにインストールされ、適切なAzureサブスクリプションへログイン済みであること。


前提と用語

  • Managed Identity: Azureリソースに付与するID(System-assigned / User-assigned)で、資格情報をコードに書かなくても済む便利な仕組みです。
  • Key Vaultのアクセス制御: これまでのアクセス ポリシー方式と、最近のRBACベースアクセスがあります。この記事ではRBACを基本に扱います(個人的には管理が楽なので推奨)。

なぜ Managed Identity を使うのか

Managed Identityは、パスワードやシークレットをアプリやスクリプトに埋め込まずに、AzureリソースがEntra IDのトークンを取得できる仕組みです。主な利点を簡潔に示します。

  • パスワードレス: 資格情報をソースコードや環境変数に置かないため、漏洩リスクが下がります。管理者・開発者・利用者が秘密情報を直接扱わずに済む点を推奨します。
  • 運用負荷の低減: シークレットのローテーションや配布をアプリ側で管理する必要がなく、Key VaultやEntra ID側でアクセス制御を集中管理できます。
  • 最小権限付与: RBACと組み合わせれば、必要な操作だけをリソースに許可できます。これにより人的ミスや過剰権限のリスクを減らせます。
  • 監査と可視化: 誰が/どのリソースがアクセスしたかがAzureのログで追えるため、インシデント対応やコンプライアンスで有利です。

以上により、パスワードレスで管理者、開発者、エンドユーザーが安全にシークレットを扱える環境を実現できます。可能であれば設計段階からManaged Identityを優先して採用することをおすすめします。

System-assigned と User-assigned の使い分け

Managed Identityには2つの主要な形があります。使い分けの考え方は次の通りです。

System-assigned (リソース固有)

  • リソースに紐づくIDで、リソース削除時に自動で消えます。短期間で簡単に有効化したいケースに向きます。
  • 単一リソースがKey Vault等にアクセスするだけなら手軽で設定が少なく済みます。

User-assigned (独立したID)

  • Azureリソースとは独立して存在し、複数のリソースに割り当て可能です。ライフサイクルをリソースより長く管理したい場合に向きます。
  • 複数のVMやFunctionsに同じIDを共有して権限を横断的に管理したいときに便利です。

推奨パターン:

  • 単発のテストや1つのVMに限定する短期的な用途ならSystem-assignedを使う。
  • 本番環境で複数リソースに同じ役割を付与したい、IDのライフサイクルを明確に管理したい場合はUser-assignedを採用すると良い。

両者を組み合わせることも可能です。運用ポリシーや監査の観点からIDのライフサイクルを明確にしたい場合はUser-assignedを中心に設計するのが良いでしょう。

オンプレミスや VM 外部からのアクセスの注意点

Managed IdentityはVMのIMDS経由でトークンを取得する仕組みです。オンプレミスやAzure外部の環境からは直接利用できません。簡潔な対処法針を示します。

-- 直接利用不可: IMDS (169.254.169.254) に到達できない環境ではManaged Identityは使えません。
-- 推奨(簡潔): 可能なら認証をAzure内で完結させる(Azure VM/ContainerやFunctions等)。
-- オンプレミスからの選択肢(概要): Azure Arcの導入や、Azure上にトークン発行を担う安全なプロキシを置く、あるいは証明書ベースのサービスプリンシパルなどが考えられます。
-- その他の手法: フェデレーションやWorkload Identityのようなアプローチもありますが、ここでは詳細を割愛します。

オンプレミス接続はネットワーク、認証、運用の設計負荷が高くなります。実装する場合は設計と監査を行ってください。

コード例(Bicep を例として) — Key Vault とアクセス (RBAC)

以下はBicepを例にとった簡単なテンプレート例です。Key Vaultを作成し、後からManaged Identityに対して "Key Vault Secrets User" ロールを付与する想定です。

@description('Location for all resources')
param location string = resourceGroup().location

@description('Key Vault name (must be globally unique within the resource)')
param keyVaultName string

resource keyVault 'Microsoft.KeyVault/vaults@2021-10-01' = {
  name: keyVaultName
  location: location
  properties: {
    tenantId: subscription().tenantId
    sku: {
      family: 'A'
      name: 'standard'
    }
    enablePurgeProtection: false
    enableSoftDelete: true
    networkAcls: {
      defaultAction: 'Allow'
    }
  }
}

output keyVaultId string = keyVault.id

ポイント: networkAcls はこの例では簡易設定にしています。ネットワークで制限したい場合は、VNet限定やPrivate Endpointの追加を検討してください。


マネージド ID を持つ VM からのアクセス

まずはVMを作ってSystem-assigned Managed Identityを付与してみます。手元にAzure CLIがあればすぐに試せます。

az login
az group create -n rg-sample -l japaneast
az vm create -g rg-sample -n vm-sample --image UbuntuLTS --assign-identity

次にKey VaultのリソースIDを取得して、VMのManaged Identity(principalId)に対してロールを割り当てます。

# Key Vault のリソース ID を取得
KV_ID=$(az keyvault show -n <your-keyvault-name> --query id -o tsv)

# VM のプリンシパル ID を取得
PRINCIPAL_ID=$(az vm identity show -g rg-sample -n vm-sample --query principalId -o tsv)

# ロール付与: Key Vault Secrets User
az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal \
  --role "Key Vault Secrets User" --scope $KV_ID

VM内からはManaged Identityでログインしてシークレットを取得できます。

az login --identity
az keyvault secret show --vault-name <your-keyvault-name> -n <secret-name> --query value -o tsv

注意: 上の手順はVM側で az (Azure CLI) が使えることが前提です。多くのLinux VM (Ubuntu等) ではパッケージ経由で簡単にインストールできます。簡易インストール例(Ubuntu):

# 公式の簡易インストールスクリプトを使う例
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# その後、az login --identity 等を実行

もしセキュリティ方針や環境制約でAzure CLIをインストールできない場合は、VM内から直接IMDS (Instance Metadata Service) 経由でアクセストークンを取得し、Key VaultのREST APIをcurl等で呼ぶ方法もあります。以下はその最小例です。

  1. IMDSからKey Vault用のアクセストークンを取得
# 注意: Metadata ヘッダが必須
ACCESS_TOKEN=$(curl -s 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net' -H 'Metadata:true' \
  | python -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
  1. Key VaultのシークレットをREST APIで取得
curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  https://<your-keyvault-name>.vault.azure.net/secrets/<secret-name>?api-version=7.3

# 値だけ取り出す場合は jq 等で加工(jq が無ければ簡易パースも可)
  • ポイント:

  • 上記のIMDSエンドポイント (169.254.169.254) はAzure VM内からのみ到達可能です。

  • resourceパラメータは必ずURLエンコード済みで https://vault.azure.net を指定します。

  • LinuxにjqやPythonが無い環境もあるので、トークン抽出は環境に合わせて調整してください。


Azure Function での利用(簡易例)

Azure Functionsにも同じ要領でManaged Identityを付与して、Key Vault側でRBACを割り当てればOKです。アプリ側はSDKのDefaultAzureCredentialを使うだけでシークレットが取得できます。

Pythonの例をひとつ。

import os
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
vault_url = os.environ.get("KEYVAULT_URI")
client = SecretClient(vault_url=vault_url, credential=credential)

secret = client.get_secret("my-secret")
print(secret.value)

運用上の注意点


まとめ

BicepでKey Vaultを作成し、Managed Identityを使って安全にシークレットを扱う流れを紹介しました。実運用ではネットワークや監査、ローテーション周りまで設計しておくと安心です。

次にやるなら、Key VaultをPrivate Endpoint化してVNet内からのみアクセスする手順を書いてみると良いでしょう。

参考

あとがき(制作について)

この記事の作成には以下の協力・手順を取り入れています。

  • GitHub Copilot(GPT-5-mini)に草案作成や校正の支援を受けました。
  • ただし、本文に書くべき内容の最終的な精査と責任は著者のよたんが負っています。
  • よたんの過去記事を参照して文体を揃えるように調整しました。

技術的な内容は環境やバージョンで挙動が変わる可能性があります。実運用前に必ず検証してください。

Discussion