CloudFormation の YAML で文字列をダブルクォートで囲う必要がある場合

記事タイトルとURLをコピーする

CloudFormation を YAML で書くとき、文字列を "(ダブルクォート) で囲まないでいいと思っていました。しかし、これが無いとエラーになるというケースに遭遇しました。

ブレースを含む場合は注意

エラーになる書き方

私は以下のように書いてハマりました。

- !If [ IsGuardDuty, !Sub arn:aws:securityhub:${AWS::Region}::product/aws/guardduty, !Ref AWS::NoValue ]

f:id:swx-watanabe:20220223145343p:plain

CloudFormation を実行すると「Template format error: YAML not well-formed. (line 75, column 62)」といったエラーがでました。行数・列数は {(ブレース) を指しています。 擬似パラメータ ${AWS::Region} の部分が問題とわかりました。

正しい書き方

このようにダブルクォートをつけると正しく処理されます。

- !If [ IsGuardDuty, !Sub "arn:aws:securityhub:${AWS::Region}::product/aws/guardduty", !Ref AWS::NoValue ]

また、配列を複数行に分けて書く場合は、ダブルクォートがなくても動きました。

ProductArn:
  - !If 
    - IsGuardDuty
    - !Sub arn:aws:securityhub:${AWS::Region}::product/aws/guardduty
    - !Ref AWS::NoValue

もちろん、擬似パラメータを使わない場合も、ダブルクォートがなくても動きました。

ProductArn:
  - !If [ IsGuardDuty, !Sub arn:aws:securityhub:ap-northeast-1::product/aws/guardduty, !Ref AWS::NoValue ]

正確な仕様は不明ですが、このような動作が確認できました。

CloudFormationテンプレート全体

参考までにテンプレート全体も載せておきます。

AWS Security Hub 経由で Amazon EventBridge に集約された各種イベントをSNS Topicに転送しようとしています。しかし、状況によっては、あるサービスだけ転送対象から外したいと思うことがあります。

f:id:swx-watanabe:20220223144041p:plain

そこで CloudFormation の Parameters で選択できるようにしました。

f:id:swx-watanabe:20220223134227p:plain

以下は正常動作するテンプレートです。

YAMLに"(ダブルクォート)は不要と思っていたので、可能な限り省略しましたが、やむなく75-77行には記載しています。

AWSTemplateFormatVersion: 2010-09-09
Description: SNS Topic and Event Rules.
 
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Enable Notifications
        Parameters:
          - EventRuleFilterGuardduty
          - EventRuleFilterInspector
          - EventRuleFilterAccessAnalyzer
    ParameterLabels: 
      EventRuleFilterGuardduty: 
        default: GuardDuty
      EventRuleFilterInspector: 
        default: Inspector"
      EventRuleFilterAccessAnalyzer: 
        default: Access Analyzer
Parameters:
  EventRuleFilterGuardduty:
    Type: String
    AllowedValues: [yes,no]
    Default: yes
  EventRuleFilterInspector:
    Type: String
    AllowedValues: [yes,no]
    Default: no
  EventRuleFilterAccessAnalyzer:
    Type: String
    AllowedValues: [yes,no]
    Default: yes
Conditions:
  IsGuardDuty: !Equals [ !Ref EventRuleFilterGuardduty, yes ]
  IsInspector: !Equals [ !Ref EventRuleFilterInspector, yes ]
  IsAccessAnalyzer: !Equals [ !Ref EventRuleFilterAccessAnalyzer, yes ]
 
Resources:
  SecurityHubTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: SecurityHubTopic
  SecurityHubTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    DependsOn: SecurityHubTopic
    Properties: 
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: SecurityHubEvents
            Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action:
              sns:Publish
            Resource:
              !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:SecurityHubTopic
      Topics:
        - !Ref SecurityHubTopic
 
  SecurityHubEventRule:
    Type: AWS::Events::Rule
    DependsOn: SecurityHubTopic
    Properties:
      Name: SecurityHubFindings
      EventPattern:
        source: 
          - aws.securityhub
        detail-type:
          - Security Hub Findings - Imported
        detail:
          findings:
            ProductArn:
              - !If [ IsGuardDuty, !Sub "arn:aws:securityhub:${AWS::Region}::product/aws/guardduty", !Ref AWS::NoValue ]
              - !If [ IsInspector, !Sub "arn:aws:securityhub:${AWS::Region}::product/aws/inspector", !Ref AWS::NoValue ]
              - !If [ IsAccessAnalyzer, !Sub "arn:aws:securityhub:${AWS::Region}::product/aws/access-analyzer", !Ref AWS::NoValue ]
      Targets:
        - Arn: !Ref SecurityHubTopic
          Id: TargetSecurityHubTopic

渡辺 信秀(記事一覧)

2017年入社 / 地味な内容を丁寧に書きたい