Resizing root volume size of ec2 instance with cloudformation - amazon-web-services

I have an instance created with cloudformation like below:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ServerAMI
InstanceType: !Ref ServerInstanceType
KeyName: !Ref KeyName
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 30
NetworkInterfaces:
- AssociatePublicIpAddress: 'false'
DeleteOnTermination: 'true'
DeviceIndex: '0'
GroupSet:
- Ref: ServerSecurityGroup
SubnetId: !Ref SubnetID
Tags:
- { Key: Name, Value: !Ref AWS::StackName }
My root volume in this case is created at 30GB. If I try increase this root volume size by setting the VolumeSize value then my ec2 instance is terminated and recreated.
Yet in the console I am able to increase the size of my root volume without recreation of my instance.
Is there any work around for this in order to prevent ec2 instance from being terminated when trying to increase root volume size via cloudformation?
Edit:
Here is a small test stack I'm using to test this again. Deployed once, then change VolumeSize and redeploy - it wants to replace the instance:
AWSTemplateFormatVersion: '2010-09-09'
Description: Test stack for a single ec2 instance
Parameters:
ServerAMI:
Type: String
Default: ami-096f43ef67d75e998
ServerInstanceType:
Type: String
Default: t2.small
DefaultVPCID:
Type: String
SubnetID:
Type: String
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ServerAMI
InstanceType: !Ref ServerInstanceType
KeyName: !Ref KeyName
BlockDeviceMappings:
- DeviceName: /dev/xvda #Linux
Ebs:
VolumeSize: 30
NetworkInterfaces:
- AssociatePublicIpAddress: 'false'
DeleteOnTermination: 'true'
DeviceIndex: '0'
GroupSet:
- Ref: ServerSecurityGroup
SubnetId: !Ref SubnetID
Tags:
- { Key: Name, Value: !Ref AWS::StackName }
ServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Webserver security group
VpcId: !Ref DefaultVPCID
SecurityGroupIngress:
- { IpProtocol: tcp, FromPort: '22', ToPort: '22', CidrIp: '127.0.0.1/32', Description: 'Test Instance' }

Unfortunately, I don't believe you can - per the CloudFormation documentation:
After the instance is running, you can modify only the DeleteOnTermination parameter for the attached volumes without interrupting the instance. Modifying any other parameter results in instance replacement.

Related

Windows spot instance with persistence request using cloudformation

When I try to launch windows server using this template, I get an error:
Property validation failure: [Value of property {/LaunchTemplateData} does not match type {Object}]
I used this template:
Parameters:
1InstanceType:
Type: String
Default: t2.small
AllowedValues:
- t2.small
- m3.medium
- m3.xlarge
- i3.xlarge
2SecurityGroup:
Type: 'AWS::EC2::SecurityGroup::Id'
3KeyName:
Type: 'AWS::EC2::KeyPair::KeyName'
4LatestAmiId:
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base
Resources:
Ec2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: WindowsDesktop
LaunchTemplateData:
- ImageId: !Ref 4LatestAmiId
InstanceType: !Ref 1InstanceType
SecurityGroups:
- GroupId: !Ref 2SecurityGroup
KeyName: !Ref 3KeyName
InstanceMarketOptions:
MarketType: spot
SpotOptions:
SpotInstanceType: persistent
InstanceInterruptionBehavior: stop
Similar code works for linux servers. It seems that Windows spot instance (or template) with persistence request can not be created using cloudformation.
The error means that your LaunchTemplateData is not an object, but it is a list in your case. This is because extra - before ImageId. So it should be:
Resources:
Ec2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: WindowsDesktop
LaunchTemplateData:
ImageId: !Ref 4LatestAmiId
InstanceType: !Ref 1InstanceType
SecurityGroups:
- GroupId: !Ref 2SecurityGroup
KeyName: !Ref 3KeyName
InstanceMarketOptions:
MarketType: spot
SpotOptions:
SpotInstanceType: persistent
InstanceInterruptionBehavior: stop

How can I change LaunchConfig settings with Cloudformation?

