TerraformとAzure CLIを用いてAzure App ServiceのIP制限を構成する
2020-03-10
azblob://2022/11/11/eyecatch/2020-03-10-terraform-local-exec-app-service-ip-restriction-000.jpg

こんにちは。cloud.config Divの神田です。
今回はTerraformとAzure CLIを用いてAzure App ServiceのIP制限を構成します。

はじめに

TerraformはAzureやAWSなどのクラウドサービスのインフラ構築をサポートしていますが、
すべてのサービスのあらゆる設定を網羅しているわけではなく、
一部の機能や新しいサービスには対応していないことがあります。
App ServiceのIP制限も対応していない機能の1つであり、IPアドレスこそ指定できるものの、ルールの名前、
優先度、アクション(通信を許可するか拒否するか)を指定できません。
TerraformではなくARMテンプレートを使ったり、後から手作業でIP制限を追加するといった方法がありますが、
今回はTerraformとAzure CLIを組み合わせて構成を行います。

参考 : azurerm_app_service - Argument Reference
https://www.terraform.io/docs/providers/azurerm/r/app_service.html#argument-reference

Terraformで設定したApp ServiceのIP制限

Terraformのlocal-exec Provisionerについて

Terraformにはlocal-execという機能が用意されています。
こちらの機能はTerraformの実行時に任意のコマンドやPowerShellスクリプトを実行することができる機能です。
このlocal-execはAzure CLIやAzure PowerShellの実行も可能であり、
上記のツールを利用する際に必要なサービスプリンシパルの認証情報や、
リソースグループ名、リソース名をTerraformのコードから引数として受け取ることができます。

ただし、Terraformの公式ドキュメントではlocal-execを含むProvisionerという機能群は非推奨となっています。
詳しくは公式ドキュメントをご確認ください。

参考 : Provisioners
https://www.terraform.io/docs/provisioners/index.html

参考 : local-exec Provisioner
https://www.terraform.io/docs/provisioners/local-exec.html

今回の目標

今回はApp ServiceのIP制限に、Azure Traffic Managerの正常性プローブで使用されるIPアドレスを追加します。
Traffic Managerが用いるIPアドレスは以下のURLから飛んだ先にjson形式で公開されています。

参考 : 正常性チェックはどの IP アドレスから発信されますか。
https://docs.microsoft.com/ja-jp/azure/traffic-manager/traffic-manager-faqs#what-are-the-ip-addresses-from-which-the-health-checks-originate

そのため今回は
 1. Microsoft社が公開しているjsonから、Traffic Managerが使用するIPアドレスのリストを取得
 2. 取得したリストから各IPアドレスを、Azure CLIを用いてApp ServiceのIP制限に追加する
上記2つの動作をTerraform上で行うようにします。

方法

用いたツール

  • Azure CLI 2.1.0
  • Terraform 0.12.9
  • Azure Provider 1.41.0

以下が今回作成したスクリプトです。
local-execは動作が保障されていない機能なので、スクリプトの処理を冪等にして
動作を安定させるべきですが、今回は初期構築を想定しているので単純な内容になっています。
(初期構築だけならARMテンプレートでいい気もしますが)
なお、Azure CLIでのApp ServiceのIP制限の設定は現時点(v2.1.0)ではプレビューですのでご注意ください。

Param(
  $client_id,
  $client_secret,
  $tenant_id,
  $resource_group_name,
  $web_app_name,
  [int]$priority
)

# jsonの取得
Invoke-WebRequest https://azuretrafficmanagerdata.blob.core.windows.net/probes/azure/probe-ip-ranges.json -OutFile ./probe-ip-ranges.json
$json = ConvertFrom-Json -InputObject (Get-Content ./probe-ip-ranges.json -Raw)

# Azureへアクセス
az login --service-principal -u $client_id -p $client_secret --tenant $tenant_id

# IP制限の追加
for($i = 0; $i -lt $json.ipv4_prefixes.length; $i++){
  $j = $i + 1
  $rule_name = "Allow_Traffic_Manager_" + $j.ToString("000")
  az webapp config access-restriction add -g $resource_group_name -n $web_app_name --rule-name $rule_name --action Allow --ip-address $json.ipv4_prefixes[$i].ip_prefix --priority $priority
  $priority += 1
}

以下がTerraform側のコードです。(App Service Plan、Resource Groupのコードは省略)
local-execを使用するには、resourceブロックの末尾に、
provisioner "local-exec"ブロックを付け、commandに任意のコマンドやスクリプトのパスを渡します。
今回はAzure CLIを使用するために必要なサービスプリンシパルの認証情報や、リソースグループ名、
リソース名を引数として渡しています。
これでTerraformだけでなくスクリプトも使いまわしやすくなり、構築の効率化が図れます。

resource "azurerm_app_service" "this" {
  name                = "AppService名"
  location            = "リージョン"
  app_service_plan_id = "AppServicePlanのリソースID"
  resource_group_name = "ResourceGroup名"

  provisioner "local-exec" {
    command = "PowerShell -file ./set_traffic_manager_ip_addresses.ps1 -client_id クライアントID -client_secret クライアントシークレット -tenant_id テナントID -resource_group_name ResourceGroup名 -web_app_name AppService名 -priority 優先度"
  }
}
Terraform + Azure CLIで設定したApp ServiceのIP制限

終わりに

以上でTerraformとAzure CLIによるApp ServiceのIP制限の設定は完了です。
あらかじめ値が分かっているものを毎回手作業で設定することは無駄なので、
このように自動化していきたいです。