しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

よく使う Resource Provider を Azure サブスクリプションに一括登録するスクリプトを書いた

新しく作成した Azure サブスクリプションを使うと、たまに特定の Resource Provider が登録されていなくてリソースの作成時にエラーとなることがあります。

Azure Portal からサブスクリプションへの強い権限を持っていれば勝手に登録されますが、Terraform 向けに権限を与える場合にはまることが多いです。Resource Provider が登録されていないサブスクリプションで Terraform で使うと以下のようなエラーが返ってきます。

Error: Error creating Application Insights "***" (Resource Group "***"): insights.ComponentsClient#CreateOrUpdate: Failure responding to request: StatusCode=409 -- Original Error: autorest/azure: Service returned an error. Status=409 Code="MissingSubscriptionRegistration" Message="The subscription is not registered to use namespace 'microsoft.insights'. See https://aka.ms/rps-not-found for how to register subscriptions."

特に調べることもなくエラーコードの MissingSubscriptionRegistration から原因は分かります。一応ドキュメントも用意されていますが、内容としては Resource Provider を登録しろという話しか書いていません。

Azure Portal / Azure PowerShell / Azure CLI それぞれでの Resource Provider 登録方法が載っています。

一番簡単なのは Azure Portal から実行することですが、Resource Provider は数が結構多いのと Resource Manager への知識がないと、どの Resource Provider が対応するのか分からないという問題があります。

ちなみにサブスクリプション単位で紐付くので、Azure Portal から確認する場合はサブスクリプションを選んでください。検索では出てこないので知らないとはまるポイントです。

一般的な Resource Provider ぐらいはデフォルトで登録しておいてほしい気持ちしかないのですが、どうしようもないので少しでも楽するためにスクリプトを書きました。

よく使われるであろう Resource Provider を一括で登録するので、Azure Portal でポチポチやるよりも圧倒的に楽です。大抵のケースではこれで十分だと思われます。

resourceProviders=(\
  "Microsoft.ApiManagement" \
  "Microsoft.AppPlatform" \
  "Microsoft.Authorization" \
  "Microsoft.Automation" \
  "Microsoft.Blueprint" \
  "Microsoft.BotService" \
  "Microsoft.Cache" \
  "Microsoft.Cdn" \
  "Microsoft.CognitiveServices" \
  "Microsoft.Compute" \
  "Microsoft.ContainerInstance" \
  "Microsoft.ContainerRegistry" \
  "Microsoft.ContainerService" \
  "Microsoft.CostManagement" \
  "Microsoft.CustomProviders" \
  "Microsoft.Databricks" \
  "Microsoft.DataLakeAnalytics" \
  "Microsoft.DataLakeStore" \
  "Microsoft.DataMigration" \
  "Microsoft.DBforMariaDB" \
  "Microsoft.DBforMySQL" \
  "Microsoft.DBforPostgreSQL" \
  "Microsoft.DesktopVirtualization" \
  "Microsoft.Devices" \
  "Microsoft.DevSpaces" \
  "Microsoft.DevTestLab" \
  "Microsoft.DocumentDB" \
  "Microsoft.EventGrid" \
  "Microsoft.EventHub" \
  "Microsoft.HDInsight" \
  "Microsoft.HealthcareApis" \
  "Microsoft.KeyVault" \
  "Microsoft.Kusto" \
  "microsoft.insights" \
  "Microsoft.Logic" \
  "Microsoft.MachineLearningServices" \
  "Microsoft.Maintenance" \
  "Microsoft.ManagedIdentity" \
  "Microsoft.ManagedServices" \
  "Microsoft.Management" \
  "Microsoft.Maps" \
  "Microsoft.MarketplaceOrdering" \
  "Microsoft.Media" \
  "Microsoft.MixedReality" \
  "Microsoft.Network" \
  "Microsoft.NotificationHubs" \
  "Microsoft.OperationalInsights" \
  "Microsoft.OperationsManagement" \
  "Microsoft.PowerBIDedicated" \
  "Microsoft.Relay" \
  "Microsoft.RecoveryServices" \
  "Microsoft.Resources" \
  "Microsoft.Search" \
  "Microsoft.Security" \
  "Microsoft.SecurityInsights" \
  "Microsoft.ServiceBus" \
  "Microsoft.ServiceFabric" \
  "Microsoft.ServiceFabricMesh" \
  "Microsoft.Sql" \
  "Microsoft.Storage" \
  "Microsoft.StreamAnalytics" \
  "Microsoft.TimeSeriesInsights" \
  "Microsoft.Web" \
)

for provider in ${resourceProviders[@]}; do
  az provider register --namespace $provider
done

# Provider の登録状況を確認したい場合に使う
#for provider in ${resourceProviders[@]}; do
#  az provider show --namespace $provider --query "{namespace: namespace, registrationState: registrationState}"
#done

Cloud Shell にコピペして実行すると、現在のサブスクリプションに対して Resource Provider を登録します。もしくは以下の 1 行を Cloud Shell にコピペしても同じように実行できます。

curl -s https://gist.githubusercontent.com/shibayan/e37307ba05a91cac884872505a4625f6/raw/resource-providers.sh | bash

1 つのテナントにサブスクリプションが複数ある場合は az account listaz account set を使って対象を切り替えてください。Azure CLI を使っているので az を使う必要があります。

実際に上のスクリプトを実行すると、未登録のものに関してはメッセージが出力されるので、どの Resource Provider が今回追加されたのか分かるようになっています。

今度は Resource Provider がほぼ登録されているサブスクリプションを使って登録状況の確認側を実行してみると、以下のように Resource Provider 名と登録状況が出力されます。

今回の Resource Provider 一覧は Terraform が暗黙的に登録しているものを拾ってきました。こういう事情があるので Terraform と組み合わせる限りは問題にならないはずです。

サブスクリプションへの強い権限があれば Terraform を実行するだけで、上のスクリプトと同じ効果が得られますが、現実的にはリソースグループへの権限だけ割り当てることも多いかと思います。

しかしリソースグループへの権限だけを割り当てている場合は Resource Provider の登録周りでエラーになってしまうので、利用する場合は skip_provider_registration = true を追加する必要があります。

それなりにはまりどころはありますが、最小限の権限だけを与えるためには必要な作業です。Resource Manager は結構よい仕組みだと思っていますが、いかんせん上手く運用できていない感が若干します。