aws-cloudformation / cfn-language-discussion

Language discussions for CloudFormation template language
https://aws.amazon.com/cloudformation/
Apache License 2.0
142 stars 13 forks source link

Transform AWS::LanguageExtensions seems to break conditions with Fn::Select #120

Closed jacky96623 closed 1 year ago

jacky96623 commented 1 year ago

Name of the resource

AWS::IAM::Role

Resource Name

No response

Issue Description

I have been using parameters and conditions to (relatively) dynamically create resources depends on a list. For example, I may have a parameter named subnets which accepts a list of subnet ID and a parameter named subnetCount which accepts an integer between 1 and 4. Then I leveraged these 2 parameters to create 4 conditions to control the creation of corresponding resources.

Recently, I noticed that the AWS CloudFormation new language extensions transform which enables conditional DeletionPolicy and started to use this transform. However, the template becomes not deployable.

Expected Behavior

The template should be deployable.

Observed Behavior

By looking at CloudFormation ChangeSet, it is reported that

Transform AWS::LanguageExtensions failed with: Fn::Select cannot select nonexistent value at index 2

Test Cases

Minimal template to reproduce:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::LanguageExtensions
Parameters:
  env:
    Type: String
    AllowedValues:
    - DEV
    - PROD
    Default: DEV
  subnets:
    Type: List<AWS::EC2::Subnet::Id>
  subnetCount:
    Type: Number
    MinValue: 1
    MaxValue: 4
Conditions:
  isProd:
    Fn::Equals:
    - Ref: env
    - PROD
  configureSubnet1:
    Fn::Or:
    - Fn::Equals:
      - Ref: subnetCount
      - 1
    - Condition: configureSubnet2
  configureSubnet2:
    Fn::Or:
    - Fn::Equals:
      - Ref: subnetCount
      - 2
    - Condition: configureSubnet3
  configureSubnet3:
    Fn::Or:
    - Fn::Equals:
      - Ref: subnetCount
      - 3
    - Condition: configureSubnet4
  configureSubnet4:
    Fn::Equals:
    - Ref: subnetCount
    - 4
Resources:
  logGroup:
    DeletionPolicy:
      Fn::If:
      - isProd
      - Retain
      - Delete
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /aws/lambda/test-lambda
      RetentionInDays:
        Fn::If:
        - isProd
        - 90
        - 30
  executionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: test-lambda-exec-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
      Policies:
      - PolicyName: allow-put-log-to-cloudwatch-policy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource:
              Fn::GetAtt:
              - logGroup
              - Arn
      - PolicyName: allow-manage-ec2-network-interface-policy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action: ec2:CreateNetworkInterface
            Resource:
            - Fn::Sub: arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:network-interface/*
            - Fn::If:
              - configureSubnet1
              - Fn::Sub:
                - arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:subnet/${subnet}
                - subnet:
                    Fn::Select:
                    - 0
                    - Ref: subnets
              - Ref: AWS::NoValue
            - Fn::If:
              - configureSubnet2
              - Fn::Sub:
                - arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:subnet/${subnet}
                - subnet:
                    Fn::Select:
                    - 1
                    - Ref: subnets
              - Ref: AWS::NoValue
            - Fn::If:
              - configureSubnet3
              - Fn::Sub:
                - arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:subnet/${subnet}
                - subnet:
                    Fn::Select:
                    - 2
                    - Ref: subnets
              - Ref: AWS::NoValue
            - Fn::If:
              - configureSubnet4
              - Fn::Sub:
                - arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:subnet/${subnet}
                - subnet:
                    Fn::Select:
                    - 3
                    - Ref: subnets
              - Ref: AWS::NoValue

Example (redacted) parameters:

[
  {
    "ParameterKey": "subnets",
    "ParemeterValue": "subnet-abc,subnet-def"
  },
  {
    "ParameterKey": "subnetCount",
    "ParameterValue": "2",
  }
]

Other Details

As a supplement, the template is deployable if you comment the top-level Transform attribute and also the conditioned DeletionPolicy.

jlhood commented 1 year ago

@jacky96623 thanks for reporting this issue! For future reference, please open CloudFormation template language-specific issues in this repo: https://github.com/aws-cloudformation/cfn-language-discussion

We'll go ahead and transfer this issue to that repo for you.

MalikAtalla-AWS commented 1 year ago

Thanks @jacky96623 for raising this issue. We will triage it with the team and notify about updates here.

MalikAtalla-AWS commented 1 year ago

Just confirming that I'm able to reproduce the problem. Really appreciate you providing the template example.

MalikAtalla-AWS commented 1 year ago

Another issue with the same root cause:

MalikAtalla-AWS commented 1 year ago

Hey @jacky96623. We have made a code change to fix this issue. It will start to make its way to production regions today and rollout to all regions will take about a week.

MalikAtalla-AWS commented 1 year ago

The bugfix has rolled out to all regions and this issue is now resolved