I have an AutoScale and a LaunchConfig that I created earlier. I want to replace AMI ID with Cloudformation in LaunchConfig. How can I do that ?
I wonder if there is any sample template that will be a reference for me?
Simple example you can find : https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#aws-properties-as-launchconfig--examples
---
AWSTemplateFormatVersion: 2010-09-09
Parameters:
LatestAmiId:
Description: Region specific image from the Parameter Store
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
InstanceType:
Description: Amazon EC2 instance type for the instances
Type: String
AllowedValues:
- t3.micro
- t3.small
- t3.medium
Default: t3.micro
Resources:
myLaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !Ref LatestAmiId
SecurityGroups:
- Ref: "myEC2SecurityGroup"
InstanceType:
Ref: "InstanceType"
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
VolumeSize: 30
VolumeType: "gp3"
- DeviceName: /dev/sdm
Ebs:
VolumeSize: 100
DeleteOnTermination: "false"

Create Cloudwatch Event for EBS Snapshot using Cloudformation

I am trying to create cloudwatch scheduled event for taking snapshot of my ebs. I am new to cloudformation not much familiar with it that's why having complexity in achieving this. I am attaching my current template which spawns my ec2 instance and override the default volume from 10gb to 20gb. I want to create a cloudwatch event on exactly the same created volume to take the snapshot of this volume that has been created from this template. I would be glad if anyone can help me in setting an event with target using the cloudformation syntax.
Parameters:
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instance
Type: 'AWS::EC2::KeyPair::KeyName'
Resources:
Ec2Instance:
Type: 'AWS::EC2::Instance'
DependsOn:
- InstanceSecurityGroup
- CWIAMRole
- EC2CWInstanceProfile
Properties:
KeyName: !Ref KeyName
ImageId: ami-057a963e8be173b19
InstanceType: t3a.micro
IamInstanceProfile: !Ref EC2CWInstanceProfile
NetworkInterfaces:
- AssociatePublicIpAddress: 'True'
DeleteOnTermination: 'True'
DeviceIndex: '0'
# Add subnet id below
SubnetId: subnet-031c6fb8172d780aa
GroupSet:
- !Ref InstanceSecurityGroup
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
DeleteOnTermination: 'true'
VolumeSize: '20'
LambdaSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Enable SSH access via port 22
# Add you vpc id below
VpcId: vpc-02e91d5d082e3a097
GroupName: DS Lambda Security Group
InstanceSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
DependsOn:
- LambdaSecurityGroup
Properties:
GroupDescription: Enable SSH access via port 22
# Add you vpc id below
VpcId: vpc-02e91d5d082e3a097
GroupName: DS DB Instance Security Group
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
# Add vpn ip below for e.g 192.168.78.2/32
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: '5432'
ToPort: '5432'
SourceSecurityGroupId: !Ref LambdaSecurityGroup
CWIAMRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/CloudWatchAgentAdminPolicy'
RoleName: DS_CW_AGENT_ROLE
EC2CWInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
InstanceProfileName: EC2CWInstanceProfile
Roles:
- !Ref CWIAMRole
S3VPCEndpoint:
Type: 'AWS::EC2::VPCEndpoint'
Properties:
RouteTableIds:
- 'rtb-031f3057458433643'
ServiceName: com.amazonaws.ap-southeast-1.s3
VpcId: vpc-02e91d5d082e3a097
Sadly, you can't do this easily. The reason is that the Instance resource does not return the id of its root volume.
What's more, you can't create an independent AWS::EC2::Volume resource and use it as a root volume in your instance. This is only for additional volumes.
The only way to get the volume id of your root device would be through development of a custom resource. This would be in the form of lambda function, which would take the instance id, and use AWS SDK to find the volume id and return to cloud formation. With that volume id you could create CloudWatch Event rules.

Assign private IP only with CloudFormation

