# Terraform AWS Knowledge

## Module Design

Split modules by domain (network, database, application layer). Do not create generic utility modules.


### Inter-Module Dependencies

Pass dependencies explicitly via outputs→inputs. Avoid implicit references (using `data` sources to look up other module resources).

```hcl
# Example: Explicit dependency
module "database" {
  source     = "../../modules/database"
  vpc_id     = module.network.vpc_id
  subnet_ids = module.network.private_subnet_ids
}

# Avoid: Implicit dependency
module "database" {
  source = "../../modules/database"
  # vpc_id not passed; module uses data "aws_vpc" internally
}
```

### Identification Variable Passthrough

Pass identification variables (environment, service name) explicitly from root to child modules. Do not rely on globals or hardcoding.

```hcl
# Example: Explicit passthrough
module "database" {
  environment      = var.environment
  service          = var.service
  application_name = var.application_name
}
```

## Resource Naming Convention

Compute `name_prefix` in `locals` and apply consistently to all resources. Append resource-specific suffixes.


```hcl
# Example: Unified with name_prefix
locals {
  name_prefix = "${var.environment}-${var.service}-${var.application_name}"
}

resource "aws_ecs_cluster" "main" {
  name = "${local.name_prefix}-cluster"
}

# Avoid: Inconsistent naming
resource "aws_ecs_cluster" "main" {
  name = "${var.environment}-app-cluster"
}
```

### Character Limit Handling

AWS services have name character limits. Use shortened forms when approaching limits.

| Service | Limit | Example |
|---------|-------|---------|
| Target Group | 32 chars | `${var.environment}-${var.service}-backend-tg` |
| Lambda Function | 64 chars | Full prefix fits |
| S3 Bucket | 63 chars | Full prefix fits |

## Tagging Strategy

Use provider `default_tags` for common tags. No duplicate tagging on individual resources.


```hcl
# Example: Centralized, individual gets Name only
provider "aws" {
  default_tags {
    tags = {
      Environment = var.environment
      ManagedBy   = "Terraform"
    }
  }
}

resource "aws_instance" "main" {
  tags = {
    Name = "${local.name_prefix}-instance"
  }
}

# Avoid: Duplicates default_tags
resource "aws_instance" "main" {
  tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
    Name        = "${local.name_prefix}-instance"
  }
}
```

## File Organization Patterns

### Environment Directory Structure

Separate environments into directories, each with independent state management.

```
environments/
├── production/
│   ├── terraform.tf       # Version constraints
│   ├── providers.tf       # Provider config (default_tags)
│   ├── backend.tf         # S3 backend
│   ├── variables.tf       # Environment variables
│   ├── main.tf            # Module invocations
│   └── outputs.tf         # Outputs
└── staging/
    └── ...
```

### Module File Structure

| File | Contents |
|------|----------|
| `main.tf` | `locals` and `data` sources only |
| `variables.tf` | Input variable definitions only (no resources) |
| `outputs.tf` | Output definitions only (no resources) |
| `{resource_type}.tf` | One file per resource category |
| `templates/` | user_data scripts and other templates |

## Security Best Practices

### EC2 Instance Security

| Setting | Recommended | Reason |
|---------|-------------|--------|
| `http_tokens` | `"required"` | Enforce IMDSv2 (SSRF prevention) |
| `http_put_response_hop_limit` | `1` | Prevent container escapes |
| `root_block_device.encrypted` | `true` | Data-at-rest encryption |

### S3 Bucket Security

Block all public access with all four settings. Use OAC (Origin Access Control) for CloudFront distributions.

```hcl
# Example: Complete block
resource "aws_s3_bucket_public_access_block" "this" {
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
```

### IAM Design

| Pattern | Recommendation |
|---------|---------------|
| Per-service role separation | Separate execution role (for ECS Agent) and task role (for app) |
| CI/CD authentication | OIDC federation (avoid long-lived credentials) |
| Policy scope | Specify resource ARNs explicitly (avoid `"*"`) |

### Secret Management

| Method | Usage |
|--------|-------|
| SSM Parameter Store (SecureString) | Manage as a parameter |
| Secrets Manager | Use when rotation is required |
| Direct in `.tfvars` | Check gitignore and the injection boundary |
| Hardcoded in `.tf` files | Keep out of the secret-management path |

Set SSM Parameter initial values to placeholders and use `lifecycle { ignore_changes = [value] }` to manage outside Terraform.

## Cost Optimization Patterns

Document trade-offs with inline comments for cost-impacting choices.

| Choice | Cost Effect | Trade-off |
|--------|------------|-----------|
| NAT Instance vs NAT Gateway | Instance ~$3-4/mo vs Gateway ~$32/mo | Lower availability and throughput |
| Public subnet placement | No VPC Endpoints needed | Weaker network isolation |
| EC2 + EBS vs RDS | EC2 ~$15-20/mo vs RDS ~$50+/mo | Higher operational burden |

```hcl
# Example: Trade-off documented
# Using t3.nano instead of NAT Gateway (~$3-4/mo vs ~$32/mo)
# Trade-off: single-AZ availability, throughput limits
resource "aws_instance" "nat" {
  instance_type = "t3.nano"
}
```

## Lifecycle Rule Usage

| Rule | Purpose | Target |
|------|---------|--------|
| `prevent_destroy` | Prevent accidental deletion | Databases, EBS volumes |
| `ignore_changes` | Allow external changes | `desired_count` (Auto Scaling), SSM `value` |
| `create_before_destroy` | Prevent downtime | Load balancers, security groups |

```hcl
# Example: Prevent accidental database deletion
resource "aws_instance" "database" {
  lifecycle {
    prevent_destroy = true
  }
}

# Example: Let Auto Scaling manage desired_count
resource "aws_ecs_service" "main" {
  lifecycle {
    ignore_changes = [desired_count]
  }
}
```

## Version Management

| Setting | Recommendation |
|---------|---------------|
| `required_version` | `">= 1.5.0"` or higher (`default_tags` support) |
| Provider version | Pin minor version with `~>` (e.g., `~> 5.80`) |
| State locking | `use_lockfile = true` required |
