Jenkins, Powershell, AWS and Cloudflare Automated Deployment. (Part2 Configure AWS)

If your interested in only the code, export of the Jenkins template and list of needed plugins it can be found on my Github

Welcome to Part Two of my on going series about how to do an AWS deploy with cloudflare using Jenkins, and Powershell. Part One can be found here. In the last post I listed the needed plugins for Jenkins, plugins for Powershell and the work flow for the script. If you have been working with the code I posted I suggest looking at the latest on my Github. I have made a few minor improvements.

For this post I’m going to focus on the different configuration settings that are needed. Both in the Jenkins build and in AWS. By the end of the post you will be able to deploy an EC2 instance of your choosing to any configured Region.

The full set of Jenkins build options:

Build Options Break Down

Region

This is where we limit the regions the user will be able to deploy into. I currently have picked us-west-2, and us-west-1. Since us-west-2 is configured I’ll be building out requirements in us-west-1. You can pick which ever region you prefer for this example. A list of AWS regions can be found here.

Jenkins Build:

Under the hood with Powershell:

The region Choice parameter is assigned to a variable:

$region = $ENV:Region

Instance Name

Instance name is what the ec2 instance is named. It is also used later when deploying to cloudflare. No special configuration is needed outside the Jenkins build.

Jenkins Build:

I recommend leaving the String Parameter blank. This is due to behavior in the aws script.

Under the hood with Powershell:

Instance name is assigned to a variable.

$instance_name = $ENV:Instance_Name

Later in the code we check the instance was named something even if it is just a character long:

if($instance_name.length -le 1) {
echo "ERROR: Instance must be named and the length must be greater than 1."
echo "ERROR: Instance name: $instance_name"
echo "ERROR: Instance name length" $instance_name.length
exit 1
}

 

Domain

Not needed by the AWS deployment section, but it is used in the cloudflare deployment. There is no Powershell code in an AWS deployment that depends on this. I’ll touch on it more in the next post when I cover the cloudflare section. Just make sure the domains you want to use are listed, and they are already in cloudflare or you’re willing to transfer them to cloudflare.

Jenkins build:

Under the hood with powershell: Not used during this stage. We will cover it in the next post.

Image_type

Image IDs change from Month to Month and region to region. The month to month change is largely due to updates. I went with image description, and most up to date version of the image as the criteria for this section.

Jenkins Build:

Launch the AWS console to Go EC2 instances, and click on Launch Instance Wizard.

Select the image you want. For this example I’m going with a Public Windows AMI:

Notice the Ami ID is “ami-179ac977

On the Right hand side select “Community AMIs” and find your AMI again:

Now we will copy the description where it says  Microsoft Windows Server 2016 with Desktop Experience Locale English AMI provided by Amazon copy that and past it under a choice parameter labeled image_type of your jenkins build.

Under the hood with powershell:

$image_Type is assigned a variable near the top of the script.

$image_type = $ENV:image_type

Later on the $image_type combined with the $region variable searches for the description and reports the ImageID as a string.

Note the -First 1 flag select addition. This is because amazon can keep multiple images with different levels of updates. This makes sure that you always get the most up to date image:

Get-EC2Image -Owner amazon, self -Region $region | where { $_.Description -eq $image_type } | select -first 1 -expandproperty ImageId

Instance Type:
You are free to use any of the common model names for instance_types found here. In Jenkins the top choice is selected by default. I personally put the cheapest Instance for the project at the top. The build and project of course doesn’t care what order you sort them, so do what make sense for your project.

Jenkins Build:

Under the hood with Powershell:

The variable is defined. Since the Instance type is universal between regions and rarely changes that is all we need to do till the AWS instance is generated in the script.

$Instance_Type = $ENV:Instance_Type

 

Security_Group:

The Name of the Security Group must exist in all Regions you will be deploying in. I personally name them after the services that are allowed.

