AWS CloudFormation の Fn::ForEach に Resources セクションでは使えない文字列を使うとエラーになる

AWS

2023.8.24

Topics

アップデートについて

2023/Jul/26 に、CloudFormation(以下、CFn と呼ぶ)に待望のループ機能が実装されました。

これにより、今まで必要な数のリソースを同じコードで複製していましたが、「Fn::ForEach」を使用してリソースを記述することが可能になりました。

AWS CloudFormation が Fn::ForEach 組み込み関数によるループ機能を発表しました。Fn:: ForEach を使用すると、最小限のコード行でテンプレートの一部を複製できます。Fn:: ForEach を使用すると、テンプレートのレイアウトを簡略化し、自分や同僚がコードを簡単かつ迅速にレビューできるようになります。
ループ機能で CloudFormation のオーサリング体験を加速させましょう

でた当初は、面白そうなので使ってみましたがとても便利だなと思いました。
正直、CFn はこういったループを出さないと思っていたのでかなり衝撃でした。

ForEach の動作

はじめに、全体構造として以下が今回作成に使用した CFn のテンプレートです。

AWSTemplateFormatVersion: 2010-09-09
Transform: "AWS::LanguageExtensions"
Description: IAM User
Resources:
  "Fn::ForEach::HogeLoopName":
    - UserList
    - - coldAirflow
      - nhnTechorus
    - "User${UserList}":
        Type: "AWS::IAM::User"
        Properties:
          UserName: !Ref UserList

「ForEach」 の使い方はものすごく簡単で、まずは「Transform」として「AWS::LanguageExtensions」を宣言します。
「AWS::LanguageExtensions」とは、CFn によってホストされるマクロです。
簡単に言うと、拡張機能を使えるように宣言しています。
AWS::LanguageExtensions 変換 – AWS CloudFormation

Transform: "AWS::LanguageExtensions"

実際に、ループ機能を使っているのは「Resources」配下になります。
このテンプレートでは、IAM ユーザーを複数作成しています。

Fn::ForEach – AWS CloudFormation

Resources:
  "Fn::ForEach::HogeLoopName":
    - UserList
    - - coldAirflow
      - nhnTechorus
    - "User${UserList}":
        Type: "AWS::IAM::User"
        Properties:
          UserName: !Ref UserList

「UserList」にループしたときに使用する各値をリストにします。
今回の場合は、「cold.airflow」と「nhn.techorus」です。
各ループのときに「UserList 変数」に各値が格納されます。

「UserList」を元に、「AWS::IAM::User」で IAM ユーザーを作成しています。

これをデプロイすると実際に実行した場合に内部で処理されたテンプレートを見ることができます。

CFnテンプレートの展開されたテンプレート内容

「.」を使うとエラーになる

では、本題です。
この「ForEach」を使って先程と同じ様に IAM ユーザーを作ろうとしたときに遭遇したエラーです。

以下が、その時に作成したテンプレートです。

AWSTemplateFormatVersion: 2010-09-09
Transform: "AWS::LanguageExtensions"
Description: IAM User
Resources:
  "Fn::ForEach::HogeLoopName":
    - UserList
    - - cold.Airflow
      - nhn.Techorus
    - "User${UserList}":
        Type: "AWS::IAM::User"
        Properties:
          UserName: !Ref UserList

先程のテンプレートと基本的な部分は変わらないですが、「UserList」の各ユーザー名だけ変更しています。

coldAirflow → cold.Airflow

これを実行するとエラーになります。

Transform AWS::LanguageExtensions failed with: OutputKey ‘Usercold.Airflow’ should be alphanumeric. Rollback requested by user.

CFnをデプロイした場合にでた文字列のエラーログ

なぜエラーになるのか

エラーログとタイトルに書いてあるとおりですが、「Resources」に使用できない文字列「.」が含まれておりエラーになってました。
ループされるときに、「Resources」の論理 IDに各変数の名前をつけるようにしています。
そのため、変数が展開されたときにエラーとなります。

"User${UserList}"
↓ 変換される
Usercold.Airflow
↓ 実際のテンプレートに変換すると
Usercold.Airflow:
    Type: "AWS::IAM::User"
    Properties:
        UserName: cold.Airflow

「Resources」 の論理 ID には、以下制限があります。

論理 ID
論理 ID は英数字(A-Za-z0-9)とし、テンプレート内で一意である必要があります。
リソース – AWS CloudFormation

「ForEach」としては文字列の制限はないですが、ループで各値が展開されたときに各リソース部分で使えないものがでてくる可能性があります。
そのため、変数として変換された場合に使用しても問題ない値を設定する必要があります。

まとめ

好奇心で使ってみたらエラーになってびっくりしました。

基本的な対処方法は、Resources の論理 ID に使えない文字列を使わないことですが、場合によっては使いたいみたいなときは力技でやるしかないのかなと思ってます。

参考記事

リソース – AWS CloudFormation
AWS::LanguageExtensions 変換 – AWS CloudFormation
Fn::ForEach – AWS CloudFormation

Cold-Airflow

2021年新卒入社。インフラエンジニアです。RDBが三度の飯より好きです。 主にデータベースやAWSのサーバレスについて書く予定です。あと寒いのは苦手です。

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら