Terraform Basics

Ebony Moorer
7 min readFeb 25, 2024

--

Terraform is a tool that revolutionizes the way we manage infrastructure in today’s digital age. Terraform operates on the principle of infrastructure as code (IaC), where infrastructure configurations are expressed in human-readable code rather than traditional manual processes. Terraform lets you treat your infrastructure like software code. Instead of clicking buttons in a web console or running manual commands, you write code that defines what your infrastructure should look like.

This approach brings several benefits:

  • IaC: Simplifies infrastructure management with code.
  • Declarative: Specifies desired state, automates details.
  • Dependency Graph: Plans changes intelligently.
  • Multi-Cloud: Manages resources across providers.
  • Immutable: Enhances reliability and security.
  • Version Control: Supports collaboration with Git.
  • Automation: Streamlines provisioning and scaling.
  • Scalability: Adapts to projects of any size.
  • Consistency: Maintains uniform configurations.
  • Auditability: Provides visibility into changes.

So How does terraform to this? By providing very simple components. These components include: resources, blocks and modules.

  • Resources: Individual components of your infrastructure (e.g., servers, databases) defined in Terraform using configuration blocks.
  • Blocks: Configuration elements within resources or modules that specify settings and attributes.
  • Modules: Reusable templates for infrastructure components and configurations, enabling easy abstraction and reuse across projects.

To showcase how to use terraform, I will be using the AWS console, AWS Cloud9 IDE, as well as using the terraform registry to make sure that I am using the correct configuration blocks.

  1. Deploy 1 EC2 Instances 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.

Links to help:

Overview — Configuration Language | Terraform | HashiCorp Developer

Terraform Registry

Provider Configuration — Configuration Language | Terraform | HashiCorp Developer

Linux (jenkins.io)

Jenkins and Docker: The Dynamic Duo | by Ebony Moorer | Jan, 2024 | Medium

My Github Repository!

Install Terraform

Using these commands, will allow you to download Terraform onto your instance in this case Cloud9. That way you can actually use the terraform commands.

sudo yum install -y yum-utils shadow-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
sudo yum -y install terraform

Configuration Explained

Provider Block:

The provider block specifies the cloud provider that Terraform will use to provision resources. In this case, it’s specifying AWS (Amazon Web Services).

provider "aws" {
region = "us-east-1" # Update with your desired region
}

Resource Blocks:

AWS VPC, Subnet, Security Group, Instance, S3 Bucket; A VPC is a virtual network in the AWS cloud. The cidr_block parameter specifies the range of IP addresses for the VPC.,

Subnets are segments of a VPC’s IP address range where you can place AWS resources. The vpc_id parameter specifies the ID of the VPC to which the subnet belongs, and cidr_block defines the IP address range for the subnet. Security groups act as virtual firewalls for your EC2 instances, controlling inbound and outbound traffic. In this case, it’s being configured to allow SSH traffic from a specific IP address and traffic on port 8080 from anywhere.

An EC2 instance is a virtual server in the AWS cloud. The Ami parameter specifies the Amazon Machine Image (AMI) to use for the instance (in this case, Ubuntu 20.04 LTS), instance type defines the instance size, subnet_id specifies the subnet where the instance will be launched, and security_groups specify the security group(s) associated with the instance.

S3 is a scalable object storage service provided by AWS. The bucket parameter specifies the name of the bucket to create, and acl specifies the access control list (ACL) for the bucket (in this case, “private” to restrict access to the bucket).

