Configure a Remote Backend with AWS S3 and DynamoDB state locking in Terraform
Tags: terraform, s3, dynamodb
Published: 2023-10-04 13:23:17

In this article, I am going to show you how to set up Terraform to use remote backend state. At first, We will set up our S3 bucket where we want to store our state file, and then set up a locking table in DynamoDB. Afterwards, We will create our remote backend configuration and deploy our resources. In the end, We will check to make sure our state file was written to our S3 bucket successfully.

# What is Terraform backend?

**Terraform Backend** is a configuration option in Terraform that allows you to store and manage the state of your infrastructure in a remote or local location. The backend is responsible for storing the state file and providing an interface for reading and writing state data. When you run Terraform, it checks the backend to see if there are any changes to the state file, and if there are, it applies those changes to your infrastructure.    


When using Terraform, it’s important to configure a backend to store the state of your infrastructure. The state file contains a representation of your resources and their current configuration, which allows Terraform to make changes to your infrastructure in a safe and predictable way. Without a backend, you would need to manage the state file manually, which can be error-prone and lead to inconsistencies.

### Remote Backend

A remote backend is a type of Terraform backend that stores the state file in a remote location, such as a cloud object storage service or a database. Remote backends provide several benefits, such as enabling collaboration between team members, versioning state files, and providing a history of changes which can help with troubleshooting and auditing, and remote state locking which prevent conflicts and ensure consistency. There are several remote backend providers available, such as Amazon S3, Azure Storage, Google Cloud Storage, and HashiCorp Consul.


Please visit my **[GitHub Repository for Terraform articles](https://github.com/awsmine/Terraform_projects)** on various topics being updated on constant basis.

_**Let’s get started!**_


# Objectives:

**1.** Login to AWS Management Console

**2.** Environment Setup - Create S3 bucket and a DynamoDB table

**3.** Create infrastructure for resources block

**4.** Under ***`terraform_files`*** resources directory - Create 4 files - ***`backend.tf`***, ***`main.tf`***, ***`variables.tf`***, and ***`outputs.tf`***.

**5.** Initialize Terraform

**6.** To generate the action plans

**7.** Create all the resources declared in main.tf configuration file

**8.** Validate all resources created
 


# Pre-requisites:
- AWS user account with admin access, not a root account.
- Cloud9 IDE with AWS CLI.

# Resources Used:
***[Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs).***
***[Terraform documentation for AMI](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami).***
***[What is Amazon S3?](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html).***
***[What is Amazon DynamoDB?](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html)***

# Steps for implementation to this project:

## 1. Login to AWS Management Console
- Make sure you're in the N. Virginia (us-east-1) region

## 2. Environment Setup - Create S3 bucket and a DynamoDB table

***Create S3 bucket***

- 1.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qn1og8y3jc2tun6u5f8.png)

- 2.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bw2j7ahcsivjs61ep2jw.png)


- 3. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q5utm44orzar801jqvpn.png)


- 4.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6clokemap2afqsmsxs7x.png)

- create bucket

- bucket name - revbucket123456

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/al96iem1zbu4dxh10fgu.png)


***Create DynamoDB table***

create a table for Terraform state locking with a simple hash LockID key and one string attribute

- 1.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9hlpiiuwefo1jj7fake.png)

- take all the defaults

- Create table

- Dynamo DB Name - revdynamodb

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ll351liwo1a4180jhv8.png)


## 3. Create infrastructure for resources block

- Let’s create the following organizational structure as shown below.


## 4. Under ***`terraform_files`*** resources directory - Create 4 files - ***`backend.tf`***, ***`main.tf`***, ***`variables.tf`***, and ***`outputs.tf`***.

- Create a directory - ***`terraform-files`***

- Create 4 files - ***`backend.tf`***, ***`main.tf`***, ***`variables.tf`***, and ***`outputs.tf`***. 

- 1. backend.tf

- **S3 Backend**: Amazon S3 is a popular cloud object storage service that can be used as a backend for storing Terraform state files.

