How to insert AWS resource IDs into application configuration files - amazon-web-services

I'm following the AWS guide for deploying an HA Wordpress site to Elastic Beanstalk which includes using the eb-php-wordpress extension. The process requires editing a couple of configuration files with known resource IDs prior to deploying the application.
In particular, the instructions say to edit the efs-create.config file with a VPC ID, and Subnet IDs. The file, among other things, helps set the OptionSettings property of the AWS::ElasticBeanstalk::Environment resource. For this reason, I suspect I should just be able to reference it with Ref:. Is this correct, though since the VPC would be created by another file and the EB environment Cloudformation stack is created next to the VPC stack rather than "inside" it? Would I have to use a Fn:: call to get the information?
The section of the configuration file I'm working with looks like this:
option_settings:
aws:elasticbeanstalk:customoption:
EFSVolumeName: "EB-EFS-Volume"
VPCId: "vpc-XXXXXXXX"
## Subnet Options
SubnetA: "subnet-XXXXXXXX"
SubnetB: "subnet-XXXXXXXX"
SubnetC: "subnet-XXXXXXXX"
SubnetD: "subnet-XXXXXXXX"
Would the VPCId line be something like
VPCId: {Ref: VPC}
Where VPC is the name of the VPC resource that I've created? Or, more simply, how would I reference the VPC ID of the default VPC if I stick with that?

You should be able to use Ref to get the various IDs of the elastic beanstalk named resources, according to the docs. However, the VPC is not one of these named resources (ie those with a logical ID), but is a property of one of the named resources, in this case, the logical ID is AWSEBSecurityGroup and the property is VpcId so you should be able to get it instead using GetAtt:
{ "Fn::GetAtt" : [ "AWSEBSecurityGroup", "VpcId" ] }
from the functions docs and the CloudFormation docs
A similar approach should also work for the subnets.

Related

Existing dynamic AWS resources in cloudformation template

I have already created AWS network resources(VPC,subnets,IGW etc) through AWS console.
Now, I am trying to create a cloudformation stack consisting of those existing & new resources.
To implement existing resources in the stack, I am using Parameters
Parameters:
VpcId:
Description: VPC Id
Type: AWS::EC2::VPC::Id
PublicSubnetId1:
Description: Public Subnet 1
Type: AWS::EC2::Subnet::Id
PublicSubnetId2:
Description: Public Subnet 2
Type: AWS::EC2::Subnet::Id
InternetGateway:
Type: AWS::EC2::InternetGateway::Id
Question 1: Is this the right approach ? (As we have diff envs so to handle dynamic AWS resources, I am doing this)
Question 2: I am able to set parameter with VPC,subnets but not with Internet gateway. How to put internetgateway as a parameter ?
Thanks
Question 1: Is this the right approach ? (As we have diff envs so to handle dynamic AWS resources, I am doing this)
Its one way of doing this. If you want to be able to select different subnet or vpc at template creation then its fine. However, if the VPC and subnets are fixed and do not change, probably better would be to export them from their own stacks, end them import them in other stacks. This way other stacks can easily refer to them, and you have simplified deployment your stacks as you don't need to provide all these parameters for each new stack.
Question 2: I am able to set parameter with VPC,subnets but not with Internet gateway. How to put internetgateway as a parameter ?
Unfortunatly, there is no such parameter like AWS::EC2::InternetGateway::Id. In this case you would have to use String:
InternetGateway:
Type: String

Is it possible to execute commands and then update security groups in a CloudFormation template?

