passing file to ec2 in cloud formation - amazon-web-services

I have a cloudfromation script that creates some ec2 instances, and later attaches them to an ELB.
I have a python server script written that I would like to have on the ec2 as soon as they are created.
Right now what I do is after the cloudformation script finishes, I use SCP to pass the script to the ec2 instances.
I was wondering if there was a way to do this within the cloudfromation, mabe under UserData?
I should point out I am very new to cloud formation. I have gone over the documentation, but have not been able to do this yet.
[EDIT] I think its important to state that I have a deploy.sh script that I run to create the stack. the script sits in the dame dir as my python server script. I AM NOT USING THE AWS CONSOLE.
this is my instance code in the cloudformation script:
EC2Instance2:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
SecurityGroupIds:
- !Ref InstanceSecurityGroup
KeyName: !Ref KeyName
ImageId: !Ref LatestAmiId
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
sleep 20
sudo apt-get update
sudo apt-get install python3-pip -y
sudo apt-get install python3-flask -y

I was wondering if there was a way to do this within the cloudfromation, mabe under UserData?
Yes, UserData would be the way to do it. For that you could store your file in S3. For that to work you would need to add instance role to your instance with S3 permissions. The you would use AWS CLI to copy your file from S3 to the instance.

Related

Is there a way to use resources created by ec2 user data in my cloudformation stack for another resource in the stack?

im working on a template in which i deploy an ec2 instance, in the instances user data, the instance pulls a script from a git repo and uses that script create an AMI. I would like to refer to that newly created ami’s ID in another resource in the same cloudformation stack using the either by using !ref or some other way.
so far I have placed this line below in the user data to get the name of the ami
export AMIID=$(aws ec2 describe-images --filters "Name=name,Values=ami-name" | jq -r ".Images[].ImageId")
and this line to create an entry to put the AMI ID in the parameter store
aws ssm put-parameter --name aminame --type String --value "$AMIID"
In the cloudformation stack I have a parameter here
AMI:
Type : 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: aminame
and in the resource block I have this the reference to the ami that looks something like this
EC2Instance:
Type: "AWS::EC2::Instance"
CreationPolicy:
ResourceSignal:
Timeout: PT120M
Properties:
ImageId: !Ref AMI
UserData:
Fn::Base64: |
#!/bin/bash
So far when I run this I get an error stating that the parameter cannot be found.. which makes sense, however is there any other way to do something like this ?
Technically you can do that using lambda:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html

AWS CloudFormation -- auto mount EFS

I'm trying to create a CF script that creates an EC2 and then automatically mounts an EFS. Here's the relevant bit of the template. I find that the packages are not loaded: amazon-efs-utils, nfs-utils.
Therefore if the mount command is executed it will fail.
I've verified that my other stack has what I need and the output variable is correct: !ImportValue dmp356-efs-EFSId
If I log into my new instance and do the steps manually it works fine and I can see my files in the EFS. Naturally I suspect that my CF script is wrong in some way, although it validates if I use "aws cloudformation validate-template ..." and it deploys with a successful conclusion. As I said, I can log into the new instance, it doesn't rollback.
Resources:
TestHost:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
configSets:
MountConfig:
- setup
- mount
setup:
packages:
yum:
amazon-efs-utils: []
nfs-utils: []
commands:
01_createdir:
command:
"mkdir /nfs"
mount:
commands:
01_mount:
command: !Sub
- mount -t efs ${EFS_ID} /nfs
- { EFS_ID: !ImportValue dmp356-efs-EFSId }
02_mount:
command:
"chown ec2-user.ec2-user /nfs"

Why am I getting "YAMLException: bad indentation of a mapping entry" on AWS Cloudformation?

