Getting Started with AWS Infrastructure as Code: A Terraform Guide
Tags: aws, terraform, infrastructureascode, devops
Published: 2023-09-26 14:27:10

If you're looking to start working with AWS and dive into the world of Terraform, this article is your comprehensive guide. We'll walk you through setting up your Terraform project to work seamlessly with AWS and share essential best practices for a smooth transition.

**Section 1: Getting Started with AWS**
1.1 [Create Your AWS Account](https://aws.amazon.com/getting-started/guides/setup-environment/)
We begin by creating your AWS account, which is your gateway to AWS services. Follow our step-by-step guide to set up your AWS account quickly and efficiently.

1.2 [Configure Users](https://docs.aws.amazon.com/SetUp/latest/UserGuide/setup-acctrequirements.html)
Learn how to configure user accounts in AWS, ensuring proper access control for your team members

1.3 [Set Up the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
Discover how to install and configure the AWS CLI (Command Line Interface) for managing AWS resources from your local environment.

We have to Configure AWS CLI credentials. In this article I will use [Long-term credentials](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html) option. But it would be better if you use AWS IAM Identity Center (SSO). This is more secure. However you have to use your root user credentials or an IAM user with sufficient permissions to enable AWS SSO to setup this.

Let’s start with Long-term credentials options first.
Go to the AWS Portal, choice user account then Security Credentials

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

Scrolling to the Access Key

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvxyacyffmhf1kusoir7.png)
Click to the Create access key button

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqutpte7b10utrekgsd7.png)
Choice the first option (Command line Interface – CLI)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19kkgtzw4yqq9b4m3gpq.png)
Tick to the confirmation checkbox and Click to the Next button.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzh0647kvjjrw2y11r91.png)
Because the Secret key only available for the first time so please note that we should copy the value of secret to some where or download csv file before closing the tab.

**Section 2: AWS CLI and Terraform**
2.1 Installing AWS CLI
Get hands-on with the AWS CLI installation process. Check your installation with aws --version.

2.2 Configure AWS CLI Credentials
Explore different options for configuring AWS CLI credentials, including long-term credentials and more secure AWS IAM Identity Center (SSO) configurations.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f7g5zebwfdmi6jg25u2u.png)
Filling the value corresponding to aws configure command
Now, we are going to create a resource group, that helps us to manage resources better via Tags management.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tflyhilzag3c5sh3qq5c.png)
It will show you the result
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sa6p8pqpbghdyayaijuy.png)

**Section 3: Setting Up Remote State Storage**
3.1 Using AWS S3 for Remote State
Secure Remote Backends: Store the Terraform state in secure remote backends such as AWS S3.

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

In AWS, the Services should be enabled tagging the tag. That can help us to manage services better. It is also the tagged the service into the resource group

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jyaru1gei8sc67r7uqyd.png)
After creating the S3 bucket, we can see it on the AWS portal.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rujywzsbcoc9b9o01uw6.png)
Go to the Resource group and check. Awesome, they look as expected.

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

**Section 4: DynamoDB for State Locking**
4.1 Understanding State Locking
As you know that, using DynamoDB for state locking enhances the reliability and scalability of Terraform workflows, especially in environments with multiple users or automation processes working concurrently. It helps ensure that infrastructure changes are applied safely and consistently while preventing conflicts and data corruption.
Terraform uses state files to keep track of resource information and dependencies. When multiple users or automation processes work with Terraform concurrently, there's a risk of conflicts and data corruption. DynamoDB provides built-in concurrency control mechanisms, ensuring that only one process can acquire a lock for a particular state file at a given time. This prevents conflicts and ensures consistent state management.
Terraform provides built-in support for using DynamoDB as a backend for state locking. Configuring Terraform to use DynamoDB is straightforward, and it seamlessly integrates with the Terraform CLI.
So, we are going to create Dynamo table

4.2 Creating a DynamoDB Table
Step-by-step instructions on creating a DynamoDB table to serve as the state locking mechanism

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hh5erhodx0fwt08lc20s.png)
It should be also tagged then it will show in the resource group

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

Awesome, now let’s start write Terraform code

