Skip to content

Implement Terragrunt for DRY Infrastructure Code #7

@jsandov

Description

@jsandov

Current Issues

  • Duplicate provider configurations
  • Repeated backend configurations
  • Common variables redefined across environments
  • Similar module configurations across staging/prod
  • Hardcoded values that should be parameterized

Proposed Solution: Terragrunt Implementation

1. Suggested Directory Structure

.
├── config.hcl               # Core configuration values
├── terragrunt.hcl          # Root configuration
├── terraform               # Terraform modules
│   └── website               
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── environments           # Environment configurations
    ├── _env              # Common configurations
    │   ├── provider.hcl      
    │   └── common.hcl    
    ├── staging
    │   └── terragrunt.hcl    
    └── prod
        └── terragrunt.hcl    

2. Core Configuration

# config.hcl
locals {
  account_name = get_env("ACCOUNT_NAME", "jdnguyen")
  tld         = get_env("DOMAIN_TLD", "tech")
  
  # Derived values
  project     = local.account_name
  base_domain = "${local.account_name}.${local.tld}"
}

3. Common Configuration

# environments/_env/common.hcl
include "config" {
  path = find_in_parent_folders("config.hcl")
}

locals {
  project     = include.config.locals.project
  base_domain = include.config.locals.base_domain
}

4. Environment Configuration

# environments/staging/terragrunt.hcl
include "root" {
  path = find_in_parent_folders()
}

include "common" {
  path = find_in_parent_folders("common.hcl")
}

locals {
  environment = "staging"
  
  # Derived variables
  domain_prefix = local.environment
  full_domain   = "${local.domain_prefix}.${local.base_domain}"
}

inputs = {
  domain_name        = local.full_domain
  environment        = local.environment
  aws_s3_bucket_name = local.full_domain
  logs_bucket_name   = "logs.${local.full_domain}"
  project_name       = local.project
  resource_prefix    = "${local.project}-${local.environment}"
}

5. Root Configuration

# terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket         = "${local.project}-terraform-state"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-locks"
    encrypt        = true
  }
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = {
      Environment = "${local.environment}"
      Project     = "${local.project}"
    }
  }
}
EOF
}

Benefits

  • DRY configuration across environments
  • Centralized core configuration values
  • Environment variable overrides
  • Consistent naming patterns
  • Simplified environment promotion
  • Reduced configuration errors
  • Easy to replicate for other projects/accounts

Implementation Steps

  1. Install Terragrunt
  2. Create config.hcl with core values
  3. Set up common configurations
  4. Migrate environment-specific configs
  5. Update deployment process
  6. Test in staging environment

Dependencies

  • Terraform file structure refactor
  • Sensitive value management

Resources

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions