You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS CloudFormation Fn::ForEach语法错误排查求助

问题描述

我有一个生成嵌套对象的脚本,希望在CloudFormation模板中循环这些对象创建资源。脚本会动态生成对象字符串,部分参数(如pCompanyAccountIds4)可能不存在,需对除pCompanyAccountIds1外的参数做条件检查。但模板运行时报错:

Transform AWS::LanguageExtensions failed with: Fn::ForEach collection must be a list of strings

参数示例:

{
  "Parameters": {
    "pCompanyAccountIds1": "COMPANY-ACC-001,COMPANY-ACC-002,COMPANY-ACC-003",
    "pCompanyAccountIds2": "COMPANY-ACC-004,COMPANY-ACC-005",
    "pCompanyAccountIds3": "COMPANY-ACC-006",
    "pCompanyAccountIds4": "COMPANY-ACC-007,COMPANY-ACC-008"
  }
}

原模板代码:

---
Transform: 'AWS::LanguageExtensions'
###
## Parameters
Parameters:
  pCompanyAccountIds1:
    Description: First batch of company account IDs
    Type: CommaDelimitedList

  pCompanyAccountIds2:
    Description: Second batch of company account IDs
    Type: CommaDelimitedList
    Default: ""

  pCompanyAccountIds3:
    Description: Third batch of company account IDs
    Type: CommaDelimitedList
    Default: ""

  pCompanyAccountIds4:
    Description: Fourth batch of company account IDs
    Type: CommaDelimitedList
    Default: ""

OutputName:
  Description: The name of the output
  Value: pCompanyAccountIds1
###
## Resources
Resources:
  'Fn::ForEach::CloudTrailShares':
    - AccountId
    - [
        !Ref pCompanyAccountIds1,
        !Ref pCompanyAccountIds2,
        !Ref pCompanyAccountIds3,
        !Ref pCompanyAccountIds4
      ]
    - 'CloudTrailFilter${AccountId}':
        Type: AWS::LakeFormation::DataCellsFilter
        Properties:
          TableCatalogId: !Ref 'AWS::AccountId'
          DatabaseName: !Ref pDatabaseName
          TableName: !Ref pCloudtrailTableName
          Name: !Join ['_', ['cloudtrail', !Ref AccountId]]
          RowFilter:
            FilterExpression: !Sub "accountid='${AccountId}'"
          ColumnWildcard: {}
      'CloudTrailPermission${AccountId}':
        Type: AWS::LakeFormation::PrincipalPermissions
        Properties:
          Principal:
            DataLakePrincipalIdentifier: !Ref AccountId
          Permissions: ['SELECT']
          PermissionsWithGrantOption: ['SELECT']
          Resource:
            DataCellsFilter:
              TableCatalogId: !Ref 'AWS::AccountId'
              Name: !Select
                      - 3
                      - !Split
                        - '|'
                        - !Ref
                            Fn::Sub: 'CloudTrailFilter${AccountId}'
              TableName: !Ref pCloudtrailTableName
              DatabaseName: !Ref pDatabaseName
解决方案

问题根源

  1. 集合格式错误:Fn::ForEach要求遍历的集合是单一字符串列表,但原模板直接传入多个CommaDelimitedList参数的引用,导致集合变成「列表的列表」(比如[[ACC1,ACC2], [ACC3], ...]),不符合要求。
  2. 空参数处理不当:可选参数的Default设为"",会被CommaDelimitedList类型解析为包含空字符串的列表[""],遍历会生成无效资源。
  3. 资源引用逻辑错误:原模板通过拆分!Ref返回的ARN获取DataCellsFilter名称,这种方式不可靠,应该直接引用资源属性。

修复步骤

  1. 合并并过滤有效账户ID:用Fn::Flatten合并所有账户ID列表,再用Fn::Filter移除空元素,生成单一字符串列表供Fn::ForEach遍历。
  2. 修正参数默认值:将可选参数的Default从""改为[],确保空参数对应空列表而非含空字符串的列表。
  3. 修复资源引用:使用!GetAtt直接获取DataCellsFilter的Name属性,替代拆分ARN的方式。

修复后的模板代码

---
Transform: 'AWS::LanguageExtensions'
###
## Parameters
Parameters:
  pCompanyAccountIds1:
    Description: First batch of company account IDs
    Type: CommaDelimitedList

  pCompanyAccountIds2:
    Description: Second batch of company account IDs
    Type: CommaDelimitedList
    Default: []

  pCompanyAccountIds3:
    Description: Third batch of company account IDs
    Type: CommaDelimitedList
    Default: []

  pCompanyAccountIds4:
    Description: Fourth batch of company account IDs
    Type: CommaDelimitedList
    Default: []

  pDatabaseName:
    Description: Name of the target database
    Type: String

  pCloudtrailTableName:
    Description: Name of the CloudTrail table
    Type: String

OutputName:
  Description: The name of the output
  Value: !Join [",", !Ref pCompanyAccountIds1]
###
## Resources
Resources:
  'Fn::ForEach::CloudTrailShares':
    - AccountId
    - !Filter
        - !Not [!Equals ["", !Ref AccountIdItem]]
        - !Flatten
            - [
                !Ref pCompanyAccountIds1,
                !Ref pCompanyAccountIds2,
                !Ref pCompanyAccountIds3,
                !Ref pCompanyAccountIds4
              ]
    - 'CloudTrailFilter${AccountId}':
        Type: AWS::LakeFormation::DataCellsFilter
        Properties:
          TableCatalogId: !Ref 'AWS::AccountId'
          DatabaseName: !Ref pDatabaseName
          TableName: !Ref pCloudtrailTableName
          Name: !Join ['_', ['cloudtrail', !Ref AccountId]]
          RowFilter:
            FilterExpression: !Sub "accountid='${AccountId}'"
          ColumnWildcard: {}
      'CloudTrailPermission${AccountId}':
        Type: AWS::LakeFormation::PrincipalPermissions
        Properties:
          Principal:
            DataLakePrincipalIdentifier: !Ref AccountId
          Permissions: ['SELECT']
          PermissionsWithGrantOption: ['SELECT']
          Resource:
            DataCellsFilter:
              TableCatalogId: !Ref 'AWS::AccountId'
              DatabaseName: !Ref pDatabaseName
              TableName: !Ref pCloudtrailTableName
              Name: !GetAtt ['CloudTrailFilter${AccountId}', Name]

内容的提问来源于stack exchange,提问作者user12494839

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 11:36:17