awslabs/aws-cfn-template-flip

Using cfn_flip.to_yaml with clean_up=True results in invalid template (Template error: every value of the context object of every Fn::Sub object must be a string or a function that returns a string)

emocibob opened this issue · 2 comments

Hi,

I have a yaml template I convert to json and then back to yaml again. Using cfn_flip.to_yaml with clean_up=True results in an invalid CloudFormation template.

Full example:

import cfn_flip

correct_yaml = """
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  ExtraManagedPolicies:
    Type: CommaDelimitedList
    Default: ""

Conditions:
  HasExtraManagedPolicies: !Not
    - !Equals
      - !Join [ "", !Ref ExtraManagedPolicies ]
      - ""

Resources:
  DemoRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          Effect: Allow
          Principal:
            Service:
              - sagemaker.amazonaws.com
          Action:
            - "sts:AssumeRole"
      Path: /
      # The combination of !Join and !Split below is used to create a list of managed policies (AWSCodeCommitPowerUser and optionally ExtraManagedPolicies)
      ManagedPolicyArns: !Split
        - ","
        - !Join
          - ","
          - - "arn:aws:iam::aws:policy/AWSCodeCommitPowerUser"
            - !If [ HasExtraManagedPolicies, !Join [ ",", !Ref ExtraManagedPolicies ] , !Ref "AWS::NoValue" ]
"""

converted_to_json_str = cfn_flip.to_json(correct_yaml)
wrong_yaml = cfn_flip.to_yaml(converted_to_json_str, clean_up=True)

print(wrong_yaml)

Trying to deploy wrong_yaml from the example above results in the following error:

Template error: every value of the context object of every Fn::Sub object must be a string or a function that returns a string

This is the problematic code in wrong_yaml:

        - !Sub
          - arn:aws:iam::aws:policy/AWSCodeCommitPowerUser,${Param1}
          - Param1: !If
              - HasExtraManagedPolicies
              - Fn::Join:
                  - ','
                  - !Ref 'ExtraManagedPolicies'
              - !Ref 'AWS::NoValue'

!Sub can't handle AWS::NoValue.

cfn_flip version:

❯ python3 -m cfn_flip --version
AWS Cloudformation Template Flip, Version 1.2.3

Hi @emocibob,

Thanks for opening this issue. I'm able to reproduce this behavior on my side.
The problem here is the use of the clean_up=True that when converting the template we do some opinionated optimizations in the template to replace Join with Sub. In this process we didn't check the existence of NoValue and in this conversion we end up generating an invalid template.

To workaround your scenario you can use the conversion with clean_up=False and this will generate a valid document for you.
I will take a look in adding a check to avoid optimizations in scenarios where we have AWS::NoValue in the parameters

Hi,

Sorry for the late reply, I can confirm that the workaround with clean_up=False works.
Thanks for the feedback, have a nice day :)