AWS CloudFormationで名前に - が使えなくて困ったこと

AWSの環境ではWAF など、名前に - が使えない物があります。

CloudFormationからWAFの設定をしようとした時に少し困ったのでメモを残しておきます。

何に困ったのか?

CloudFormationのテンプレートで、Parametersから入ってくる変数の値に - が入っていると Name を設定するときにエラーになってしまう。

最初に作成したテンプレートは↓です。

AWSTemplateFormatVersion: '2010-09-09'
Description: WAF CI/CD Pipeline

Parameters:
  ProductName:
    Type: String
  Stage:
    Type: String
    Default: prod

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Product Configuration
        Parameters:
          - ProductName
          - Stage
    ParameterLabels:
      ProductName:
        default: ProductName
      Stage:
        default: Stage

Resources:
  WAF:
    Type: AWS::WAF::WebACL
    Properties:
      Name: !Sub ${ProductName}${Stage}
      MetricName: !Sub ${ProductName}${Stage}
      DefaultAction:
        Type: BLOCK
      Rules:
        - Action:
            Type: ALLOW
          Priority: 1
          RuleId: !Ref WAFRule

  WAFRule:
    Type: AWS::WAF::Rule
    Properties:
      Name: !Sub ${ProductName}MyIp${Stage}
      MetricName: !Sub ${ProductName}MyIp${Stage}
      Predicates:
        - DataId: !Ref WAFIPSet
          Negated: false
          Type: IPMatch

  WAFIPSet:
    Type: AWS::WAF::IPSet
    Properties:
      Name: !Sub ${ProductName}-my-ipset-${Stage}
      IPSetDescriptors:
        - Type: IPV4
          Value: {IPアドレス}/32

モックアプリを作っていたので、 ProductName には hoge-mock という感じで - 付きにしていました。
AWS::WAF::WebACL AWS::WAF::RuleName には - が使えないので、ココでエラーが出てしまいます。

Stage は、環境を表していて、 prod stg dev などの文字が入ってきます。

- を消す方法(テンプレートの変換の流れ)

どうにか - を消せないかとイロイロ試したところ↓の方法で - を消すことができました。

      Name:
        !Join
          - ''
          - - !Join
                - ''
                - !Split
                    - '-'
                    - !Ref ProductName
            - !Ref Stage

!Ref のところを展開します。

      Name:
        !Join
          - ''
          - - !Join
                - ''
                - !Split
                    - '-'
                    - hoge-mock
            - prod

!Splithoge-mock を、 - で分割した配列に変えます。

      Name:
        !Join
          - ''
          - - !Join
                - ''
                - - hoge
                  - mock
            - prod

!Join[hoge, mock] を、文字列に変換します。

      Name:
        !Join
          - ''
          - - hogemock
            - prod

!Join[hogemock, prod] を、文字列に変換します。

      Name:
        hogemockprod

こういう変換の流れで、 - を消すことができました。

完成形

AWSTemplateFormatVersion: '2010-09-09'
Description: WAF CI/CD Pipeline

Parameters:
  ProductName:
    Type: String
  Stage:
    Type: String
    Default: prod

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Product Configuration
        Parameters:
          - ProductName
          - Stage
    ParameterLabels:
      ProductName:
        default: ProductName
      Stage:
        default: Stage

Resources:
  WAF:
    Type: AWS::WAF::WebACL
    Properties:
      Name:
        !Join
          - ''
          - - !Join
                - ''
                - !Split
                    - '-'
                    - !Ref ProductName
            - !Ref Stage
      MetricName:
        !Join
          - ''
          - - !Join
                - ''
                - !Split
                    - '-'
                    - !Ref ProductName
            - !Ref Stage
      DefaultAction:
        Type: BLOCK
      Rules:
        - Action:
            Type: ALLOW
          Priority: 1
          RuleId: !Ref WAFRule

  WAFRule:
    Type: AWS::WAF::Rule
    Properties:
      Name:
        !Join
          - ''
          - - !Join
                - ''
                - !Split
                    - '-'
                    - !Ref ProductName
            - MyIp
            - !Ref Stage
      MetricName:
        !Join
          - ''
          - - !Join
                - ''
                - !Split
                    - '-'
                    - !Ref ProductName
            - MyIp
            - !Ref Stage
      Predicates:
        - DataId: !Ref WAFIPSet
          Negated: false
          Type: IPMatch

  WAFIPSet:
    Type: AWS::WAF::IPSet
    Properties:
      Name: !Sub ${ProductName}-my-ipset-${Stage}
      IPSetDescriptors:
        - Type: IPV4
          Value: {IPアドレス}/32

参考URL

Fn::Join - AWS CloudFormation

Fn::Split - AWS CloudFormation