A Production Ready EKS Deployment with IaC & GitOps - Part 3 - Backend & Provider Configuration

In this part of the series, we will provision an AWS EKS Cluster using Terraform. To maintain infrastructure as code (IaC), we are using Terraform to define and manage the EKS cluster and related resources in an automated and repeatable manner. Before diving into the actual cluster provisioning, let’s go through the file structure and the Terraform backend & provider configurations that will be used throughout this guide. Terraform File Structure Our initial Terraform setup is structured as follows: ├── terraform.tf ├── main.tf ├── variables.tf We will add more terraform files here for other components such as vpc, eks etc.. terraform.tf: The Foundation The terraform.tf file serves as the foundational configuration file for our Terraform project. It contains two critical sections: Backend Configuration backend "s3" { bucket = "opsninja-tf-state-prod" region = "us-east-1" key = "opsninja/v1/terraform-prod.tfstate" dynamodb_table = "opsninja-tf-state-prod" } In Part 2 of this article series we provisioned the S3 bucket and the DynamoDB table. You should use the same table name and bucket name here. This configuration specifies where Terraform should store its state file. Using an S3 bucket with DynamoDB for state locking is a common practice in production environments, ensuring safe concurrent access to the infrastructure state. Here's what each property does: bucket - The name of the S3 bucket where Terraform will store the state file region - The AWS region where the S3 bucket is located key - The path within the S3 bucket where the state file will be stored. In your case: opsninja/v1/terraform-prod.tfstate represents the full path to the state file dynamodb_table - The name of the DynamoDB table used for state locking. This prevents multiple users from modifying the infrastructure at the same time This configuration ensures your Terraform state is stored remotely and can be accessed securely by team members while preventing concurrent modifications. Provider Requirements required_providers { aws = { source = "hashicorp/aws" version = "5.76.0" } # Additional providers... } This section defines all the providers needed for our infrastructure and their specific versions, ensuring consistency across team members and environments. main.tf: Provider Configuration The main.tf file focuses on configuring the providers declared in terraform.tf. It contains the specific settings and authentication methods for each provider. Key aspects include: AWS Provider Configuration provider "aws" { region = var.region profile = var.profile default_tags { tags = { application_name = var.app application_env = var.env terraform = "true" managed_by = "Terraform" } } } This configuration sets up AWS-specific settings, including default tags that will be applied to all resources. Kubernetes-Related Providers The file also includes configurations for kubectl, kubernetes, and helm providers, all necessary for managing Kubernetes resources. variables.tf: Variable Definitions The variables.tf file defines all the variables used across our Terraform configuration: variable "app" { description = "Application name" type = string default = "opsninja" } This file makes our configuration more flexible and reusable across different environments. Now that we have a clear idea about what our project structure is, you can add the following files to your terraform project. terraform.tf terraform { backend "s3"{ bucket = "opsninja-tf-state-prod" region = "us-east-1" key = "opsninja/v1/terraform-prod.tfstate" dynamodb_table = "opsninja-tf-state-prod" } required_providers { aws = { source = "hashicorp/aws" version = "5.76.0" } random = { source = "hashicorp/random" version = "~> 3.5.1" } tls = { source = "hashicorp/tls" version = "~> 4.0.4" } cloudinit = { source = "hashicorp/cloudinit" version = "~> 2.3.2" } helm = { source = "hashicorp/helm" version = "~> 2.11.0" } kubectl = { source = "alekc/kubectl" version = ">= 2.0.0" } } required_version = "~> 1.3" } main.tf provider "aws" { region = var.region profile = var.profile default_tags { tags = { application_name = var.app application_env = var.env terraform = "true" managed_by = "Terraform" } } } provider "kubectl" { apply_retry_count = 15 host = module.eks.cluster_endpoint cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) load_config_file = false exec {

Feb 2, 2025 - 11:45
 0
A Production Ready EKS Deployment with IaC & GitOps - Part 3 - Backend & Provider Configuration

In this part of the series, we will provision an AWS EKS Cluster using Terraform. To maintain infrastructure as code (IaC), we are using Terraform to define and manage the EKS cluster and related resources in an automated and repeatable manner.

Before diving into the actual cluster provisioning, let’s go through the file structure and the Terraform backend & provider configurations that will be used throughout this guide.

Terraform File Structure

Our initial Terraform setup is structured as follows:

├── terraform.tf
├── main.tf
├── variables.tf

We will add more terraform files here for other components such as vpc, eks etc..

terraform.tf: The Foundation

The terraform.tf file serves as the foundational configuration file for our Terraform project. It contains two critical sections:

  1. Backend Configuration
backend "s3" {
    bucket         = "opsninja-tf-state-prod"
    region         = "us-east-1"
    key            = "opsninja/v1/terraform-prod.tfstate"
    dynamodb_table = "opsninja-tf-state-prod"
}

In Part 2 of this article series we provisioned the S3 bucket and the DynamoDB table. You should use the same table name and bucket name here.

This configuration specifies where Terraform should store its state file. Using an S3 bucket with DynamoDB for state locking is a common practice in production environments, ensuring safe concurrent access to the infrastructure state.

Here's what each property does:

  1. bucket - The name of the S3 bucket where Terraform will store the state file

  2. region - The AWS region where the S3 bucket is located

  3. key - The path within the S3 bucket where the state file will be stored. In your case:

    • opsninja/v1/terraform-prod.tfstate represents the full path to the state file
  4. dynamodb_table - The name of the DynamoDB table used for state locking. This prevents multiple users from modifying the infrastructure at the same time

This configuration ensures your Terraform state is stored remotely and can be accessed securely by team members while preventing concurrent modifications.

  1. Provider Requirements
required_providers {
    aws = {
        source  = "hashicorp/aws"
        version = "5.76.0"
    }
    # Additional providers...
}

This section defines all the providers needed for our infrastructure and their specific versions, ensuring consistency across team members and environments.

main.tf: Provider Configuration

The main.tf file focuses on configuring the providers declared in terraform.tf. It contains the specific settings and authentication methods for each provider. Key aspects include:

  1. AWS Provider Configuration
provider "aws" {
    region = var.region
    profile = var.profile
    default_tags {
        tags = {
            application_name = var.app
            application_env = var.env
            terraform = "true"
            managed_by = "Terraform"
        }
    }
}

This configuration sets up AWS-specific settings, including default tags that will be applied to all resources.

  1. Kubernetes-Related Providers The file also includes configurations for kubectl, kubernetes, and helm providers, all necessary for managing Kubernetes resources.

variables.tf: Variable Definitions

The variables.tf file defines all the variables used across our Terraform configuration:

variable "app" {
    description = "Application name"
    type        = string
    default     = "opsninja"
}

This file makes our configuration more flexible and reusable across different environments.

Now that we have a clear idea about what our project structure is, you can add the following files to your terraform project.

terraform.tf

terraform {

  backend "s3"{
    bucket                 = "opsninja-tf-state-prod"
    region                 = "us-east-1"
    key                    = "opsninja/v1/terraform-prod.tfstate"
    dynamodb_table         = "opsninja-tf-state-prod"
  }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.76.0"
    }

    random = {
      source  = "hashicorp/random"
      version = "~> 3.5.1"
    }

    tls = {
      source  = "hashicorp/tls"
      version = "~> 4.0.4"
    }

    cloudinit = {
      source  = "hashicorp/cloudinit"
      version = "~> 2.3.2"
    }

    helm = {
      source  = "hashicorp/helm"
      version = "~> 2.11.0"
    }

    kubectl = {
      source  = "alekc/kubectl"
      version = ">= 2.0.0"
    }
  }

  required_version = "~> 1.3"

}

main.tf

provider "aws" {
  region = var.region
  profile = var.profile
  default_tags {
    tags = {
      application_name = var.app
      application_env = var.env
      terraform = "true"
      managed_by = "Terraform"
    }
  }
}

provider "kubectl" {
  apply_retry_count      = 15
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  load_config_file       = false

  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args        = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
  }
}

provider "kubernetes" {
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
  }
}

provider "helm" {
  kubernetes {
    host                   = module.eks.cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      args        = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
      command     = "aws"
    }
  }
}

variables.tf

##### Globals #####

variable "app" {
  description = "Application name. Used as a prefix to most resources created (Ex: Policies)"
  type        = string
  default     = "opsninja"
}

variable "env" {
  description = "Environment. Used to prefix most resources to identify resources environment-wise"
  type        = string
  default     = "prod"
}

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

variable "profile" {
  description = "AWS Profile. Used to provision resources"
  type        = string
  default     = "terraform"
}