Getting "Template validation error: Invalid template resource property 'VPCID' " - amazon-web-services

I am trying to create a VPC using AWS CloudFormation.
I built a VPC on its own, then I updated the existing stack by adding more components to the JSON template (components like subnets, internet gateways, NATs, route tables, etc.) - one component at a time.
My VPC created successfully but when I tried to update the stack with an internet gateway and attach to the VPC, I started getting the error Template validation error: Invalid template resource property 'VPCID'.
My JSON template is as follows:
{
"Parameters": {
"CIDRRange": {
"Description": "VPCCIDR Range (will be a /16 block)",
"Type": "String",
"Default": "10.251.0.0",
"AllowedValues": ["10.250.0.0","10.251.0.0"]
}
},
"Resources": {
"VPCBase": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": { "Fn::Join" : ["", [{ "Ref" : "CIDRRange" }, "/16"]] },
"EnableDnsSupport": "True",
"EnableDnsHostnames": "True",
"Tags": [{ "Key": "Name", "Value": { "Fn::Join" : ["", [{ "Ref" : "AWS::StackName" }, "-VPC"]] } }]
}
},
"IGWBase" : {
"Type" : "AWS::EC2::InternetGateway",
"Properties" : {
"Tags" : [{ "Key": "Name", "Value": { "Fn::Join" : ["", [{ "Ref" : "AWS::StackName" }, "-IGW"]] } }]
}
},
"VGAIGWBase" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"InternetGatewayId" : { "Ref" : "IGWBase" },
"VpcId" : { "Ref" : "VPCBase" }}
},
"Outputs": {
"VPCID" : { "Value" : { "Ref" : "VPCBase" } },
"DefaultSG" : { "Value" : { "Fn::GetAtt" : ["VPCBase", "DefaultSecurityGroup"] }}
}
}
}

Your formatting is a bit of a mess - I'd recommend going with yaml over json - but the problem is you're not closing the Resources: section.
You can validate a template with the cli with
aws cloudformation validate-template --template-body file://path.json
"VGAIGWBase" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"InternetGatewayId" : { "Ref" : "IGWBase" },
"VpcId" : { "Ref" : "VPCBase" }
}
}
}, << ADD THIS
"Outputs": {
"VPCID" : { "Value" : { "Ref" : "VPCBase" } },
"DefaultSG" : { "Value" : { "Fn::GetAtt" : ["VPCBase", "DefaultSecurityGroup"] }}
}
}

Related

Is there a way to configure the 'Stack Name' of nested stacks in AWS cloudformation ?

