Abidoye Joshua mayowa
7 min readMay 27, 2023

Learn how to deploy CI/CD projects on AWS through the utilization of Terraform and Jenkins.

Greetings and welcome to week 20 of the LevelUp In Tech Bootcamp! In this week's project, I'll be demonstrating how to launch an EC2 instance in AWS using Terraform. Additionally, I'll guide you through the process of bootstrapping Jenkins and creating an S3 bucket that restricts public access.

What is Terraform & How does it work?

Terraform is an infrastructure tool that lets you define resources in configuration files and manage them consistently throughout their lifecycle. It can handle low and high-level components.

  • Write: As a user, you have the ability to designate resources from various cloud providers and services. An illustration of this is setting up a configuration for the deployment of an application on virtual machines within a Virtual Private Cloud (VPC) network, complete with security groups and a load balancer.
  • Plan: Terraform plans infrastructure changes based on your configuration.
  • Apply: Once approved, Terraform executes the intended actions in the appropriate sequence while considering any dependencies between resources.

What is Jenkins?

Jenkins provides an easy means of establishing a continuous integration or continuous delivery (CI/CD) system for a variety of programming languages and source code repositories via pipelines. It can also automate routine development tasks. Although scripts for specific steps are still required, Jenkins offers a more efficient and reliable method of integrating your entire build, test, and deployment toolchain than you could create alone.

Use Case

Your team would like to start using Jenkins as their CI/CD tool to create pipelines for DevOps projects. They need you to create the Jenkins server using Terraform so that it can be used in other environments and so that changes to the environment are better tracked. For the Foundational project, you are allowed to have all your code in a single main.tf file (known as a monolith) with hardcoded data. Push all your code to GitHub and include the link to your repo in your documentation.

Prerequisites:

  • AWS account
  • Vs Code IDE environment or AWS Cloud9
  • Basic Terraform knowledge

Objectives:

  1. Deploy 1 EC2 Instance in your Default VPC.
  2. Bootstrap the EC2 instance with a script that will install and start Jenkins.
  3. Create and assign a Security Group to the Jenkins Security Group that allows traffic on port 22 from your ip and allows traffic from port 8080.
  4. Create a S3 bucket for your Jenkins Artifacts that is not open to the public.
  5. Verify that you can reach your Jenkins install via port 8080 in your browser. Be sure to include a screenshot of the Jenkins login screen in your documentation.
  6. Push your code to GitHub and include the link in your write-up.

Step 1: Create the main.tf file

To kick off, we should generate the main.tf file in a fresh folder named TERA and utilize Visual Studio Code.

After opening the folder, we need to change the directory to the tera folder as shown below.

To avoid hardcoding AWS credentials in Terraform, we can pass them through as environment variables instead of writing them into the code. This bypasses the need for a provider's block.

Please execute the code below and replace the necessary fields with your personal information.

export AWS_ACCESS_KEY_ID=<id>
export AWS_SECRET_ACCESS_KEY=<id>

Step 2: Compile the code for main.tf

In order to proceed, we must update the AMI ID of the code provided. To locate the appropriate ID for the desired Amazon Linux 2 AMI (or any other preferred AMI), please access the AMI Catalog in the EC2 console. Once located, copy the AMI ID; please be aware that the ID will differ depending on the Region in use.

We set the instance type as "t2.micro".

In order to SSH into our instance, it's necessary to copy our keypair into the folder we're working on in VS Code. In the following code, my keypair is named "newkey".

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}

#Configure the AWS Provider
provider "aws" {
region = "us-east-1"
}

#Create EC2 Instance
resource "aws_instance" "instance1" {
ami = "ami-0bef6cc322bfff646"
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.jenkins_sg.id]
associate_public_ip_address = true
key_name = "newkey"
tags = {
Name = "jenkins_instance"
}

#Bootstrap Jenkins installation and start
user_data = <<-EOF
#!/bin/bash
sudo yum update –y
sudo wget -O /etc/yum.repos.d/jenkins.repo \ https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
sudo yum upgrade
sudo amazon-linux-extras install java-openjdk11 -y
sudo yum install jenkins -y
sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
EOF

user_data_replace_on_change = true

}

#Create security group
resource "aws_security_group" "jenkins_sg" {
name = "jenkins_sg14"
description = "Open ports 22, 8080, and 443"

#Allow incoming TCP requests on port 22 from any IP
ingress {
description = "Incoming SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

#Allow incoming TCP requests on port 8080 from any IP
ingress {
description = "Incoming 8080"
from_port = 8080
to_port = 8080

protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

#Allow incoming TCP requests on port 443 from any IP
ingress {
description = "Incoming 443"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

#Allow all outbound requests
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "jenkins_sg"
}
}

#Create S3 bucket for Jenkins artifacts
resource "aws_s3_bucket" "my-new-s3-bucket" {
bucket = "my-new-bucket-joshua-${random_id.randomness.hex}"

tags = {
Name = "jenkins_bucket"
Purpose = "for s3"
}
}
#To block public access
resource "aws_s3_bucket_acl" "my_new_bucket1_acl" {
bucket = aws_s3_bucket.my-new-s3-bucket.id
acl = "private"
depends_on = [aws_s3_bucket_ownership_controls.s3_bucket_acl_ownership]

}
resource "aws_s3_bucket_ownership_controls" "s3_bucket_acl_ownership" {
bucket = aws_s3_bucket.my-new-s3-bucket.id
rule {
object_ownership = "ObjectWriter"
}
}

#Create random number for S3 bucket name
resource "random_id" "randomness" {
byte_length = 16
}

Once we have compiled the entire code, it may be necessary to format the file if any mistakes were made. To do so, enter the command provided below.

terraform fmt

After running the command, I observed that the file was formatted accurately. Furthermore, the command below provided information about the file that was formatted.

Step 3: Deploy our Infrastructure

The next step is to begin the terraform workflow and deploy our infrastructure.

Firstly, run the command:

terraform init

When setting up your configuration files for Terraform, it's important to remember that the 'init' command is essential for downloading all the plugins needed to execute those files. This ensures that your process runs smoothly and efficiently without any hiccups along the way. So, be sure to run the 'init' command before you dive into your configuration files!

Now run the command:

terraform plan

When using Terraform, the command "terraform plan" generates an execution plan that outlines the resources that will be created based on the contents of the Terraform file.

To bring your Terraform file to life, simply execute the command: terraform apply. This will get your resource infrastructure up and running according to your specifications.

terraform apply

Step 4: Verify Infrastructure

Could you kindly check the management console to confirm if your instance, S3 bucket, and security groups are visible?

Instance is running and passed Health checks
Bucket Created successfully
The bucket is not Public

Step 5: Verify Jenkins Deployment

Connect to your instance via EC2 instance connect using SSH.

To make sure Jenkins has been installed successfully, go ahead and punch in this command:

sudo systemctl status jenkins

To ensure that Jenkins can be accessed through a web browser, kindly enter the address in your command line and web browser.

http://<instance_ip>:8080

Step 6: Clean up

Ready to tidy up and wipe out all the infrastructure resources we've put in place? Here's the command you need to run:

terraform destroy -auto-approve

Conclusion

I would like to express my gratitude for accompanying me on this Terraform tutorial. Let's continue learning together as I release more Terraform tutorials in the following weeks. Don't forget to check back every week!

Check out my GitHub link for this tutorial here https://tinyurl.com/gitjh. See you next time!

Abidoye Joshua mayowa

DevOps Engineer. I'm interested in collaborating with anyone interested in cloud engineer or cloud DevOPs.