# Deploying Workloads on Oracle Cloud Infrastructure (OCI) via Terraform - PART 1

# What is Terraform?

Terraform is an** infrastructure as code (IAC) ** tool that lets you define both cloud & on-prem resources in human-readable configuration files that you can version, reuse, and share. The concept of Terraform is to allow users to provision huge & complex infrastructure & workloads in an automated fashion by defining the parameters in a **".tf" file,** instead of manually provisioning them which takes alot of effort & time.

Terraform creates & manages resources on cloud platforms **(such as OCI)** & other services through their application programming interfaces (APIs). Providers enable Terraform to work with virtually any platform or service with an accessible API.


![intro-terraform-apis.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1646669347233/lHvBkVY5F.png) Image credits: terraform.io

Terraform execution involves three stages:

![image-79.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1646669375667/1L8wsRoL7.png) Image credits: freecodecamp.org

<ul>
<li>**Write -** This is where you write a “.tf” file to define the resources that you're provisioning to a provider (Eg: AWS, Azure, OCI, GCP, etc.)</li>
<li>**Plan -** Terraform will create an execution plan outlining the infrastructure that you want to create, update or destroy based on your environment & the “.tf” file that you've defined</li>
<li>**Apply -** This is when Terraform executes the plan based on the parameters defined in your “.tf” file</li>
</ul>


![intro-terraform-workflow.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1646669500940/EyOUpyIqH.png)  Image credits: terraform.io

# Working with Terraform on OCI

In this section, I'll be documenting the process of configuring Terraform & the creation of resources on OCI.

## Setting Up Terraform

### Terraform Installation