I am trying to create a nested stack using AWS CloudFormation.
I need to specify the 'Stack Name' of the nested stack.
I tried using the 'Tags' property with Key: 'Stack Name'. But that didn't help.
Is there any way to provide the Stack Name as an input while creating nested stack?
In a given template, you have access to the pseudo-parameters stackId and stackName. Those can be marked for export, then referenced in another stack. Joined, they give you the child stack's name.
I found the following video quite useful despite its age: https://youtu.be/6R44BADNJA8
This sample template may also be helpful in understanding how these work: https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleNetworkCrossStack.template
{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "AWS CloudFormation Sample Template VPC_with_PublicIPs_And_DNS: Sample template that creates a VPC with DNS and public IPs enabled. Note that you are billed for the AWS resources that you use when you create a stack from this template.", "Resources" : { "VPC" : { "Type" : "AWS::EC2::VPC", "Properties" : { "EnableDnsSupport" : "true", "EnableDnsHostnames" : "true", "CidrBlock" : "10.0.0.0/16" } }, "PublicSubnet" : { "Type" : "AWS::EC2::Subnet", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "CidrBlock" : "10.0.0.0/24" } }, "InternetGateway" : { "Type" : "AWS::EC2::InternetGateway" }, "VPCGatewayAttachment" : { "Type" : "AWS::EC2::VPCGatewayAttachment", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "InternetGatewayId" : { "Ref" : "InternetGateway" } } }, "PublicRouteTable" : { "Type" : "AWS::EC2::RouteTable", "Properties" : { "VpcId" : { "Ref" : "VPC" } } }, "PublicRoute" : { "Type" : "AWS::EC2::Route", "DependsOn" : "VPCGatewayAttachment", "Properties" : { "RouteTableId" : { "Ref" : "PublicRouteTable" }, "DestinationCidrBlock" : "0.0.0.0/0", "GatewayId" : { "Ref" : "InternetGateway" } } }, "PublicSubnetRouteTableAssociation" : { "Type" : "AWS::EC2::SubnetRouteTableAssociation", "Properties" : { "SubnetId" : { "Ref" : "PublicSubnet" }, "RouteTableId" : { "Ref" : "PublicRouteTable" } } }, "PublicSubnetNetworkAclAssociation" : { "Type" : "AWS::EC2::SubnetNetworkAclAssociation", "Properties" : { "SubnetId" : { "Ref" : "PublicSubnet" }, "NetworkAclId" : { "Fn::GetAtt" : ["VPC", "DefaultNetworkAcl"] } } }, "WebServerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP ingress", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ] } } }, "Outputs" : { "VPCId" : { "Description" : "VPC ID", "Value" : { "Ref" : "VPC" }, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-VPCID" }} }, "PublicSubnet" : { "Description" : "The subnet ID to use for public web servers", "Value" : { "Ref" : "PublicSubnet" }, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SubnetID" }} }, "WebServerSecurityGroup" : { "Description" : "The security group ID to use for public web servers", "Value" : { "Fn::GetAtt" : ["WebServerSecurityGroup", "GroupId"] }, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SecurityGroupID" }} } } }
As commented below, the answer is no for now.
Original:Yes, it's the resource name that gets taken as the stack name. Below you'd get a stack called myStackName
YAML
AWSTemplateFormatVersion: "2010-09-09"
Resources:
myStackName:
Type: "AWS::CloudFormation::Stack"
Properties:
TemplateURL: "https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2ChooseAMI.template"
Parameters:
InstanceType: "t1.micro"
KeyName: "mykey"
JSON
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Resources" : {
"myStackName" : {
"Type" : "AWS::CloudFormation::Stack",
"Properties" : {
"TemplateURL" : "https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2ChooseAMI.template",
"Parameters" : {
"InstanceType" : "t1.micro",
"KeyName" : "mykey"
}
}
}
}
}

cloudformation failing with security group mismatch

I'm trying to setup my cloudformation for my database:
"VPC" : {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : "10.0.0.0/16",
"EnableDnsSupport" : "false",
"EnableDnsHostnames" : "false",
"InstanceTenancy" : "default",
"Tags" : [ { "Key" : "Name", "Value" : "DomainName" } ]
}
},
"Subnet" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"CidrBlock" : "10.0.0.0/16",
"AvailabilityZone" : { "Fn::Select": [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }]},
"Tags" : [ { "Key" : "Name", "Value" : "DomainName" } ]
}
},
"SecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Allow http to client host",
"VpcId" : {"Ref" : "VPC"},
"SecurityGroupIngress" : [{
"IpProtocol" : "tcp",
"FromPort" : "3306",
"ToPort" : "3306",
"CidrIp" : "10.0.0.0/16"
}],
"Tags" : [ { "Key" : "Name", "Value" : "DomainName" } ]
}
},
"Database" : {
"Type" : "AWS::RDS::DBInstance",
"Properties" : {
"DBName" : { "Fn::Join": ["", { "Fn::Split": [".", { "Ref" : "DomainName" }]}]},
"AllocatedStorage" : "5",
"DBInstanceClass" : "db.t2.micro",
"Engine" : "MySQL",
"EngineVersion" : "5.5",
"MasterUsername" : { "Ref": "DBUsername" },
"MasterUserPassword" : { "Ref": "DBPassword" },
"VPCSecurityGroups" : [ { "Fn::GetAtt": [ "SecurityGroup", "GroupId" ] } ],
"Tags" : [ { "Key" : "Name", "Value" : "DomainName" } ]
},
"DeletionPolicy" : "Snapshot"
},
Should be setting up a VPC for the database. But when I run the cloudformation template I get the following error:
UPDATE_FAILED AWS::RDS::DBInstance Database Database is in vpc-3081245b, but Ec2 Security Group sg-b122ffca is in vpc-f7173290
How do I get my database in the VPC properly?
As part of your Database definition, you can specify a DBSubnetGroupName.
A DB Subnet Group provides a list of subnets in which the Database is allowed to run. Each subnet in a DB Subnet Group belongs to a VPC.
Therefore, you need to do the following to your Amazon CloudFormation template:
Add a AWS::RDS::DBSubnetGroup, specifying the Subnet already defined in your template
Add a DBSubnetGroupName parameter to your AWS::RDS::DBInstance definition

How to add a RDS instance to a VPC using aws cloudformation