Go back to your AWS Management console, select the region you have chosen to configure. For me that is us-west-1.

In the EC2 dashboard go to the security groups option on the left. Create a security group and name it something that makes sense for your project.

In my case I created “SSH, HTTP, HTTPS, ICMP” and “RDP, HTTP, HTTPS, ICMP”

Set the rules by your security policy as well as your VPC settings that match your AWS policy.

Under the hood with Powershell:

The name of security group is searched and then the GroupID is assigned.

$SecurityGroup_Id = Get-EC2SecurityGroup -Region “$region” | where { $_.Groupname –eq “$SecurityGroup” } | select -expandproperty GroupId
AWS_Profile:

When originally setting up your Powershell AWS plugin under getting started it has you to store your credentials in powershell.

Make sure the Jenkins service is running as a user, and the AWS Plugin was setup under that profile. I named the profile name “Jenkins_deploy.” You can store multiple AWS profiles in this manner. The profile name doesn’t really matter so you can name it something more descriptive for your users.

Under the hood with Powershell:

The Environment variable is set, and the AWS profile credentials are loaded:

$aws_profile = $ENV:AWS_Profile

Set-AWSCredentials -ProfileName $aws_profile

Key_Pair:

In each aws region you will need to make sure there is a key pair uploaded and configured for the VM you are generating. If you plan on deploying to only one Region you can let AWS generate the keypair and be all set. If you plan on having the same multiple key pairs across regions I suggest looking into generating and importing the key pairs.

Under the hood with Powershell:

The Environment variable is set, and the AWS profile credentials are loaded:

$env:Key_pair = $Key_pair

 

Build Variables And Tagging:

If you installed the plugins from the last post you should see a check mark field:

This will populate the BUILD_USER and BUILD_TAG variables:

Under the hood with Powershell:

$builder = $ENV:BUILD_USER
$buildtag = $ENV:BUILD_TAG

#Once EC2 instance is created tags are added that are visible in the AWS console
echo “Naming Instance”
$tag = New-Object Amazon.EC2.Model.Tag
$tag.Key = “Name”
$tag.Value = “$instance_name”

New-EC2Tag -Resource $instance_info.instances.instanceid -Tag $tag -Region $region
echo “Tagging build information”
$tag.Key = “BuiltBy”
$tag.Value = “$builder”
New-EC2Tag -Resource $instance_info.instances.instanceid -Tag $tag -Region $region

$tag.Key = “BuildTag”
$tag.Value = “$BUILDTAG”

New-EC2Tag -Resource $instance_info.instances.instanceid -Tag $tag -Region $region

Optional:

So now you should have added all the Jenkins build parameters: Region, Instance_Name, Domain, image_type, Instance_Type, Security_Group,AWS_Profile and Key_Pair. If any of these will be static you can always skip the Jenkins build step by removing it and simply define the variable in the build as a static string:


$aws_profile = $ENV:AWS_Profile
#Load all the other environment variables AWS needs to to create an instance

$region = “us-west-1”
$instance_name = $ENV:Instance_Name
$builder = $ENV:BUILD_USER
$buildtag = $ENV:BUILD_TAG
$image_type = “t2.micro”
$Instance_Type = $ENV:Instance_Type
$domain = $ENV:Domain
$Key_pair = $ENV:Key_Pair
$SecurityGroup = $ENV:Security_Group

 

Add Powershell Build Step:

The final step is to add a powershell Build step and copy the powershell code into it.

It is easiest to pull the latest code off of my github and copy and paste it into place.

 

Now run the jenkins build.

A successful build’s console output will look like:


A failure should provide an error message that hints where you went wrong. I suggest checking for spaces, or typos. I used a try/catch method that should display the powershell error in the console output of Jenkins.

Alright, that is it for this week. In Part 3 I’ll combine the injected environment variables and talk about the cloudflare integration steps and the Powershell code driving it in Jenkins.
Thanks for reading

I_script_stuff