I'm using CloudFormation to create an EC2 instance. What I am trying to achieve is only assign a private IP. No public IP. Everything gets created fine and it creates a DNS entry for the private IP, but it also creates a public IP. How can I tell it to not create a public IP. Here is my template. The vpc_id and subnet_id is on a private network.
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS CloudFormation template for creating riskInternalElk instance with DNS record'
Parameters:
Resources:
InstanceSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupName: "{{security_group_name}}"
GroupDescription: "{{security_group_name}}"
VpcId: "{{vpc_id}}"
SecurityGroupIngress:
{% for item in security_group_ingress %}
- IpProtocol: "{{item.protocol}}"
FromPort: "{{item.from_port}}"
ToPort: "{{item.to_port}}"
CidrIp: "{{item.cidr_ip}}"
{% endfor %}
NetworkInterface:
Type: AWS::EC2::NetworkInterface
Properties:
SubnetId: "{{subnet_id}}"
Description: "{{subnet_description}}"
GroupSet:
- !Ref InstanceSecurityGroup
SourceDestCheck: true
Tags:
- Key: Network
Value: Web
EC2Instance:
Type: AWS::EC2::Instance
Properties:
Tags:
- Key: "Name"
Value: "{{instance_name}}"
ImageId: "{{image_id}}"
InstanceType: "{{instance_type}}"
KeyName: "{{key_name}}"
NetworkInterfaces:
- NetworkInterfaceId: !Ref NetworkInterface
DeviceIndex: 1
BlockDeviceMappings:
- DeviceName: "{{device_name}}"
Ebs:
VolumeType: "gp2"
VolumeSize: "{{volume_size}}"
Encrypted: true
DeleteOnTermination: false
DnsRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: "{{hosted_zone_name}}"
Comment: "DNS name for risk internal ec2 instance."
Name: "{{host_name}}"
Type: A
TTL: '60'
ResourceRecords:
- !GetAtt EC2Instance.PrivateIp
You can specify the information in the EC2:Instance resource set for the NetworkInterfaces differently to have it deviate from the subnets setting for assigning a public IP.
Specifically set the AssociatePublicIpAddress to "False" and move your NetworkInterface resource to be in-line like this:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
Tags:
- Key: "Name"
Value: "{{instance_name}}"
ImageId: "{{image_id}}"
InstanceType: "{{instance_type}}"
KeyName: "{{key_name}}"
NetworkInterfaces:
- AssociatePublicIpAddress: false <--- This should do it
DeleteOnTermination: false
DeviceIndex: 0
SubnetId: "{{subnet_id}}"
Description: "{{subnet_description}}"
GroupSet:
- !Ref InstanceSecurityGroup
SourceDestCheck: true
BlockDeviceMappings:
- DeviceName: "{{device_name}}"
Ebs:
VolumeType: "gp2"
VolumeSize: "{{volume_size}}"
Encrypted: true
DeleteOnTermination: false
You control the assignment of public IP addresses to EC2 instances thru the subnet configuration. The subnet defines MapPublicIpOnLaunch. This also means that the subnet must be part of your cloudformation stack.
If you are using Auto Scaling, then you have the option AssociatePublicIpAddress in AWS::AutoScaling::LaunchConfiguration
AWS::EC2::Subnet
AWS::AutoScaling::LaunchConfiguration
Check the Subnet for the setting, "Auto-assign public IPv4 address".
Change it by going to the VPC Console and selecting the Subnet-->Actions-->"Modify auto-assign IP settings".

CloudFormation: simple example