**Section 5: Writing Terraform Modules**
5.1 Terraform Configuration
Setting up your Terraform project with the required providers, including AWS and optional Kubernetes configurations.

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

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.16.2"#"~> 4.16"
    }

    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = ">= 2.16.1"
    }
  }

  required_version = ">= 1.2.0"
}
provider "aws" {
  region = "us-east-1"
}
terraform {
  backend "s3" {
    bucket         = "s3-terraform-state-use1"
    key            = "terraform.tfstate"   # State file name
    region         = "us-east-1"           # Use your desired AWS region
    encrypt        = true                  # Optionally, enable server-side encryption
    dynamodb_table = "ddb-statelock-table" # Optional, use a DynamoDB table for state locking
  }
}
```

5.2 Creating a Resource Group
Learn how to define a Terraform resource group to organize AWS resources based on tags.

```
resource "aws_resourcegroups_group" "rg" {
  name = join("-", [var.resource_type, var.application, var.application_environment, var.region_short])

  resource_query {
    query = <<JSON
    {
      "ResourceTypeFilters": [
        "AWS::AllSupported"
      ],
      "TagFilters": [
        {
          "Key": "Environment",
          "Values": ["${var.workload_environments}"]
        },
        {
          "Key": "ApplicationEnvironment",
          "Values": ["${var.application_environment}"]          
        },
        {
          "Key": "OpsTeam",
          "Values": ["${var.ops_team}"]
        },
        {
          "Key": "Owner",
          "Values": ["${var.owner}"]
        },{
          "Key": "Criticality",
          "Values": ["${var.business_criticality}"]          
        },{
          "Key": "OpsCommitment",
          "Values": ["${var.ops_commitment}"]          
        },{
          "Key": "ApplicationName",
          "Values": ["${upper(var.application)}"]
        }
      ]
    }
  JSON
  }
}
```

5.3 Configuring S3 Buckets
Create S3 buckets for your infrastructure components, making them public and configuring website settings.

```
resource "aws_s3_bucket" "s3" {
  bucket = join("-", [var.resource_type, var.application, var.application_environment, var.region_short]) #"s3-static-website-bucket"                                                                               # Make the bucket public

  tags = {
    Environment            = var.workload_environments
    ApplicationEnvironment = var.application_environment
    OpsTeam                = var.ops_team
    Owner                  = var.owner
    Criticality            = var.business_criticality
    OpsCommitment          = var.ops_commitment
    ApplicationName        = upper(var.application)
  }
  depends_on = [ var.resource_group]
}

resource "aws_s3_bucket_website_configuration" "s3_website" {
  bucket = aws_s3_bucket.s3.id

  index_document {
    suffix = "index.html"
  }

  error_document {
    key = "error.html"
  }

  routing_rule {
    condition {
      key_prefix_equals = "docs/"
    }
    redirect {
      replace_key_prefix_with = "documents/"
    }
  }

  depends_on = [ var.resource_group]
}
```


**Section 6: Module Integration in Main Configuration**
6.1 Integrating the Resource Group Module
See how to call and configure the resource group module in your 

```
main configuration.
module "rg" {
  for_each                = var.application_environments
  source                  = "./modules/resource-group"
  resource_type           = "rg"
  application             = var.organization
  workload_environments   = var.workload_environments
  application_environment = each.value #var.application_environment# 
  region                  = var.region
  region_short            = var.region_short
  ops_team                = var.ops_team
  owner                   = var.owner
  business_criticality    = var.business_criticality
  ops_commitment          = var.ops_commitment
}
```
6.2 Integrating the S3 Bucket Module
Integrate the S3 bucket module into your main configuration and link it to your resource group.

```
module "s3" {
  for_each                = var.application_environments
  source                  = "./modules/bucket"
  resource_type           = "s3"
  application             = var.organization
  workload_environments   = var.workload_environments
  application_environment = each.value #var.application_environment#
  region                  = var.region
  region_short            = var.region_short
  ops_team                = var.ops_team
  owner                   = var.owner
  business_criticality    = var.business_criticality
  ops_commitment          = var.ops_commitment
  resource_group          = module.rg[each.value]
  resource_group_id       = module.rg[each.value].resource_group_id
  resource_group_arn      = module.rg[each.value].resource_group_arn
}
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hea2tq5e0vj8r22ce49m.png)

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

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

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

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

Source code: https://github.com/namphuongtran/aws-infrastructure
By the end of this article, you'll have a firm grasp of setting up AWS and Terraform for your infrastructure needs. The included best practices will ensure you're working efficiently and effectively in your new AWS environment.