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
解决方案
问题根源
- 集合格式错误:
Fn::ForEach要求遍历的集合是单一字符串列表,但原模板直接传入多个CommaDelimitedList参数的引用,导致集合变成「列表的列表」(比如[[ACC1,ACC2], [ACC3], ...]),不符合要求。 - 空参数处理不当:可选参数的
Default设为"",会被CommaDelimitedList类型解析为包含空字符串的列表[""],遍历会生成无效资源。 - 资源引用逻辑错误:原模板通过拆分
!Ref返回的ARN获取DataCellsFilter名称,这种方式不可靠,应该直接引用资源属性。
修复步骤
- 合并并过滤有效账户ID:用
Fn::Flatten合并所有账户ID列表,再用Fn::Filter移除空元素,生成单一字符串列表供Fn::ForEach遍历。 - 修正参数默认值:将可选参数的
Default从""改为[],确保空参数对应空列表而非含空字符串的列表。 - 修复资源引用:使用
!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
相关产品推荐
相关产品推荐