I would like to build EC2 behind ELB(Elastic Load Balancer).
What would be the yaml/json code of doing this?
If you are looking for sample templates in json/yaml with Cloud Formation designer, you can use this sample templates provided by AWS.
Below is a sample CF template for simple 1 EC2/1 ELB stack
AWSTemplateFormatVersion: '2010-09-09'
Description: '1 EC2 Instance and 1 ELB'
Parameters:
AppServer:
Description: Hostname of Server
Type: String
Default: ec2instance01
MinLength: '1'
MaxLength: '16'
AllowedPattern: '[0-9a-zA-Z-]*'
ConstraintDescription: 'Must contain valid DNS characters, AD length limit.'
AMI:
Description: AMI to deploy AWSLinux Instances
Type: String
Default: ami-xxxxxxxx
InstanceType:
Description: Application EC2 instance type
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t2.2xlarge
- m4.2xlarge
ConstraintDescription: Must be a valid EC2 instance type.
VPCID:
Description: Name of the VPC
Type: 'AWS::EC2::VPC::Id'
Default: vpc-xxxxxxxx
ConstraintDescription: Must be a valid VPC.
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Type: 'AWS::EC2::KeyPair::KeyName'
Default: XXXX-key
MinLength: '1'
MaxLength: '255'
AllowedPattern: '[\x20-\x7E]*'
ConstraintDescription: Must contain only ASCII characters.
SubnetIdPrivateEastC:
Description: Private subnet for confidential apps in us-east-1c
Type: 'AWS::EC2::Subnet::Id'
Default: subnet-xxxxxxxx
MinLength: '1'
MaxLength: '255'
ConstraintDescription: Must be a valid Private Subnet.
SubnetIdPrivateEastD:
Description: Private subnet for confidential apps in us-east-1d
Type: 'AWS::EC2::Subnet::Id'
Default: subnet-xxxxxxxx
MinLength: '1'
MaxLength: '255'
ConstraintDescription: Must be a valid Private Subnet.
InstanceProfile:
Description: Instance Profile Name
Type: String
Default: xxxx-role
MinLength: '0'
MaxLength: '255'
AllowedPattern: '[\x20-\x7E]*'
ConstraintDescription: Must contain a vailed instance profile name
RootVolumeSize:
Description: Size (GB) of root EBS volume for application instance
Type: Number
Default: '10'
MinValue: '10'
MaxValue: '1024'
SwapDisk:
Description: Size (GB) of application EBS volume for instance
Type: Number
Default: '2'
MinValue: '2'
MaxValue: '128'
SubnetAvailabilityZone:
Description: Availability Zone for subnet
Type: String
Default: us-east-1d
AllowedValues:
- us-east-1c
- us-east-1d
ConstraintDescription: Must be a valid Availability zone.
PrivateSubnets:
Type: List<AWS::EC2::Subnet::Id>
Description: 'Private subnet for the ELB in us-east-1c and us-east-1d'
Default: "subnet-xxxxxxxx,subnet-xxxxxxxx"
Resources:
ec2instance01:
Type: 'AWS::EC2::Instance'
Properties:
DisableApiTermination: 'true'
AvailabilityZone: us-east-1d
ImageId:
Ref: AMI
InstanceType:
Ref: InstanceType
KeyName:
Ref: KeyName
SecurityGroupIds:
- Ref: WebSG
IamInstanceProfile:
Ref: InstanceProfile
SubnetId:
Ref: SubnetIdPrivateEastD
#EbsOptimized: true
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize:
Ref: RootVolumeSize
VolumeType: gp2
- DeviceName: /dev/sds
Ebs:
VolumeSize:
Ref: SwapDisk
VolumeType: gp2
Tags:
- Key: Name
Value:
Ref: AppServer
UserData:
'Fn::Base64': !Sub |-
#!/bin/bash -v
yum update -y aws-cfn-bootstrap
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
date > /home/ec2-user/starttime
date > /home/ec2-user/stoptime
echo END
WebSG:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Web SG
VpcId:
Ref: VPCID
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: 10.0.0.0/8
Tags:
- Key: Name
Value: web_sg
ElbSG:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: ELB SG
VpcId:
Ref: VPCID
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '443'
ToPort: '443'
CidrIp: '0.0.0.0/0'
Tags:
- Key: Name
Value: elb_sg
ElasticLoadBalancer:
Type: AWS::ElasticLoadBalancing::LoadBalancer
DependsOn:
- ec2instance01
Properties:
LoadBalancerName: elb_01
SecurityGroups:
- Ref: ElbSG
Subnets: !Ref PrivateSubnets
Scheme: internal
Instances:
- Ref: ec2instance01
Listeners:
- LoadBalancerPort: '80'
InstancePort: '8080'
InstanceProtocol: HTTP
Protocol: HTTP
AccessLoggingPolicy:
EmitInterval: '60'
Enabled: 'False'
S3BucketName: elb-logs
S3BucketPrefix: ELB
HealthCheck:
Target: TCP:8080
HealthyThreshold: '5'
UnhealthyThreshold: '10'
Interval: '30'
Timeout: '5'
ConnectionDrainingPolicy:
Enabled: true
Timeout: '60'
Tags:
- Key: Name
Value: ELB_Name
Outputs:
ElbDNS:
Description: ELB DNS
Value:
'Fn::GetAtt':
- ElasticLoadBalancer
- DNSName
AppServerPrivateIP:
Description: Private IP address of instance ec2instance01
Value:
'Fn::GetAtt':
- ec2instance01
- PrivateIp
It looks like you are using the CloudFormation template designer. When you use the designer, it generates a CloudFormation template for you. You can see this by selecting the Template tab towards the bottom-left of the screen. You are also given the choice of JSON or YAML.