When I launch a RDS instance manually I'm able to assign what VPC I want it to be part of. I'm trying to create a stack using AWS cloudformation, however I do not see an API to be able to do that. I can create my VPC in the stack and then reference it for security groups both EC2 and DB security groups and they both end up been part of the VPC however the RDS instance itself does not. Is there a way to assign the VPC to the RDS instance?
Below is my template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Metadata": {
"AWS::CloudFormation::Designer": {
"30e03bfc-b61a-4d6c-89db-1b62b258a305": {
"size": {
"width": 80,
"height": 80
},
"position": {
"x": 700,
"y": 170
},
"z": 0,
"embeds": []
}
}
},
"Parameters": {
"DBPreferredBkupWindow": {
"Description" : "The daily time range (in UTC) during which automated backups are created, ideally off peak-hours.",
"Type" : "String",
"MinLength" : "1",
"MaxLength" : "11",
"AllowedPattern" : "\\d[0-23]:\\d[0-59]-\\d[0-23]:\\d[0-59]",
"Default" : "01:00-02:00"
}
},
"Resources": {
"VPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock" : "172.16.0.0/16",
"EnableDnsSupport" : true
}
},
"DB": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"DBName" : "ems",
"Engine" : "postgres",
"EngineVersion" : "9.4.7",
"DBInstanceClass" : "db.t1.micro",
"DBInstanceIdentifier" : "rltdb",
"MasterUsername" : "pgadmin",
"MasterUserPassword" : "pgadmin1",
"AllocatedStorage" : "100",
"Iops" : "1000",
"BackupRetentionPeriod" : "7",
"PreferredBackupWindow" : { "Ref" : "DBPreferredBkupWindow" },
"MultiAZ" : true,
"PubliclyAccessible" : false,
"AutoMinorVersionUpgrade" : false,
"VPCSecurityGroups" : [{ "Ref" : "SecurityGroup" } ]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "30e03bfc-b61a-4d6c-89db-1b62b258a305"
}
}
},
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"EC2VpcId" : { "Ref" : "VPC" },
"DBSecurityGroupIngress" : { "EC2SecurityGroupName": { "Ref": "SecurityGroup"} },
"GroupDescription" : "Database Access"
}
},
"SecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"GroupDescription" : "Enable database access for application",
"SecurityGroupIngress" : [
{"IpProtocol" : "tcp", "FromPort" : "5432", "ToPort" : "5432", "CidrIp" : "0.0.0.0/0"}
]
}
}
}
}
You have to create a DBSubnetGroup and at least two subnets in your CloudFormation template.
"subnet-1" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"CidrBlock" : "172.16.1.0/24",
"VpcId" : { "Ref" : "VPC" }
}
},
"subnet-2" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"CidrBlock" : "172.16.2.0/24",
"VpcId" : { "Ref" : "VPC" }
}
},
"DBSubnetGroup" : {
"Type" : "AWS::RDS::DBSubnetGroup",
"Properties" : {
"SubnetIds" : [
{ "Ref" : "subnet-1" },
{ "Ref" : "subnet-2" }
],
}
},
and in last you have to include DBSubnetGroup in your "DB" Object.
"DBSubnetGroupName": { "Ref": "DBSubnetGroup" }
You need to include the DBSubnetGroupName:
A DB subnet group to associate with the DB instance.
If there is no DB subnet group, then it is a non-VPC DB instance.
Create a DBSubnetGroup resource using subnets in your VPC, then tie that to your DBInstance:
"DBSubnetGroupName": { "Ref": "MySubnetGroup" }

How get "cidrblock" of a subnet in the "outputs" of a AWS Cloudformation?

I am writing a AWS Code formation. I have to print the Cidrblock of a subnet. But that does not work. Please help
"Resources": {
"Subnet": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": "10.0.0.0/16",
}
},
Outputs : {
"SubnetCIDR": {
"Value": {
"Fn::GetAtt": [
"Subnet",
"CidrBlock"
]
},
"Description": "The CIDR"
},
}
This does not work. The following error message is shown while uploading the template:
Template validation error: Template error: resource Subnet does not
support attribute type CidrBlock in Fn::GetAtt
Not supported.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html
If you look at the doc, the only supported attribute is AvailabilityZone
Since you seem to be hard coding the CIDR block anyway, you could set it as a parameter and then just reference the parameter in both places.
"Parameters" : {
"CidrBlock" : {
"Type" : "String",
"Default" : "10.0.0.0/16"
}
},
"Resources" : {
"Subnet" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : {
"Ref" : "VPC"
},
"CidrBlock" : { "Ref" : "CidrBlock" }
}
}
},
"Outputs" : {
"SubnetCIDR" : {
"Value" : { "Ref" : "CidrBlock" },
"Description": "The CIDR"
}
}

