Module Reference Syntax
Git Source with Version
Always use version tags to ensure reproducible deployments:
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=v1.0.0"
# Module inputs...
}
Branch Reference
For testing or development:
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=main"
# Module inputs...
}
Avoid using branch references in production. Always pin to specific version tags.
Commit SHA Reference
For maximum stability:
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=abc123def456"
# Module inputs...
}
Common Patterns
Multi-Environment Setup
Organize modules across environments:
terraform/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ └── production/
│ ├── main.tf
│ ├── variables.tf
│ └── terraform.tfvars
└── modules/
└── (local modules if needed)
Example dev environment:
# environments/dev/main.tf
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=v1.0.0"
vpc_name = "${var.environment}-vpc"
vpc_cidr = "10.0.0.0/16"
aws_region = var.aws_region
availability_zones = var.availability_zones
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnet_cidrs = ["10.0.11.0/24", "10.0.12.0/24"]
# Dev: Single NAT for cost savings
enable_nat_gateway = true
single_nat_gateway = true
tags = var.tags
}
Example production environment:
# environments/production/main.tf
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=v1.0.0"
vpc_name = "${var.environment}-vpc"
vpc_cidr = "10.0.0.0/16"
aws_region = var.aws_region
availability_zones = var.availability_zones
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
private_subnet_cidrs = ["10.0.11.0/24", "10.0.12.0/24", "10.0.13.0/24"]
# Production: NAT per AZ for HA
enable_nat_gateway = true
single_nat_gateway = false
enable_s3_endpoint = true
enable_dynamodb_endpoint = true
enable_flow_logs = true
tags = var.tags
}
Module Composition
Build complex infrastructure by composing modules:
# Network layer
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=v1.0.0"
# VPC configuration
}
# Compute layer
module "eks" {
source = "[email protected]:opsnorth/terraform-modules.git//eks?ref=v1.0.0"
cluster_name = "app-cluster"
private_subnet_ids = module.vpc.private_subnet_ids
}
# Data layer
module "rds" {
source = "[email protected]:opsnorth/terraform-modules.git//rds?ref=v1.0.0"
identifier = "app-db"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
allowed_security_group_ids = [module.eks.cluster_security_group_id]
}
# Secrets layer
module "vault" {
source = "[email protected]:opsnorth/terraform-modules.git//vault?ref=v1.0.0"
cluster_name = module.eks.cluster_id
oidc_provider_arn = module.eks.oidc_provider_arn
oidc_provider_url = module.eks.oidc_provider_url
}
Using Module Outputs
Pass outputs between modules:
# VPC module outputs
output "vpc_outputs" {
value = {
vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnet_ids
public_subnet_ids = module.vpc.public_subnet_ids
}
}
# Reference in other modules
module "eks" {
source = "[email protected]:opsnorth/terraform-modules.git//eks?ref=v1.0.0"
private_subnet_ids = module.vpc.private_subnet_ids
}
# Reference in resources
resource "aws_security_group" "app" {
vpc_id = module.vpc.vpc_id
# Security group rules...
}
Variable Management
Store environment-specific values:
# environments/production/terraform.tfvars
environment = "production"
aws_region = "us-east-1"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_cidr = "10.0.0.0/16"
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
private_subnet_cidrs = ["10.0.11.0/24", "10.0.12.0/24", "10.0.13.0/24"]
eks_version = "1.34"
eks_node_instance_types = ["m5.large"]
eks_node_desired_size = 3
rds_instance_class = "db.t3.medium"
rds_allocated_storage = 100
tags = {
Environment = "production"
Team = "platform"
ManagedBy = "terraform"
}
Using Variable Files
Load different configurations:
# Development
terraform apply -var-file="environments/dev/terraform.tfvars"
# Production
terraform apply -var-file="environments/production/terraform.tfvars"
Environment Variables
Use TF_VAR prefix:
export TF_VAR_environment="production"
export TF_VAR_aws_region="us-east-1"
terraform apply
State Management
Remote State Backend
Always use remote state for team collaboration:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "production/vpc/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
State Isolation
Isolate state by layer or component:
state/
├── production/
│ ├── network/terraform.tfstate # VPC
│ ├── compute/terraform.tfstate # EKS
│ ├── data/terraform.tfstate # RDS
│ └── secrets/terraform.tfstate # Vault
└── dev/
└── ...
Remote State Data Source
Reference outputs from other state files:
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "production/network/terraform.tfstate"
region = "us-east-1"
}
}
module "eks" {
source = "[email protected]:opsnorth/terraform-modules.git//eks?ref=v1.0.0"
private_subnet_ids = data.terraform_remote_state.network.outputs.private_subnet_ids
}
Tagging Strategy
locals {
common_tags = {
Environment = var.environment
Team = "platform"
ManagedBy = "terraform"
CostCenter = "engineering"
Project = "shipyard"
}
}
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=v1.0.0"
tags = local.common_tags
}
module "eks" {
source = "[email protected]:opsnorth/terraform-modules.git//eks?ref=v1.0.0"
tags = local.common_tags
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Terraform = "true"
Environment = var.environment
Project = "shipyard"
}
}
}
Testing Modules
Plan Before Apply
Always review changes:
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan
Target Specific Modules
Test individual modules:
# Plan only VPC changes
terraform plan -target=module.vpc
# Apply only EKS changes
terraform apply -target=module.eks
Using -target should be temporary. Always run a full plan/apply afterward to ensure consistency.
Validate Configuration
# Check syntax
terraform validate
# Format code
terraform fmt -recursive
# Validate with variables
terraform validate -var-file="terraform.tfvars"
Module Updates
Upgrading Module Versions
-
Review changelog:
git log v1.0.0..v1.1.0 -- vpc/
-
Update source version:
module "vpc" {
source = "[email protected]:opsnorth/terraform-modules.git//vpc?ref=v1.1.0"
}
-
Re-initialize:
-
Plan and review:
-
Apply changes:
Pinning Versions in CI/CD
# .github/workflows/terraform.yml
name: Terraform
on:
push:
branches: [main]
pull_request:
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- name: Terraform Init
run: terraform init
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Plan
run: terraform plan -no-color
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve
Best Practices
Version Pinning
Always pin module versions using Git tags. Never use branches in production.
State Locking
Use DynamoDB for state locking to prevent concurrent modifications.
Environment Isolation
Separate state files and AWS accounts per environment.
Least Privilege IAM
Grant minimum required permissions. Use IAM roles over access keys.
Module Documentation
Document your usage patterns and custom configurations.
Change Review
Always review terraform plan output before applying.
Troubleshooting
Module Not Found
Error:
Solution:
# Ensure Git SSH access is configured
ssh -T [email protected]
# Re-initialize with upgrade flag
terraform init -upgrade
State Lock Errors
Error:
Error: Error acquiring the state lock
Solution:
# List locks
aws dynamodb scan --table-name terraform-state-lock
# Force unlock (use with caution)
terraform force-unlock <LOCK_ID>
Module Output Not Available
Error:
Error: Unsupported attribute
Solution:
Check if the output exists in the module:
terraform output -module=vpc
VPC Module
Complete VPC infrastructure
EKS Module
Kubernetes cluster setup
State Module
Remote state backend
Infrastructure Guide
Complete deployment workflow