42

I know that it is possible via the use of Conditions to conditionally (what else?) create resources.

I am trying to find a way though to conditionally create properties of resources;

in my case I am creating several EC2 instances in a subnet with default public ip assignment = false.

Sometimes though for debugging purposes I want my instances to get public IPs.

Now I have to comment in/out the SG/Subnet and the NetworkInterfaces properties below (those do not go together)

  myEC2:
    Type: AWS::EC2::Instance
    Metadata:
      Comment: My EC2 Instance
      AWS::CloudFormation::Init:
        config:
          commands:
            01_provision:
              command:
                !Sub |
                  sed -i "s/somestring/${somevar}/" /some/path/
    CreationPolicy:
      ResourceSignal:
        Timeout: PT4M
    Properties:
      ImageId: !FindInMap [ MyAamiMap, 'myami', amiid ]
      InstanceType: "t2.2xlarge"
      # SubnetId: !Ref SBNDemo1
      # SecurityGroupIds: [!Ref SGInternalDemo]
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          GroupSet:
            - Ref: "SGInternalDemo"
          SubnetId:
            Ref: "SBNDemo1"
      UserData:
        "Fn::Base64":
          !Sub |
            #!/bin/bash -xe
            # Start cfn-init
            /usr/local/bin/cfn-init -s ${AWS::StackId} -r myEC2 --region ${AWS::Region} || echo 'Failed to run cfn-init'
            # All done so signal success
            /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource myEC2 --region ${AWS::Region}

Any suggestions?

1
  • do you know you can now use aws lambda in cloud formation, can that be useful in your case ?
    – varnit
    Commented Dec 5, 2018 at 12:57

3 Answers 3

91

This might be a little late, but I recently had a same question.

From AWS docs, you can use Fn::If to set properties accordingly.

The template will look like:

Properties:
  ImageId: !FindInMap [ MyAamiMap, 'myami', amiid ]
  InstanceType: "t2.2xlarge"
  # SubnetId: !Ref SBNDemo1
  # SecurityGroupIds: [!Ref SGInternalDemo]
  NetworkInterfaces:
    !If
    - YourCondition
    - 
      AssociatePublicIpAddress: "true"
      DeviceIndex: "0"
      GroupSet:
        - Ref: "SGInternalDemo"
      SubnetId:
        Ref: "SBNDemo1"
    - !Ref "AWS::NoValue"

AWS::NoValue means there will be no NetworkInterfaces properties set.

4
  • 2
    This "AWS::NoValue" is what I've been looking for months now to conditionale enable webhook for a CodeBuild project based on a parameter. Is it just me or this isn't anywhere nearly documented enough? Thanks man! Commented Jan 7, 2021 at 1:52
  • Awesome! I think I had tried this previously, but I put the !If statement above NetworkInterfaces instead of inside of it and I wasn't successful. I'm glad my coworker sent me a link to this!
    – Brandon
    Commented Oct 12, 2021 at 19:26
  • tried it with serverless lambda function, didn't work. Events: !Ref "AWS::NoValue"
    – coolman
    Commented Feb 22, 2023 at 3:36
  • Note: this doesn't work on the top level of resource properties, even when the top level property is optional. For example, you couldn't conditionally define instanceType property using an !If block (you would get a syntax error), and that is a significant limitation. Commented Mar 25 at 22:12
1

Perhaps I am misunderstanding but this sounds like a parameter use case rather than a condition use case. I say that because you do not say under what conditions you would like a public ip. Just "sometimes for debugging purposes" How would the template know that you are debugging? You have to tell it with a parameter.

check out the docs https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html

So you could have a public ip parameter and a subnet id parameter and pass in what you like at stack creation.

One way that conditions could be useful is to create a debug parameter that would toggle public/private ip and subnet. Is this what you were thinking of?

To use conditions on properties use the IF function

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html

I suggest setting your public subnet to provide a public ip on launch, and of course ensuring your private subnet does not do that. Then just pass the subnet in as a parameter.

https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html#subnet-public-ip

0

Greg's answer (accepted one) didn't work for me. I needed this:

  NetworkInterfaces:
    - !If
      - YourCondition
      - AssociatePublicIpAddress: "true"
        DeviceIndex: "0"  
        ...
      - !Ref "AWS::NoValue"

Traps on the way:

  • Without the hyphen before the !If, I was unable to deploy.
  • Watch out for the proper indentation.
  • You might find other answer using - - instead of -. That is probably wrong.
    Details: - - will create an Array. - will create a dictionary (key: value). The latter is probably what you need

Not the answer you're looking for? Browse other questions tagged or ask your own question.