```
terraform {
  backend "s3"{
    bucket                 = "<YOUR_BUCKET_NAME>"
    region                 = "<YOUR_BUCKET_REGION>"
    key                    = "backend.tfstate"
    dynamodb_table         = "<YOUR_DYNAMODB_TABLE_NAME>"
  }
```
- substitute your bucket name and dynamodb table name

```
terraform {
  backend "s3"{
    bucket                 = "revbucket123456"
    region                 = "us-east-1"
    key                    = "backend.tfstate"
    dynamodb_table         = "revdynamodb"
  }
}
```

- 2. ***`main.tf`***

```
terraform {

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

  required_version = ">= 0.14.9"
}

provider "aws" {
  profile = "default"
  region  = var.region
}

data "aws_ami" "linux" {
   most_recent = true
   owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_instance" "app_server" {
  ami           = data.aws_ami.linux.id
  instance_type = var.instance_type
  availability_zone = var.az_1a

  tags = {
    Name = "var.instance_name"
  }
}
```

- 3. ***`variables.tf`***

```
variable "region" {
  description = "region"
  type        = string
  default     = "us-east-1"
}

variable "az_1a" {
  description = "availability zone 1"
  type        = string
  default     = "us-east-1a"
}

variable "instance_type" {
  description = "Value of the Name tag for the EC2 instance type"
  type        = string
  default     = "t2.micro"
}


variable "instance_name" {
  description = "Value of the Name tag for the EC2 instance"
  type        = string
  default     = "MyInstance"
}
```

- 4. ***`outputs.tf`*** 

```
output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.app_server.id
}

output "instance_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_instance.app_server.public_ip
}

output "instance_name" {
  description = "Name of the EC2 instance"
  value       = aws_instance.app_server.tags.Name
}
```
## 5. Initialize Terraform
***`cd terraform-files`***

- ***`terraform status`*** 
```
terraform version
```
Since the Terraform version is returned, you have validated that the Terraform binary is installed and functioning properly.

#### Note:
If you receive a notification that there is a newer version of Terraform available, you can ignore it — it will run safely with the version installed on the VM.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r18cvp2sburm2km1phqw.png)



- ***`terraform fmt`*** 

to format all of your resources

```
terraform fmt
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f76s032m0eld1xuvm6zr.png)


- ***`terraform init`*** will check for all the plugin dependencies and download them if required, this will be used for creating a deployment plan.

```
terraform init
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18i0u84duqznrofgz4yv.png)



- Validate your Terraform syntax

```
terraform validate
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zphfvpw99a3hkkwq00u2.png)



## 6. To generate the action plans

```
terraform plan
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0g9dklx5sw3ovcw6lfkq.png)





## 7. Create all the resources declared in main.tf configuration file

#### Note: 
The --auto-approve flag will prevent Terraform from prompting you to enter yes explicitly before it deploys the code.

```
terraform apply --auto-approve
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03ij88e67t0eh8dkvwv1.png)

## 8. Validate all resources created


- 1. AMI Name

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n916fg0mzdjo11m6mr6w.png)


- 2. instance_name, instance_id, and instance_ip

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10ikem0ne8dpoz4e0rwh.png)


- 3. availability zone

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8fybrntrspjs6l6zqqt.png)


- 4. s3 bucket

Navigate back to your S3 bucket in the AWS Management Console.
Click on your bucket and there should be a backend.tfstate file.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z8o0nmum0hy4p81u5shb.png)

- At the same time if we open our terraform.tfstate locally on our machine, we will see that the file is empty.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e26h78n77uqfx73skmfd.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/foayamh94rlixqxw4vuq.png)

- we have successfully built our Terraform backend where instead of using our terraform.tfstate file that we have locally, we are using ***backend.tfstate*** file remotely from our S3 bucket,

- 5. dynamodb table


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qctw1n8585x9qisrfx3v.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4uqjevj8ir9vh5sdzgp.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqtci509eypzh7gb45uf.png)

# Cleanup

- terraform destroy

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8y8knc8si2nb7im2yaof.png)


# What we have done so far

- We have successfully created an S3 bucket, DynamoDB lock table, add backend configuration, and then deployed our environment. 
- Then we confirmed by looking in our S3 bucket if our state file was created.