I am starting to learn/work with AWS and Cloudformation, I have this:
Type: 'AWS::EC2::Instance'
Properties:
SecurityGroupIds:
- !Ref InstanceSecurityGroup
SubnetId:
!Ref "PublicSubnet1"
IamInstanceProfile:
!Ref RootInstanceProfile
ImageId: ami-02cb52d7ba9887a93
InstanceType: t3.micro
UserData:
Fn::Base64: !Sub |
#!/bin/bash
# Install Apache Web Server and PHP
yum install -y httpd mysql
amazon-linux-extras install -y php7.2
# Download Lab files
wget https://us-west-2-tcprod.s3.amazonaws.com/courses/ILT-TF-100-ARCHIT/v6.5.0/lab-2-webapp/scripts/inventory-app.zip
unzip inventory-app.zip -d /var/www/html/
# Download and install the AWS SDK for PHP
wget https://github.com/aws/aws-sdk-php/releases/download/3.62.3/aws.zip
unzip aws -d /var/www/html
# Turn on web server
chkconfig httpd on
service httpd start
When I try to create the stack I receive an identention error at UserData:
Any advice or tip?
Thank you so much for your help
You can use this as an example for writing the userdata in cloudformation template.
Use cfn-linter and the documentation for generating the template, there are plenty of good examples in the documentation as well.
Github Search always results into working examples.
The linter can be installed as a plugin in VS Code or you can run it from your command line the above one.
The error says that you have indentation issue in your UserData which is clear from your code. It should be (you also don't need Sub):
Type: 'AWS::EC2::Instance'
Properties:
SecurityGroupIds:
- !Ref InstanceSecurityGroup
SubnetId:
!Ref "PublicSubnet1"
IamInstanceProfile:
!Ref RootInstanceProfile
ImageId: ami-02cb52d7ba9887a93
InstanceType: t3.micro
UserData:
Fn::Base64: |
#!/bin/bash
# Install Apache Web Server and PHP
yum install -y httpd mysql
amazon-linux-extras install -y php7.2
# Download Lab files
wget https://us-west-2-tcprod.s3.amazonaws.com/courses/ILT-TF-100-ARCHIT/v6.5.0/lab-2-webapp/scripts/inventory-app.zip
unzip inventory-app.zip -d /var/www/html/
# Download and install the AWS SDK for PHP
wget https://github.com/aws/aws-sdk-php/releases/download/3.62.3/aws.zip
unzip aws -d /var/www/html
# Turn on web server
chkconfig httpd on
service httpd start

Cloud9 and CloudFormation - access EC2 instance

I'm creating a cloud9 instance in cloudformation as follows:
Resources:
DevEnv:
Type: 'AWS::Cloud9::EnvironmentEC2'
Properties:
SubnetId: !Ref PublicSubnet
Name: MyEnvironment
InstanceType: !Ref Cloud9InstanceType
Subsequently, I want to run a bash script on that EC2 instance (within the cloudformation script) to set it up properly. How do I do that?
Unfortunately you can't. AWS::Cloud9::EnvironmentEC2 doesn't expose UserData or something like that and you cannot run SSM Documents against Cloud9 instances.
The closest you can get is using Repositories to clone a AWS CodeCommit into the instance, and that repository has a script that you run manually first time you connect...

How to set the instance type with Elastic Beanstalk?

How can I change the instance type of an existing Elastic Beanstalk application?
Currently I am changing it in the web interface:
I tried changing it with the command line tool:
eb setenv InstanceType=t2.medium
It didn't throw an error, but also didn't change the instance type.
The setenv command is for changing Environment Variables. Hence the command you tried is bash equivalent of:
export InstanceType=t2.medium
And doesnt really do anything for your beanstalk environment.
You can create an environment using the -i option during create
eb create -i t2.micro
Or, you can use eb config to edit a currently running environment. This will open up a text editor. Look for the section that looks like:
aws:autoscaling:launchconfiguration:
IamInstanceProfile: aws-elasticbeanstalk-ec2-role
EC2KeyName: aws
InstanceType: t1.micro
And edit the t1.micro to t2.micro. (save and quit)
But just to make your life easier, you can save the below as .elasticbeanstalk/saved_configs/default.cfg.yml and the CLI will use all these settings on all future creates.
AWSConfigurationTemplateVersion: 1.1.0.0
OptionSettings:
aws:elb:loadbalancer:
CrossZone: true
aws:elasticbeanstalk:command:
BatchSize: '30'
BatchSizeType: Percentage
aws:autoscaling:launchconfiguration:
IamInstanceProfile: aws-elasticbeanstalk-ec2-role
EC2KeyName: aws
InstanceType: t2.micro
aws:elb:policies:
ConnectionDrainingEnabled: true
aws:autoscaling:updatepolicy:rollingupdate:
RollingUpdateType: Health
RollingUpdateEnabled: true
aws:elb:healthcheck:
Interval: '30'
More scriptable way:
aws elasticbeanstalk update-environment --environment-name "your-env-name" --option-settings "Namespace=aws:autoscaling:launchconfiguration,OptionName=InstanceType,Value=t2.micro"
The accepted solution didn't work for me in 2020.
As of today (26th, February 2020), in my .ebextensions/02_python.config I had to add the following under option_settings:
option_settings:
# ...
aws:ec2:instances:
InstanceTypes: 'm5.large'
Reference: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.as.html#environments-cfg-autoscaling-namespace.instances