# Using Jenkins to create AWS Infrastructure with Terraform.

The finished product of this project is terraform code that builds an AWS environment with three EC2 instances. The Jenkins CI/CD Pipeline will be triggered when the code is pushed to a GitHub repository via GitHub Webhook.

## What is Jenkins?

Jenkins is an open-source automation server that helps facilitate the continuous integration and delivery (CI/CD) of software projects. It allows developers to automate various stages of the software development lifecycle, including building, testing, and deploying applications.

## What is Terraform?

Terraform is an open-source infrastructure as code (IaC) tool developed by HashiCorp. It enables you to define and manage your infrastructure resources, such as virtual machines, networks, storage, and services, in a declarative manner. With Terraform, you can provision and manage your infrastructure across various cloud providers and on-premises environments.

# **Prerequisites**

* [GitHub](https://github.com/) Account
    
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
    
* [AWS Account](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/)
    
* Install [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli)
    
* Jenkins Installed
    
* [Terraform Cloud](https://app.terraform.io/signup/account?utm_source=cloud_landing&utm_content=offers_tfc) Account
    
* Install [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
    

## Configure Terraform Cloud

[Terraform Cloud](https://cloud.hashicorp.com/products/terraform) is an application that helps teams use Terraform together. It manages Terraform runs in a consistent and reliable environment, and includes easy access to shared state and secret data, access controls for approving changes to infrastructure, a private registry for sharing Terraform modules, detailed policy controls for governing the contents of Terraform configurations, and more.

1. Sign in to [Terraform Cloud](https://app.terraform.io/session)
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685385220868/ab670394-7640-4d00-8800-7dde24f12141.png align="center")

2\. Select **CLI-driven workflow**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685385019206/2210acf5-33a2-4784-99f8-83d7166ba8dc.png align="center")

1. Name your workspace then Create workspace.
    
2. Copy the provided example code and add it to `backend.tf` to replace the current backend.
    
    ```yaml
    terraform {
      cloud {
        organization = "YOUR ORGANIZATION NAME"
    
        workspaces {
          name = "YOUR WORKSPACES NAME"
        }
      }
    }
    ```
    

Set the Execution Mode by clicking Remote and selecting **Local**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685386016352/f8bd5f91-c9c2-401a-b1cb-17beeb6ee2db.png align="center")

### Create Terraform Cloud Token

1. Run `terraform login` in CLI and Enter the value `yes`.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685386410934/873ad73d-f212-46ad-97d7-0b919cb25871.png align="center")
    
2. Terraform will open a web browser to the tokens page for [app.terraform.io](http://app.terraform.io).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685386570419/87d8bb4e-8ebf-46a3-bec3-7a5d74f2ab63.png align="center")
    
3. Enter a **Description** and click **Generate token**.
    
4. Copy down the provided token and keep it in a safe place. (You can always generate a new token if you lose the previous one)
    
5. Copy and paste the Terraform Cloud token
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685386987183/3dc83777-82e0-4d24-95a4-7a7da9d4c2bb.png align="center")
    
6. Run `terraform init`
    

This ensures our Terraform code is connected to Terraform cloud, uses Terraform cloud workspaces and stores our state file remotely.

## Terraform Code

Create the following terraform files

`backend.tf`

```yaml
terraform {
  cloud {
    organization = " YOUR ORGANIZATION NAME "

    workspaces {
      name = " YOUR WORKSPACES NAME "
    }
  }
}
```

`provider.tf`

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

provider "aws" {
  region = "us-east-1"
}
```

`variables.tf`

```yaml
variable "instance_type" {
  type    = string
  default = "t2.micro"
}
variable "monitoring" {
  default = true
}

variable "tags" {
  type = map(any)
  default = {
    Terraform   = "true"
    Environment = "dev"
  }
}

data "aws_vpc" "selected" {
  default = true
}

data "aws_security_groups" "default" {

  filter {
    name   = "group-name"
    values = ["default"]
  }
}
```

`ec2.tf`

```yaml
module "ec2_instance" {
  source = "terraform-aws-modules/ec2-instance/aws"

  for_each = toset(["one", "two", "three"])

  name = "instance-${each.key}"

  instance_type          = var.instance_type
  monitoring             = var.monitoring
  vpc_security_group_ids = data.aws_security_groups.default.ids

  tags = var.tags
}
```

## **Create Security Group**

Create the **Jenkins** Security Group with the following inbound rules:

* **Type**: HTTP  
    **Port range**: 8080  
    **Source**: My IP
    

Outbound Rules:

* **Type**: All traffic  
    **Port range**: All  
    **Destination:** 0.0.0.0/0
    

## Jenkins Configuration

1. Enter \[Public IP\]:8080 or \[Public DNS\]:8080 in your browser to see Jenkins setup.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685471830495/9cb93a64-3761-4a6c-b447-34a6cbe909d3.png align="center")
    
    1. retrieve your administrative password by running `sudo cat /var/lib/jenkins/secrets/initialAdminPassword`
        
    2. Copy and then paste the result into the Unlock Jenkins field and click **Continue**.
        
    3. Click **Install suggested plugins**.
        
    4. Enter the required information. **Save** and continue to Jenkins.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685476075082/ed2c4d35-eac9-459d-9684-a6ea824935a9.png align="center")
        
    5. Click **Manage Plugins** &gt; Select **Available** &gt; Search **Pipeline: AWS Steps**, **Terraform** and **install without restart**.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685476525488/5dc9483e-02b4-4ec6-9249-ca9b6bef9140.png align="center")
        
2. Click **Manage Jenkins &gt; Global Tool Configuration** then scroll to **Terraform and click Add Terraform**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685476795803/3baebc25-65f7-4c7c-b310-2cf4f46487ef.png align="center")
    
3. Enter any name of your choice and select Terraform version `Terraform 30504 linux (386)` and click save
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685477238344/497b3f14-5435-4008-9bc5-f2732d91295d.png align="center")
    
    ### **Terraform Cloud Credentials**
    
    1. To get the Terraform Cloud credentials, in the terminal run `cat /home/<YOUR-USERNAME>/.terraform.d/credentials.tfrc.json` for Linux or open the the file `credentials.tfrc.json` with the path `C:\Users\<YOUR-USERNAME>\AppData\Roaming\terraform.d\credentials.tfrc.json` in windows.
        
    2. Copy the output. Create a local txt file and paste the output and save.
        
    3. Go back to Jenkins and **add a new credential**.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685482388544/91d0538b-099b-4064-9f4c-d016ac392e86.png align="center")
        
    
    * **Kind** = Secret file
        
    * **File** = (Choose the file you just saved)
        
    * **ID** = tf-creds
        
    * **Description** = terraform cloud credentials
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685546778972/360ea543-f0e5-435d-9c42-675315800768.png align="center")
    
4. Click **Create**
    

### GitHub Webhooks

1. Go to the project GitHub repo and click **Settings**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685483136057/9435a96c-597f-45ab-b4ff-2d2c2d135271.png align="center")
    
2. Click **Webhooks then Add Webhook**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685483325760/16fc42ed-2463-4b58-a82b-cbff046101fa.png align="center")
    
3. Enter the following:
    
    **Payload URL** = \[jenkins url\]/github-webhook/  
    Please Note: Ensure the `/` is at the end.  
    **Content type** = application/json
    
    **Which events would you like to trigger this webhook?** = Just the push event
    
4. Click **Add WebHook**
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685483580792/23443cfe-780f-414e-93b4-aa2c6e68076f.png align="center")

### **Create Jenkins Pipeline**

1. **Go to the Jenkins Dashboard and click New Item.**
    
2. **Name the pipeline** `terraform-jenkins` **and select Pipeline. Then click OK.**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685485787561/60e5e1c8-c3e4-4394-8fa7-2456cca9d093.png align="center")
    
3. **Configure the pipeline  
    1\. Build Triggers = GitHub hook trigger for GITScm polling**
    
    **2\. Pipeline Definition = Pipeline script from SCM**
    
    **3\. SCM = Git**
    
    **4\. Repository HTTPS URL = \[repo name\].git**
    
    **5\. Branches to build = \*/main**
    
    **6\. Script Path = jenkinsfile**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685501661597/a4e73346-7c0c-490d-af6a-7a89cf8b4166.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685501703501/128dada0-4c9b-42a5-bc89-2228b397c668.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685501734421/29d2478d-420d-4b98-b81a-69a6cfa496bc.png align="center")
    

### **JenkinsFile**

**Jenkins requires a** `Jenkinsfile` **in the root of our code directory to create a Jenkins Pipeline.**

```yaml
pipeline {
  agent any
  environment {
    TF_IN_AUTOMATION = 'true'
    TF_CLI_CONFIG_FILE = credentials('tf-creds')
  }
tools {
  terraform 'terraform'
}

stages {
    stage('Init') {
      steps {
        sh 'terraform init -no-color'
      }
    }
    stage('Plan') {
      steps {
        sh 'terraform plan -no-color'
      }
    }
    stage('Apply') {
      steps {
        sh 'terraform apply -auto-approve -no-color'
      }
    }
}
}
```

Push your code to GitHub and the build process will be triggered because of the GitHub webhook we created earlier.

The image below shows a successful build along with the instances running in AWS**.**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685502054145/e355a9c7-1cda-470a-aea3-0eb9a6af2175.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685502149261/0213e315-e1d2-4aa6-9a50-8bef0f1a4315.png align="center")

## **Destroy the Infrastructure using Jenkins Build Parameters**

Our intention with build parameters is to provide an option for the users to select which “Action” they wish to perform. Depending on the selection, the pipeline will either run the “apply” command or “destroy” the infrastructure.

1. Go to: **Dashboard &gt;terraform-jenkins&gt; Configuration.** In the general section, click on the checkbox stating, **“This project is parameterized.”**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685502851340/3d08b6d0-0dc6-4f1f-94bc-113e20210a32.png align="center")
    
2. Select the **Choice Parameter** and fill in the form as shown below. The name represents the “variable” name we will use in our pipeline script to replace the variable with the selected value.
    
    Each choice is listed on the next line; here, we have two choices – apply and destroy. These are potential values.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685503284092/4919776e-d4d4-4ad5-87d9-addb72d9a254.png align="center")
    
3. **Edit the** `jenkinsfile` **to use the action variable in the “ Apply” stage.**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685504440344/964d5a8a-59ac-44ad-a100-859d449aee61.png align="center")
    
4. **Click on Build with Parameters** then Select **destroy** and click on **Build**
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685503439948/d747064d-a73a-4602-93de-e24e18683386.png align="center")
    
    The image below shows the resources being destroyed along with confirmation of the instances terminated in AWS.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685504099572/4dcd5f49-5421-4d1e-bf19-4c5761347239.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685504122866/c8216af7-bfc2-4356-805a-b702615ce5f7.png align="center")