resource "aws_vpc" "default" {
cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "default" {
vpc_id = aws_vpc.default.id
cidr_block = "10.0.1.0/24"
}

resource "aws_security_group" "jenkins" {
# Configuration for security group...
}

resource "aws_instance" "jenkins_instance" {
# Configuration for EC2 instance...
}

resource "aws_s3_bucket" "jenkins_artifacts" {
# Configuration for S3 bucket...
}

Using Terraform Commands to Provision Resources

Once executed, Terraform will provision all these resources in the specified AWS region, creating the necessary networking infrastructure, security groups, EC2 instance, and S3 bucket required for hosting Jenkins and associated artifacts. *Although the script for Jenkins does work, I eventually had to manually install the Jenkins script to the EC2 instance.*

# main.tf

# Define provider and region
provider "aws" {
region = "us-east-1" # Update with your desired region
}

# Create a default VPC
resource "aws_vpc" "default" {
cidr_block = "10.0.0.0/16"
}

# Create a subnet within the default VPC
resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.default.id
cidr_block = "10.0.1.0/24"
}

# Create a security group for Jenkins
resource "aws_security_group" "jenkins" {
name = "jenkins-security-group"
description = "Security group for Jenkins"

vpc_id = aws_vpc.default.id

# Allow SSH from your IP
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Update with your IP
}

# Allow traffic on port 8080
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

# Create an EC2 instance
resource "aws_instance" "jenkins_instance" {
ami = "ami-0c7217cdde317cfec" # Ubuntu AMI, change as needed
instance_type = "t2.micro"
key_name = "terraformpracticekey" # Use the existing key pair name here
subnet_id = aws_subnet.public_subnet.id
associate_public_ip_address = true

user_data = <<-EOF
#!/bin/bash

sudo apt-get update -y
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update -y
sudo apt-get install -y fontconfig openjdk-17-jre
sudo apt-get install -y jenkins
sudo systemctl start jenkins
sudo systemctl enable jenkins

EOF
}

resource "aws_s3_bucket" "jenkins-s3-bucket1234512345" { #MAKE SURE BUCKET NAME IS UNIQUE
bucket = "jenkins-s3-bucket1234512345"

tags = {
Name = "Jenkins"
}
}

resource "aws_s3_bucket_acl" "s3_bucket_acl" {
bucket = aws_s3_bucket.jenkins-s3-bucket1234512345.id
acl = "private"
depends_on = [aws_s3_bucket_ownership_controls.s3_bucket_acl_ownership]
}

# Avoids error "AccessControlListNotSupported"
resource "aws_s3_bucket_ownership_controls" "s3_bucket_acl_ownership" {
bucket = aws_s3_bucket.jenkins-s3-bucket1234512345.id
rule {
object_ownership = "ObjectWriter"
}
}

To do this, these commands tell Terraform execute your requests.

# Initialize Terraform: 
# This command initializes the directory containing your Terraform configuration files.
terraform init

# Format Terraform Configuration Files:
# This command automatically formats all Terraform configuration files in the current directory.
# It recursively traverses directories, formatting all '.tf' files it encounters.
terraform fmt -recursive

# Validate Terraform Configuration Syntax:
# This command checks the syntax and configuration of your Terraform files for errors.
terraform validate

# Preview Changes:
# This command shows an execution plan without making any actual changes.
terraform plan

# Apply Changes:
# This command applies the changes required to reach the desired state of the configuration.
terraform apply
# During the apply process, Terraform will prompt you to confirm whether you want to perform the planned actions.
# You can type 'yes' to proceed.

# Destroy Resources (Optional):
# If you want to destroy the resources created by Terraform, you can use the following command.
terraform destroy
# This command will prompt you to confirm whether you want to destroy all the resources managed by the Terraform configuration.

Verifying resources were provisioned and connection to Jenkins

When you will check back in with your AWS console for EC2 and S3, You should see the names of all of the things that you have created. Case, I did not name my instance, so it does not have a name, but every other resource was created.

Using a PowerShell, I connect to my EC2 instance, and I use the IP address and the :8080 port number to access Jenkins. *https:/localhost:8080* Once connected, Jenkins will provide you with a command that you will use to access your password to sign into Jenkins and create an account.

sudo cat /var/kib/jenkins/secrets/initialAdminPassword

--

--