しばやん雑記

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

Terraform Provider for Azure v2.3.0 で Service Tags の Data Source が追加されたので試した

今日 Azure Resource Manager 向けの Terraform Provider の新バージョンがリリースされていたので、リリースノートを眺めていたら Service Tags を取るための Data Source が追加されていました。

Service Tags を取るには巨大な JSON を読み取るしかないと思っていましたが、ARM REST API が Public Preview として公開されているので、それを利用して実装しているようです。

ドキュメントは微妙に typo が多いですが、パラメータが少ないので簡単に使えます。ARM REST API の仕様がイマイチで、Service Tags を取るために location を指定する必要があり、それが Service 自体の location と混同しそうになります。

App Service などの各リージョンにデプロイされているサービスで、対象リージョンを絞り込む場合には location_filter を指定して行います。

実際に Japan East にある App Service の IP Address のリストを取得する場合には、以下のような定義を書いて terraform refresh を実行すると表示されます。

data "azurerm_network_service_tags" "default" {
  location = "Japan East"
  service  = "AppService"
  location_filter = "Japan East"
}

output "address_prefixes" {
  value = data.azurerm_network_service_tags.default.address_prefixes
}

JSON ではなく ARM REST API を使っているからか、微妙にドキュメントに書いてある Service Tags とは名前付けが異なっているケースもありました。プレビュー中は同期されるのにラグがありそうです。

VNET と NSG を使っている場合は、直接 Service Tags を条件に指定できるので IP Address のリストを使う機会はほぼなさそうですが、App Service の IP 制限では欲しいときがたまにあります。

Service Endpoints が使えるので特定の Subnet からのトラフィックのみ許可の場合は簡単に行えますが、それ以外の場合は IP Address でチマチマと書く必要がありました。*1

サンプルとして、よく使いそうな Front Door からのトラフィックのみ許可するような定義を書いてみました。

現状 Front Door の Outbound IP Range は 1 つしかないので手動でも変わらない気もしますが、もし増えた場合には自動で対応できるメリットはあります。

data "azurerm_network_service_tags" "frontdoor" {
  location = "Japan East"
  service  = "AzureFrontDoor"
}

resource "azurerm_resource_group" "default" {
  name     = "appservice-test"
  location = "Japan East"
}

resource "azurerm_app_service_plan" "default" {
  name                = "ASP-Default-01"
  location            = azurerm_resource_group.default.location
  resource_group_name = azurerm_resource_group.default.name

  sku {
    tier = "PremiumV2"
    size = "P1v2"
  }
}

resource "azurerm_app_service" "default" {
  name                = "backend-appservice-01"
  location            = azurerm_resource_group.default.location
  resource_group_name = azurerm_resource_group.default.name
  app_service_plan_id = azurerm_app_service_plan.default.id

  site_config {
    dynamic "ip_restriction" {
      for_each = data.azurerm_network_service_tags.frontdoor.address_prefixes
      content {
        ip_address = ip_restriction.value
      }
    }
  }
}

複数の IP Address が返ってくることを考慮して、Dynamic blocks を使って ip_restriction を生成するようにしています。ちょっと冗長さは否めないです。

この定義を使うと、Front Door の IP Address のみ許可する設定が追加された状態で作成されます。

必要な時にサクッと Terraform の Data Source として特定リージョンのサービスの IP Address を参照できるのは便利なのですが、割とニッチな需要という感じはします。

本当なら NSG + Service Tags や Private Link などで解決したい世界でした。

*1:Service Tags を条件に使えるようになって欲しさがある