DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

MASTER PROJECT: Terraform State Management, Security & Team Collaboration

In production, companies usually have multiple Git repositories.
Platform (or Cloud) engineers create shared infrastructure repos, and DevOps or application teams have their own repos that consume those shared resources.

This is industry standard.


🧠 Real Production Model (MOST COMMON)

Typical setup:

GitHub Organization
β”‚
β”œβ”€β”€ terraform-platform-networking   (Platform team)
β”‚
β”œβ”€β”€ terraform-platform-security     (Platform team)
β”‚
β”œβ”€β”€ terraform-app-orders            (App / DevOps team)
β”‚
β”œβ”€β”€ terraform-app-payments          (App / DevOps team)
β”‚
└── terraform-app-analytics         (App / DevOps team)
Enter fullscreen mode Exit fullscreen mode

πŸ‘₯ Who owns what?

🟦 Platform / Cloud Engineering Team

Owns:

  • VPC
  • Subnets
  • Routing
  • Shared IAM
  • Shared EKS clusters
  • Shared logging / monitoring
  • Terraform backends (S3 + DynamoDB)

Examples:

  • terraform-platform-networking
  • terraform-platform-security

🟩 DevOps / Application Teams

Own:

  • EC2 / ECS / EKS workloads
  • RDS / DynamoDB
  • App-specific IAM roles
  • Autoscaling / ALB

Examples:

  • terraform-app-orders
  • terraform-app-payments

They do NOT create VPCs β€” they consume them.


πŸ” How teams collaborate (KEY CONCEPT)

They collaborate via Remote State Data Source:

data "terraform_remote_state" "network" {
  backend = "s3"

  config = {
    bucket = "terraform-state-company-prod"
    key    = "networking/terraform.tfstate"
    region = "us-east-1"
  }
}
Enter fullscreen mode Exit fullscreen mode

βœ” No hardcoding
βœ” Loose coupling
βœ” Safe separation
βœ” Production-grade


πŸ” Why state is centralized

Component Owner
S3 state bucket Platform team
DynamoDB locking Platform team
Backend config All teams
State files Isolated per repo

🚫 Why NOT one repo in production?

Reason Explanation
Access control Not all teams should touch networking
Blast radius Mistake in one repo β‰  break everything
Team autonomy Teams deploy independently
CI/CD Separate pipelines
Scaling Hundreds of services

Single repo is used for:

  • Learning Terraform concepts
  • Seeing full picture
  • Exam preparation
  • Student labs

Multi-repo is used for:

  • Real production
  • Enterprise environments
  • Interviews

πŸ‘‰ Both are correct depending on context.


🎯 Interview-Perfect Answer (MEMORIZE)

In production, we typically use multiple Terraform repositories. Platform engineers manage shared infrastructure like networking and backends, while DevOps or application teams have separate repositories for their services. Teams collaborate using remote state stored in S3 with DynamoDB locking.


🧠 One-Sentence Summary (VERY STRONG)

Platform teams build the foundation, application teams build on top of it.


βœ… Certificate Alignment (Terraform Associate)

The exam expects you to know:

  • Multiple repos exist
  • Remote state enables collaboration
  • State must be secured
  • Teams are isolated

What this project covers

βœ” Git team collaboration
βœ” Why Terraform state must NOT be in Git
βœ” .gitignore
βœ” Terraform backend
βœ” S3 backend
βœ” DynamoDB state locking
βœ” Terraform state management
βœ” Remote state data source
βœ” Cross-project collaboration
βœ” Terraform import
βœ” Interview & certification alignment


Real-World Scenario

A company has multiple teams:

  • Networking team β†’ creates VPC
  • Application team β†’ creates EC2
  • Teams collaborate using remote state
  • State is stored securely in S3
  • Git is used safely by multiple engineers

High-Level Architecture

GitHub (Code Only)
      |
Terraform
      |
S3 (State Files)
      |
DynamoDB (Locking)
      |
Networking Project (VPC)
      |
Application Project (EC2)
Enter fullscreen mode Exit fullscreen mode

1️⃣ Create ONE parent directory

mkdir terraform-team-collaboration
cd terraform-team-collaboration
Enter fullscreen mode Exit fullscreen mode

FINAL PROJECT STRUCTURE

terraform-team-collaboration/
β”‚
β”œβ”€β”€ terraform-networking/
β”‚   β”œβ”€β”€ backend.tf
β”‚   β”œβ”€β”€ provider.tf
β”‚   β”œβ”€β”€ vpc.tf
β”‚   β”œβ”€β”€ subnet.tf
β”‚   └── outputs.tf
β”‚
└── terraform-application/
    β”œβ”€β”€ backend.tf
    β”œβ”€β”€ provider.tf
    β”œβ”€β”€ data.tf
    └── ec2.tf
Enter fullscreen mode Exit fullscreen mode

PART 1 β€” Networking Project (Platform Team)

terraform-networking/backend.tf

terraform {
  backend "s3" {
    bucket         = "terraform-state-company-prod"
    key            = "networking/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}
Enter fullscreen mode Exit fullscreen mode

terraform-networking/provider.tf

provider "aws" {
  region = "us-east-1"
}
Enter fullscreen mode Exit fullscreen mode

terraform-networking/vpc.tf

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "prod-vpc"
  }
}
Enter fullscreen mode Exit fullscreen mode

terraform-networking/subnet.tf

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true
}
Enter fullscreen mode Exit fullscreen mode

terraform-networking/outputs.tf

output "vpc_id" {
  value = aws_vpc.main.id
}

output "subnet_id" {
  value = aws_subnet.public.id
}
Enter fullscreen mode Exit fullscreen mode

β–Ά Run networking

cd terraform-networking
terraform init
terraform apply
Enter fullscreen mode Exit fullscreen mode

PART 2 β€” Application Project (DevOps Team)

terraform-application/backend.tf

terraform {
  backend "s3" {
    bucket         = "terraform-state-company-prod"
    key            = "application/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}
Enter fullscreen mode Exit fullscreen mode

terraform-application/provider.tf

provider "aws" {
  region = "us-east-1"
}
Enter fullscreen mode Exit fullscreen mode

terraform-application/data.tf

data "terraform_remote_state" "network" {
  backend = "s3"

  config = {
    bucket = "terraform-state-company-prod"
    key    = "networking/terraform.tfstate"
    region = "us-east-1"
  }
}
Enter fullscreen mode Exit fullscreen mode

terraform-application/ec2.tf

resource "aws_instance" "app" {
  ami           = "ami-0fc5d935ebf8bc3bc"
  instance_type = "t2.micro"

  subnet_id = data.terraform_remote_state.network.outputs.subnet_id

  tags = {
    Name = "app-server"
  }
}
Enter fullscreen mode Exit fullscreen mode

β–Ά Run application

cd ../terraform-application
terraform init
terraform apply
Enter fullscreen mode Exit fullscreen mode

PART 3 β€” State Locking (DynamoDB)

  • Two engineers run terraform apply
  • Second engineer gets state lock error
  • Infrastructure is protected

PART 4 β€” Terraform Import (Overview)

terraform import aws_instance.app i-0abcd1234
terraform plan
Enter fullscreen mode Exit fullscreen mode

βœ” Existing infra now managed
βœ” No recreation


PART 5 β€” Terraform State Management

terraform state list
terraform state show aws_vpc.main
terraform state rm aws_instance.app
terraform refresh
Enter fullscreen mode Exit fullscreen mode

Top comments (0)