Reusing AWS::CloudFormation::Init (and userdata?) for multiple instances

Is it possible to reuse the same bootstrapping config from AWS::CloudFormation::Init (and/or userdata) for multiple EC2::Instances in a template?
I need to set the content of 3 files and then run 3 commands to bootstrap all servers, but the Metadata block is about 30 lines long (and is likely to grow).
Each server instance has a different set of Tags, some have more tags than others.
Ideally, I think that you should be able to declare the AWS::CloudFormation::Init as a resource, and refer to it from multiple EC2::Instances, but I don't think that this is possible.
I initially thought (as a newbie) that AWS::CloudFormation::CustomResource might be appropriate, but I don't think that it is.
I'm currently thinking of using a AWS::CloudFormation::Stack to import a shared instance template, but I would need to somehow pass the Tags parameter for each resource in the stack template into the instance template. The question is - if this is the best approach, what do I enter in the 3 locations that currently have ?????
(Bonus credit - what's the difference between userdata and this init block?)
stack.template
...
"Resources" : {
"Server1" : {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"Parameters": {
"InstanceType": "m1.medium",
...
"Tags": { ???? }
},
"TemplateURL": "https://s3.amazonaws.com/mybucket/instance.template"
}
instance.template
...
"Parameters" : {
"InstanceType" : {...}
"KeyName": {...}
...
"Tags": {
????
}
},
"Resources" : {
"Instance" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"files" : {
"/etc/apt/apt.conf.d/99auth" : {
"content" : "APT::Get::AllowUnauthenticated yes;"
},
"/etc/apt/sources.list.d/my-repo.list" : {
"content" : "deb http://my-repo/repo apt/"
},
},
"commands" : {
"01-apt-get update" : {
"command" : "apt-get update"
},
"02-apt-get install puppet" : {
"command" : "apt-get install puppet my-puppet-config"
},
"03-puppet apply" : {
"command" : "puppet apply"
}
}
}
}
},
"Properties" : {
"InstanceType" : {"Ref" : "InstanceType"},
"ImageId" : "ami-84a333be",
"KeyName" : {"Ref" : "KeyName"},
"SubnetId" : {"Ref" : "SubnetId"},
"SecurityGroupIds" : [ { "Ref" : "SecurityGroupId"] } ],
"Tags" : [
????
]
}
}
}
Is it possible to reuse the same bootstrapping config from
AWS::CloudFormation::Init (and/or userdata) for multiple
EC2::Instances in a template?
No, this is not possible with the AWS::EC2::Instance resource in a single template. However, there is a resource type AWS::AutoScaling::LaunchConfiguration, but today this resource is only applicable to Auto Scaling groups. Ideally, AWS would provide a similar resource type that can be applied to multiple AWS::EC2::Instance resources. That being said, there is a lot of value in using Auto Scaling groups.
Here is a simple example that would allow you to do this with a single Launch Configuration and multiple Auto Scaling group resources in a single template. Auto scaling is typically configured with more than one instance, but I am using a MinSize and MaxSize of 1 to mirror the configuration you were going after with the AWS::EC2::Instance resource type. Even though we are using a single instance with an Auto Scaling group, we still gain the benefits of Auto Scaling with single instance resiliency. If the instance becomes unhealthy, Auto Scaling will automatically replace the instance.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources" : {
"LaunchConfig" : {
"Type" : "AWS::AutoScaling::LaunchConfiguration",
"Properties" : {
"InstanceType" : { "Ref" : "InstanceType" },
"ImageId" : "ami-84a333be",
"KeyName" : { "Ref" : "KeyName" },
"SecurityGroupIds" : [{"Ref" : "SecurityGroupId"}],
"UserData" : { "Fn::Base64" : { "Fn::Join" : [ "", [
"#!/bin/bash -v\n",
"# Run cfn-init\n",
"/opt/aws/bin/cfn-init -v ",
" -stack ", { "Ref": "AWS::StackName" },
" -resource LaunchConfig ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"# Signal success\n",
"/opt/aws/bin/cfn-signal -e $? '", { "Ref" : "WaitConditionHandle" }, "'\n"
]]}}
},
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"files" : {
"/etc/apt/apt.conf.d/99auth" : {
"content" : "APT::Get::AllowUnauthenticated yes;"
},
"/etc/apt/sources.list.d/my-repo.list" : {
"content" : "deb http://my-repo/repo apt/"
}
},
"commands" : {
"01-apt-get update" : {
"command" : "apt-get update"
},
"02-apt-get install puppet" : {
"command" : "apt-get install puppet my-puppet-config"
},
"03-puppet apply" : {
"command" : "puppet apply"
}
}
}
}
}
},
"ASG1" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : [ { "Ref" : "AZ" } ],
"VPCZoneIdentifier" : [ { "Ref" : "SubnetId" } ],
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MaxSize" : "1",
"MinSize" : "1",
"Tags" : [
{ "Key" : "Name", "Value": "Server1", "PropagateAtLaunch" : "true" },
{ "Key" : "Version", "Value": "1.0", "PropagateAtLaunch" : "true" }
]
}
},
"ASG2" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : [ { "Ref" : "AZ" } ],
"VPCZoneIdentifier" : [ { "Ref" : "SubnetId" } ],
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MaxSize" : "1",
"MinSize" : "1",
"Tags" : [
{ "Key" : "Name", "Value": "Server2", "PropagateAtLaunch" : "true" },
{ "Key" : "Version", "Value": "1.0", "PropagateAtLaunch" : "true" }
]
}
},
"WaitConditionHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"WaitCondition" : {
"Type" : "AWS::CloudFormation::WaitCondition",
"Properties" : {
"Handle" : { "Ref" : "WaitConditionHandle" },
"Timeout" : "300"
}
}
}
}
This is an incomplete example and there is much more you can do with Auto Scaling, but I just wanted to give you a simple example sharing a Launch Configuration with multiple instances. Each Auto Scaling group does define its own set of tags.
I'm currently thinking of using a AWS::CloudFormation::Stack to import
a shared instance template, but I would need to somehow pass the Tags
parameter for each resource in the stack template into the instance
template. The question is - if this is the best approach, what do I
enter in the 3 locations that currently have ?????
I would recommend the solution I described above, but I would also like to answer your questions on how use tags with the nested stack approach.
stack.template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources" : {
"Server1" : {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/mybucket/instance.template",
"Parameters": {
"InstanceType": "m1.medium",
"TagName": "Server1"
"TagVersion": "1.0"
}
}
},
"Server2" : {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/mybucket/instance.template",
"Parameters": {
"InstanceType": "m1.medium",
"TagName": "Server2"
"TagVersion": "1.0"
}
}
}
}
}
instance.template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters" : {
"InstanceType" : {...},
"KeyName": {...}
"TagName": {
"Description" : "The name tag to be applied to each instance",
"Type" : "String"
},
"TagVersion": {
"Description" : "The version tag to be applied to each instance",
"Type" : "String"
}
},
"Resources" : {
"Instance" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"AWS::CloudFormation::Init" : {
...
}
},
"Properties" : {
"InstanceType" : { "Ref" : "InstanceType" },
"ImageId" : "ami-84a333be",
"KeyName" : { "Ref" : "KeyName" },
"SubnetId" : { "Ref" : "SubnetId" },
"SecurityGroupIds" : [ { "Ref" : "SecurityGroupId"] } ],
"Tags" : [
{ "Key" : "Name", "Value": { "Ref" : "TagName" } },
{ "Key" : "Version", "Value": { "Ref" : "TagVersion" } },
]
}
}
}
}
There is not a standard for passing an entire array of tags as a parameter, so you can see I simply broke each tag out into its own parameter and passed these on to the nested stacks.
(Bonus credit - what's the difference between userdata and this init
block?)
UserData allows you to pass arbitrary data to the instance at first boot. Often this is a shell script that can automate tasks when the instance starts. For example, you could simply run a yum update.
"UserData" : { "Fn::Base64" : { "Fn::Join" : [ "", [
"#!/bin/bash\n"
"yum update -y", "\n"
]]}}
UserData becomes even more useful when combined with the AWS::CloudFormation::Init metadata which allows you to structure your bootstrapping configuration. In this case, UserData is simply used to invoke the cfn-init script that executes the AWS::CloudFormation::Init metadata. I've included this pattern in my first example above using a Launch Configuration. It is important to note that the UserData section is executed only once during the first boot of the instance. This is important to keep in mind when thinking about how you want to handle updates to your instances.