ARMテンプレートで他のリソースのプロパティを参照する方法
2019-07-03
azblob://2022/11/11/eyecatch/2019-07-03-arm-template-reference-000.jpg

最近勝機を零してる木下です。

タイトル通りで最近Azure上にARMテンプレートで環境構築する際に単純な事ですがちょっと詰まったのでほぼ備忘録として書きます。
因みに木下のARM歴は1ヶ月程度なので記事に関する鉞歓迎です。

やりたい事

ざっくりとAzure上にSQL Server立ててそこにアクセスできる踏み台VMを構築する。
環境構築にはARM(Azure Resource Manager)を用いるので、デプロイ実行時SQL Serverを立てる際にfire wallへのip address許可の設定を行いたい。

詰まった事

まず何も考えずにAzure PortalでSQL serverとPubric ipを作成します。
リソースが作成出来たらPortal上でSQL serverの[ファイアウォールと仮想ネットワーク]を開き、作成したPubric ipの IP アドレスを入力して[保存]をクリック。
後はリソースグループのテンプレートをエクスポートして、よしなに整えれば完了かと思ってjsonファイルを確認してるとsql serverのfirewallの設定が下記のような形式でした。

        {
            "type": "Microsoft.Sql/servers/firewallRules",
            "apiVersion": "2015-05-01-preview",
            "name": "[concat(parameters('servers_name'), '/test_rule')]",
            "dependsOn": [
                "[resourceId('Microsoft.Sql/servers', parameters('servers_name'))]"
            ],
            "properties": {
                "startIpAddress": "13.78.14.190",
                "endIpAddress": "13.78.14.190"
            }
        }

何が問題かと言うとIPアドレスがパラメータ等の参照じゃなくて入れ込みなんですよね。
このままだとデプロイしても一緒に作成したPublic Ipではアクセスできないです。
分かってたと言えば分かってたんですけど下記のNIC(Network Interfaces)の[publicIPAddress]の様にリソースIdを指定する形でもないのでどうしたものかと。

{
      "apiVersion": "2015-06-15",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[variables('nicName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
        "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "publicIPAddress": {
                "id": "[resourceId ('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
              },
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      }
}

解決方法

シンプルに結論を書くとリソース関数の[reference]を使います。そのまんまですね。
下記の[startIpAddress]と[endIpAddress]の様な形で。

        {
            "type": "Microsoft.Sql/servers/firewallRules",
            "apiVersion": "2015-05-01-preview",
            "name": "[concat(parameters('servers_name'), '/test_rule')]",
            "dependsOn": [
                "[resourceId('Microsoft.Sql/servers', parameters('servers_testipsqlserver_name'))]"
            ],
            "properties": {
                "startIpAddress": "[reference(concat('Microsoft.Network/publicIPAddresses/',parameters('ipAddressName'))).ipAddress]",
                "endIpAddress": "[reference(concat('Microsoft.Network/publicIPAddresses/',parameters('ipAddressName'))).ipAddress]"
            }
        }

全体のARMテンプレートは今回載せないですが、上記の様にfirewallを設定するようにするとデプロイ時に作成したpublic ipからのアクセスを許可できます。
[reference]関数について詳しくは公式ドキュメント参照となるのですが今回の使い方について簡単に解説します。

https://docs.microsoft.com/ja-jp/azure/azure-resource-manager/resource-group-template-functions-resource#reference

公式ドキュメントではパラメータに関して下記の様に記されていますね。

パラメーター必須Type説明
resourceName または resourceIdentifierはいstring名前またはリソースの一意の識別子。
apiVersionいいえstring指定したリソースの API バージョンです。 同じテンプレート内でリソースがプロビジョニングされない場合に、このパラメーターを追加します。 通常、yyyy-mm-dd の形式。
'Full'いいえstring完全なリソース オブジェクトを返すかどうかを指定する値。 'Full' を指定しない場合、リソースのプロパティ オブジェクトのみが返されます。 完全なオブジェクトには、リソース ID や場所などの値が含まれます。

今回の例で[reference]関数を利用している部分は下記の形ですね。

"startIpAddress": "[reference(concat('Microsoft.Network/publicIPAddresses/',parameters('ipAddressName'))).ipAddress]"

今回の場合だと必須パラメータのリソースの指定は[resourceName]として[concat]を用いて、リソースタイプとリソース名を結合させ一意のものを指定してます。
[resourceIdentifier]で一意のものを指定する場合は[resourceId]関数を用いた下記の様な形になるでしょうか。

"startIpAddress": "[reference(resourceId('Microsoft.Network/publicIPAddresses/',parameters('ipAddressName'))).ipAddress]"

[apiVersion]については今回は同一のテンプレート内で作成したリソースを対象としているので、パラメータは記載していません。

[Full]については今回の使用したipAddressは素の?プロパティオブジェクトなので、パラメータは記載せずに[reference]関数からそのままプロパティを指定しています。
referenceで取れるプロパティオブジェクトって何が有るのか等は下記の公式ドキュメントから確認しました。ここら辺はリソース毎にとれるプロパティ違うのでほぼ毎回公式ドキュメントとにらめっこする必要有りそうですね…

https://docs.microsoft.com/en-us/azure/templates/microsoft.network/2019-04-01/publicipaddresses

仮に全部載せで[reference]関数を呼ぼうとするとこんな感じでしょうか。
[apiVersion]を指定する場合は多分高確率で[resourceId]関数のパラメータにリソースグループ名やサブスクリプションIdを指定する事になると思いますが、その辺りは次が有ったらその時に説明します。

"startIpAddress": "[reference(resourceId('Microsoft.Network/publicIPAddresses/',parameters('ipAddressName')),'2019-04-01','Full').ipAddress]"

最後に

今回こんな初歩的な[reference]関数をちゃちゃっと使うレベルでもブログを書いたのは、軽くggっても日本語の記事が中々見つからなかったからです。(そもそもQiita等にARMの記事少なすぎ…)
公式ドキュメントとgithub、stackoverflow等見れば大抵解決できるんで良いんですけど、もう少し日本語圏のコミュニティ活発にはならないですかね…