Firstly, we need to install Terraform in our environment. I have a Linux (Ubuntu) Windows Subsystem for Linux (WSL) on my Windows 10 machine which allows me to run a Linux environment directly on Windows without needing a virtual machine or dual boot setup. To learn more on WSL, refer here: [WSL](https://docs.microsoft.com/en-us/windows/wsl/about)

For Ubuntu/Debian, do the following:

<br>
```
$ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -

$ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"

$ sudo apt-get update && sudo apt-get install terraform

``` 
<br>
For CentOS/RHEL, do the following:

```
$ sudo yum install -y yum-utils

$ sudo yum-config-manager --add-repo 

$ sudo yum -y install terraform

``` 
#### Creating RSA Keys

Once Terraform installed, we need to generate RSA keys to allow API signing into the OCI tenant.

On your terminal, create an .oci directory in the root folder.

```
$ mkdir $HOME/.oci
``` 

Generate a 2048-bit private key in PEM format.

```
$ openssl genrsa -out $HOME/.oci/<your-rsa-key-name>.pem 2048
``` 

Modify the permission of your PEM file (private key) so that only you can read & write the file.

```
$ chmod 600 $HOME/.oci/<your-rsa-key-name>.pem
``` 

Generate a public key (also in PEM format).

```
$ openssl rsa -pubout -in $HOME/.oci/<your-rsa-key-name>.pem -out $HOME/.oci/<your-rsa-key-name>_public.pem
``` 

View your public key & copy it's contents. Include ‘BEGIN PUBLIC KEY’ & ‘END PUBLIC KEY’.

```
$ cat $HOME/.oci/<your-rsa-key-name>_public.pem
``` 


```
-----BEGIN PUBLIC KEY-----

xxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxx

-----END PUBLIC KEY-----

``` 

Add the public key to your user account on the OCI portal.

![Profile.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1646670201542/ixYNf8HgG.PNG)
<ul>
<li>Click your profile</li>
<li>Click **API Keys**</li>
<li>Click **Add Public Key**</li>
<li>Select **Paste Public Keys**</li>
<li>Paste your public key into the field, include the lines with 'BEGIN PUBLIC KEY' & 'END PUBLIC KEY'</li>
<li>Click **Add**</li>
</ul>

### Define Policies on OCI

You need to define policies to provide permissions for your user(s) & group(s) to read & manage resources in your tenancy.


1. Navigate to **Identity & Security > Users**. Create your user (Eg: terraformuser)
2. Navigate to **Identity & Security > Groups**. Create your group (Eg: terraformgroup) & add your user to the group
3. Navigate to **Identity & Security > Policies**
4. Choose a Compartment if you have one or select the root compartment for now (We'll be creating a Compartment later as well, in Part 2)
5. Click **Create Policy** & click **Show manual editor**
6. Paste the following policy & click **Create**

```
allow group <the-group-your-username-belongs> to read all-resources in tenancy
``` 
### Gather Required Information

We will need to collect the following information to authenticate our Terraform scripts. Collect them from here:

![Profile1.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1646671393176/q_IKE4jgw.PNG)


1. **Tenancy OCID:** <tenancy-ocid>Below your profile, click Tenance:<your-tenancy> & copy the OCID
2. **User OCID:** <user-ocid>Click on your profile & copy the OCID
3. **Fingerprint:** <fingerprint>In your profile, click API Keys & copy the fingerprint associated with your RSA public key. The format is xx:xx:xx:…..:xx
4. **Region:** <region-identifier>From the top navigation bar, locate your region & find your region's <region-identifier> from [Regions & Availability Domains](https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm). Eg: us-ashburn-1

Also, collect the following information from your environment (Linux, in my case).

1. **Private Key Path:** <rsa-private-key-path>Eg: $HOME/.oci/<your-rsa-key-name>.pem

### Creating Your Scripts
Next, we need to create scripts (.tf files) to allow Terraform to authenticate & fetch data from the OCI tenant.

#### Add API Key-Based Authentication

In your $HOME directory (your root directory), create a directory called ‘tf-provider’ & change to that directory.


```
$ mkdir tf-provider

$ cd tf-provider

``` 

Create a file called ‘provider.tf’ using your preferred text editor (vi/vim/nano).
Add the following code into your file. Replace the field brackets with the information gathered earlier. Retain the quotations around the string values. Save the file.

```
provider "oci" {

tenancy_ocid = "<tenancy-ocid>"

user_ocid = "<user-ocid>"

private_key_path = "<rsa-private-key-path>"

fingerprint = "<fingerprint>"

region = "<region-identifier>"

}

``` 
#### Add Data Source
In this section, you create a .tf file to fetch a list of availability domains in your tenancy.

1. In the tf-provider directory, create a file called 'availability-domains.tf'
2. Add the following code & save.

```
data “oci_identity_availability_domains” “ads” {

compartment_id = “<tenancy-ocid>”

}

``` 

### Run Your Scripts
In this section, we run the Terraform script by the workflow, **Initialize > Plan > Apply**

#### Initialize

1. Initialize a working directory in the tf-provider directory.

```
$ terraform init
``` 
Example output:

```
Initializing the backend...

Initializing provider plugins...

- Finding latest version of hashicorp/oci...

- Installing hashicorp/oci vx.x.x...

- Installed hashicorp/oci vx.x.x (signed by HashiCorp)

Terraform has been successfully initialized!

``` 
#### Plan

1. Now, we create an execution plan to check whether the changes shown in the plan match our expectations, without changing the real resource.


```
$ terraform plan
``` 
Example output:

```
Changes to Outputs:

  + all-availability-domains-in-your-tenancy = [

      + {

          + compartment_id = "ocid1.tenancy.oc1..xxx"

          + id             = "ocid1.availabilitydomain.xxx"

          + name           = "QnsC:US-ASHBURN-AD-1"

        },

      + {

          + compartment_id = "ocid1.tenancy.oc1..xxx"

          + id             = "ocid1.availabilitydomain.xxx"

          + name           = "QnsC:US-ASHBURN-AD-2"

        },

      + {

          + compartment_id = "ocid1.tenancy.oc1..xxx"

          + id             = "ocid1.availabilitydomain.xxx"

          + name           = "QnsC:US-ASHBURN-AD-3"

        },

    ]

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

``` 
#### Apply
Now, we run the Terraform scripts. Enter ‘yes’ when prompted.


```
$ terraform apply
``` 

Example output:

```
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

all-availability-domains-in-your-tenancy = tolist([

  {

    "compartment_id" = "ocid1.tenancy.xxx"

    "id" = "ocid1.availabilitydomain.xxx"

    "name" = "QnsC:US-ASHBURN-AD-1"

  },

  {

    "compartment_id" = "ocid1.tenancy.xxx"

    "id" = "ocid1.availabilitydomain.xxx"

    "name" = "QnsC:US-ASHBURN-AD-2"

  },

  {

    "compartment_id" = "ocid1.tenancy.xxx"

    "id" = "ocid1.availabilitydomain.xxx"

    "name" = "QnsC:US-ASHBURN-AD-3"

  },

])

``` 
We have successfully authenticated our OCI tenant with our Terraform provider scripts.

# Summary
To summarize Part 1, we have done the following:
<ul>
<li>Installed Terraform</li>
<li>Created .tf scripts</li>
<li>Executed the workflows, Initialize > Plan > Apply</li>
<li>Authenticated our OCI tenant with the Terraform provider scripts</li>
</ul>

In [Part 2](https://vicknesh.cloud/deploying-workloads-on-oracle-compute-infrastructure-oci-via-terraform-part-2), I will document steps to provision resources (compartments, compute instances, etc.) in our OCI tenant via Terraform scripts.

I hope this has been beneficial to you. I'll see you in [Part 2](https://vicknesh.cloud/deploying-workloads-on-oracle-compute-infrastructure-oci-via-terraform-part-2). Stay tuned & have a nice day.

