CloudFormation 文字列の配列をパラメータで渡してテンプレートを実行したいとき、CommaDelimitedListを使ってみる

2021.07.29

CloudFormationのパラメータで文字列を配列で渡したいときどう指定するのか調べる機会がありました。テンプレートのサンプルと共にまとめておきます。

まとめ

  • パラメータのデータタイプCommaDelimitedListが文字列の配列形式タイプ
  • ,区切りで文字列を並べていく
    • 例)"Sapporo, Kitami, Abashiri"
  • 配列に入れたい文字列が多くなるとパラメータが見づらくなる
    • 本当にパラメータから文字列を配列で渡したいのか一考の余地あり

例題

配列で文字列をパラメータで渡す例として、AWS WAFにホワイトリスト形式のIPアドレス制限をかけるとします。その際に復数のIPアドレスをホワイトリストに追加したいため、復数のIPアドレスのリストをパラメータとして受け取って実行したい。

サンプルのテンプレートではWAF本体は作成せず、許可または拒否したいIPアドレスのリストを定義するIP setsのみ作成します。

WAF本体も作成したい場合は以下のブログポストを参考にしてください。

ベタ書きの例

アクセスを許可したいIPアドレスが復数ある場合、テンプレートは以下の記述になります。Addresses配下のIPアドレス部分をパラメータとして受け取りたい場合どうするのか?を見ていきましょう。

Resources:
  IPWhiteList:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: Custom-ipaddress-whitelist
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses:
	  	- 1.1.1.1/32
	  	- 2.2.2.2/32
	  	- 3.3.3.3/32

Addressesで指定するCIDR表記のIPアドレスは数値ではなく文字列の配列扱いとなっています。

パラメータのデータタイプ

よく使われるStringNumberなどのデータ型のひとつにCommaDelimitedListがあります。これは,区切りで文字列の配列を渡せます。Default:で初期値で文字列の配列を設定しています。

ipset.yml

AWSTemplateFormatVersion: 2010-09-09
Description: WAF IPSet

Parameters:
  AllowAddresses:
    Description: IP list to allow access.
    Type: CommaDelimitedList
    Default: "1.1.1.1/32, 2.2.2.2/32, 3.3.3.3/32"

Resources:
  IPWhiteList:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: Custom-ipaddress-whitelist
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses: !Ref AllowAddresses

マネジメントコンソールからスタック作成

先ほどのテンプレートからスタックを作成してみます。パラメータで復数値を渡せるのですが、指定する値が多くなると非常に分かりづらくなります。

実行結果

AWS CLIからスタック作成

AWS CLIからスタックを作成します。パラメータ指定用のJSONファイルを用意して引数でファイルを渡します。

AWS CLIからなら上手いこと見やすくできないかと考えたみたのですが結局こうなりました。これまた分かりづらいですね。

parameters.json

[
	{
		"ParameterKey": "AllowAddresses",
		"ParameterValue": "4.4.4.4/32, 5.5.5.5/32, 6.6.6.6/32, 7.7.7.7/32"
	}
]

AWS CLIからスタックを作成します。引数でJSONファイルを渡しています。

aws cloudformation create-stack \
	--stack-name sample-ipsetlist \
	--template-body file://./ipset.yml \
	--parameters file://./parameters.json

実行結果

補足: Refでパラメータの値を取り出すとき

今回の場合、CommaDelimitedListのパラメータの値を!Ref関数で取り出すときは下記の様に指定します。

      Addresses: !Ref AllowAddresses

IPアドレス直接指定してたときは下記の書式です。-付きで指定していました。

      Addresses:
	  	- 1.1.1.1/32

上記を真似て下の様に-付きの書式でテンプレートを作成してみました。このテンプレートからスタックを作成するとエラーでリソースの作成に失敗します。

      Addresses:
	  	- !Ref AllowAddresses

本来は文字列(String)で指定するところにJSON形式の配列が入ってくるため、下記のエラーになります。

Resource handler returned message: "Model validation failed (#/Addresses/0: expected type: String, found: JSONArray)"

些細な違いでエラーになるため指定方法には注意が必要です。このエラーについて書き残したかったがためにまとめました。

おわりに

外部からパラメータとして配列で文字列を渡したいときにはCommaDelimitedListが使えます。今回は文字列の対象がIPアドレスだったこともあり、非常に見づらい結果となりました。本当に外部からパラメータとして文字列の配列をもらい受ける必要があるのかを再考した方がよいかなといった感想です。

Resources:
  IPWhiteList:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: Custom-ipaddress-whitelist
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses:
	  	- 1.1.1.1/32  # ymlならコメントも書けるし、後で見ても分かりやすい
	  	- 2.2.2.2/32  # A社のIPアドレス
	  	- 3.3.3.3/32  # B社のIPアドレス