Assigning a public ip to an ec2 in cloudformation

amazon ec2amazon-cloudformationamazon-web-services

In the vpc I am using on aws ec2's do not get a public ip address by default. I am trying to add one manually after referencing this and this bit of documentation.

Currently my cloudformation template includes

"netinterface"    : {
  "Type" : "AWS::EC2::NetworkInterface",
  "Properties" : {
    "SubnetId" : {"Ref": "Subnet"}
   }


},


"billingattributionapi" : {
  "Type"        : "AWS::EC2::Instance",
  "Properties"  : {

    "NetworkInterfaces" : [
      {
        "AssociatePublicIpAddress"  : "true",
        "DeviceIndex"               : "eth0",
        "NetworkInterfaceId"        : {"Ref" : "netinterface"},
        "DeleteOnTermination"       : "true"
      }

    ]
  }
}

There is a lot omitted, but this is everything relevant to adding an ip.

My problem is that the documentation says that only network interfaces with a DeviceIndex of eth0 can have a public ip address, but using eth0 results in an error saying

    Encountered non numeric value for property DeviceIndex

But if I set the device id to 0 I will get

The associatePublicIPAddress parameter cannot be specified for a network interface with an ID

But if I remove the NetworkInterfaceId and add a subnet id as required by the documentation I get

Network interfaces and an instance-level subnet ID may not be specified on the same request

At this point I have no idea what I should do. According to the documentation my original approach seems correct. Has anyone done this before and can point out what I'm doing wrong?

Best Answer

This is what works for me:

Set a private IP as primary IP address in "AWS::EC2::Instance" resource:

  "NetworkInterfaces" : [
                {
                    "DeleteOnTermination" : true,
                    "Description"         : "Main interface",
                    "DeviceIndex"         : "0",
                    "PrivateIpAddresses"  : [
                        {
                            "PrivateIpAddress" : {
                                "Ref" : "InternalIPAddress"
                            },
                            "Primary"          : true
                        }
                    ],
                    "GroupSet"            : [
                        {
                            "Ref" : "SecurityGroupId"
                        }
                    ],
                    "SubnetId"            : {
                        "Ref" : "VPCSubnet"
                    }
                }
            ],

Note that the reference to "InternalIPAddress" above is a parameter to pass what internal IP the machine should have. I don't think it's necessary, as without it, the instance will pick up an IP through dhcp.

Then later in the template, add a resource of type "AWS::EC2::EIP":

 "EIPExternalIP"                 : {
        "Type" : "AWS::EC2::EIP",
        "Properties" : {
            "InstanceId" : {
                "Ref" : "Instance"
            },
            "Domain"     : "vpc"
        }
    },

You can get the External IP with {"Ref" : "EIPExternalIP"}