I would like to perform the following operations in order with CloudFormation.
Start up an EC2 instance.
Give it privileges to access the full internet using security group A.
Download particular versions of Java and Python
Remove its internet privileges by removing security group A and adding a security group B.
I observe that there is a DependsOn attribute for specifying the order in which to create resources, but I was unable to find a feature that would allow me to update the security groups on the same EC2 instance twice over the course of creating a stack.
Is this possible with CloudFormation?
Not in CloudFormation natively, but you could launch the EC2 instance with a configured userdata script that itself downloads Java/Python and the awscli, as necessary, and then uses the awscli to switch security groups for the current EC2 instance.
However, if all you need is Java and Python pre-loaded then why not simply create an AMI with them already installed and launch from that AMI?
The best way out is to utilise a Cloudformation custom resource here. You can create a lambda function that does exactly what you need. This lambda function can then be called as a custom resource function in the cloud formation template.
You can pass your new security group ID and instance ID to the lambda function and code the lambda function to use AWS SDK and do the modifications that you need.
I have leveraged it to post an update to my web server about the progress of the cloud formation template. Below is the sample code of the template.
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [!Ref 'EC2Role']
MarkInstanceProfileComplete:
Type: 'Custom::EC2InstanceProfileDone'
Version: '1.0'
DependsOn: EC2InstanceProfile
Properties:
ServiceToken: !Ref CustomResourceArn
HostURL: !Ref Host
LoginType: !Ref LoginType
SecretId: !Ref SecretId
WorkspaceId: !Ref WorkspaceId
Event: 2
Total: 3
Here the resource MarkInstanceProfileComplete is a custom resource that calls a Lambda function. It takes the event count and total count as input and processes them to calculate percentage progress. Based on that it sends out a request to my web server. For all we care, this Lambda function can do potentially anything you want it to do.

Is there a way to configure the Auto Scaling Group termination policy when using Elastic Beanstalk?

The ASG part of Beanstalk options does not have it listed: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html?shortFooter=true#command-options-general-autoscalingasg - and neither does the rest of the page.
Right now I'm having to resort to manually editing the termination policy in the ASG page in EC2.
The following works for me. I use .ebextensions folder to configure my apps. Inside I have created a termination.config file containing this:
Resources:
AWSEBAutoScalingGroup:
Type: "AWS::AutoScaling::AutoScalingGroup"
Properties:
TerminationPolicies: [ "OldestInstance" ]

Cloud Formation: How to get VPC from Subnet Id

I have a Cloud Formation to set up an EC2 instance. I'm currently using the Parameters to specify the Subnet Id for the EC2 instance as well as the VPC Id for the Security Group (to be used in turn by the EC2 instance).
In my situation the Subnet Id specified is required to be part of the VPC and I'd like to only have to specify the Subnet Id in the Parameters. But I can't find a way to derive the VPC from the Subnet Id (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html)
I see the GetAtt function can be used to return resource attributes. Is there something equivalent to return resource properties?
From the documentation Fn:GetAtt, you can only retrieve AvailabilityZone and Ipv6CidrBlocks details of the Subnet. There is no inbuilt support to get VpcId of the given subnet in CFn Templates.
There is a work-around though. If you are using the aws-cli documentation, you can use the describe-subnets method to fetch the VpcId of the required subnet and pass it as input to the Cloudformation template create_stack call.
This method works even if you are using any SDK. for example, in Java.
//pseudo code only!
DescribeSubnetsRequest request = new DescribeSubnetsRequest();
request.withSubnetIds("subnet-abcdefgh");
DescribeSubnetsResult result = awsClient.describeSubnets(request);
String myVpc = result.getSubnets().get(0).getVpcId();
// add the above VPC Id to the parameters of your Cloud formation template create stack request.
Hope this helps.
I created a small project called cli2cloudformation. Using that you're able to execute cli commands inside your cloudformation stack and use the results of the commands.
Just check it here. I hope it helps you.

AWS Elastic Beanstalk - can I set the name of the scaling group?

I can set the name of the LoadBalancer that EB defines with the following ebextension configuration:
Resources:
AWSEBLoadBalancer:
Type: "AWS::ElasticLoadBalancing::LoadBalancer"
Properties:
"LoadBalancerName":
"Fn::Join":
- ""
-
- {Ref: AWSEBEnvironmentName}
- "-elb"
This lets me address the loadbalancer by name in scripts, and also makes the loadbalancer list in the EC2 console much easier read (can just scan for the ELB you're interested in instead of having to dig through tags).
I'd like to do similar for the autoscaling group, is there any way to do this?
Edit: I've decided not to manipulate the ASG directly (should be done through EB settings, not by manipulating the ASG directly, to avoid inconsistency). But I would still like to rename the ASG, just to make the console view cleaner.
This can be done with { Ref: AWSEBAutoScalingGroup }.
A complete list of all supported options is available here: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-format-resources-eb.html