Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ terraform plan
terraform apply
```

> **Project name length limit**: The `project_name` Terraform variable is used as a prefix for AWS resource names. Due to AWS name length limits (e.g., ALB target groups are limited to 32 characters), `project_name` must be **22 characters or fewer for dev** and **21 characters or fewer for prod**. The default `aws-infra-visualizer` (20 chars) fits both. See the [Infrastructure Guide](infrastructure/README.md#project-name-limitations) for details.

See [infrastructure/README.md](infrastructure/README.md) for detailed deployment instructions.

## Versioning
Expand Down
26 changes: 26 additions & 0 deletions infrastructure/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,32 @@ The `secrets` module manages AWS Secrets Manager secrets for sensitive configura

Secrets are injected into ECS task definitions as secret environment variables (resolved at container launch from Secrets Manager ARNs).

## Project Name Limitations

The `project_name` variable is used as a prefix for AWS resource names. Because several AWS services enforce strict name length limits, `project_name` must stay within the bounds below:

| Environment | Max Length | Tightest Constraint |
|-------------|-----------|---------------------|
| **dev** | **22 characters** | ALB target group: `{name}-dev-fe-tg` (32 char limit) |
| **prod** | **21 characters** | ALB target group: `{name}-prod-fe-tg` (32 char limit) |

The default value `aws-infra-visualizer` (20 characters) fits both environments.

**Additional format rules:**
- Lowercase letters, numbers, and hyphens only
- Must not start or end with a hyphen

**Derived resource name limits by AWS service:**

| AWS Service | Name Pattern | Limit | Dev max name | Prod max name |
|-------------|-------------|-------|-------------|---------------|
| ALB Target Group | `{name}-{env}-fe-tg` | 32 | 22 | 21 |
| ALB | `{name}-{env}-alb` | 32 | 24 | 23 |
| S3 Bucket | `{name}-{env}-alb-logs-access-{acct_id}` | 63 | 29 | 28 |
| IAM Role | `{name}-{env}-vpc-flow-logs-role` | 64 | 39 | 38 |

Terraform will reject a `project_name` that exceeds the limit at plan time with a clear error message.

## Prerequisites

1. **AWS CLI** configured with appropriate credentials
Expand Down
12 changes: 11 additions & 1 deletion infrastructure/environments/dev/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@
# -----------------------------------------------------------------------------

variable "project_name" {
description = "Name of the project"
description = "Name of the project (max 22 characters for dev environment)"
type = string
default = "aws-infra-visualizer"

validation {
condition = length(var.project_name) >= 2 && length(var.project_name) <= 22
error_message = "project_name must be between 2 and 22 characters. The dev environment appends suffixes like '-dev-fe-tg' to create AWS resource names, and ALB target group names are limited to 32 characters."
}

validation {
condition = can(regex("^[a-z0-9][a-z0-9-]*[a-z0-9]$", var.project_name))
error_message = "project_name must contain only lowercase letters, numbers, and hyphens, and must not start or end with a hyphen."
}
}

variable "environment" {
Expand Down
12 changes: 11 additions & 1 deletion infrastructure/environments/prod/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@
# -----------------------------------------------------------------------------

variable "project_name" {
description = "Name of the project"
description = "Name of the project (max 21 characters for prod environment)"
type = string
default = "aws-infra-visualizer"

validation {
condition = length(var.project_name) >= 2 && length(var.project_name) <= 21
error_message = "project_name must be between 2 and 21 characters. The prod environment appends suffixes like '-prod-fe-tg' to create AWS resource names, and ALB target group names are limited to 32 characters."
}

validation {
condition = can(regex("^[a-z0-9][a-z0-9-]*[a-z0-9]$", var.project_name))
error_message = "project_name must contain only lowercase letters, numbers, and hyphens, and must not start or end with a hyphen."
}
}

variable "environment" {
Expand Down
30 changes: 27 additions & 3 deletions infrastructure/modules/alb/main.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# =============================================================================

Check warning on line 1 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

terraform "required_version" attribute is required

Check warning on line 1 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

terraform "required_version" attribute is required
# ALB Module
# Creates Application Load Balancer with optional HTTPS
# =============================================================================
Expand All @@ -8,7 +8,7 @@
# -----------------------------------------------------------------------------

data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

Check warning on line 11 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

data "aws_region" "current" is declared but not used

Check warning on line 11 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

data "aws_region" "current" is declared but not used

# ELB service account for access logs (varies by region)
data "aws_elb_service_account" "main" {}
Expand Down Expand Up @@ -91,6 +91,13 @@
tags = merge(var.tags, {
Name = "${var.project_name}-${var.environment}-alb-logs-access"
})

lifecycle {
precondition {
condition = length("${var.project_name}-${var.environment}-alb-logs-access-${data.aws_caller_identity.current.account_id}") <= 63
error_message = "S3 bucket name '${var.project_name}-${var.environment}-alb-logs-access-${data.aws_caller_identity.current.account_id}' exceeds the 63-character AWS limit. Shorten project_name (currently ${length(var.project_name)} characters)."
}
}
}

resource "aws_s3_bucket_versioning" "alb_logs_access_logs" {
Expand Down Expand Up @@ -211,8 +218,8 @@
}

resource "aws_sns_topic_policy" "alb_logs_events" {
count = var.enable_access_logs && var.access_logs_bucket == "" ? 1 : 0
arn = aws_sns_topic.alb_logs_events[0].arn
count = var.enable_access_logs && var.access_logs_bucket == "" ? 1 : 0
arn = aws_sns_topic.alb_logs_events[0].arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
Expand Down Expand Up @@ -296,7 +303,7 @@
# -----------------------------------------------------------------------------

resource "aws_lb" "main" {
name = "${var.project_name}-${var.environment}-alb"
name = "${var.project_name}-${var.environment}-alb"
#trivy:ignore:AWS-0053 -- ALB is intentionally public-facing as the internet entry point for the web application
internal = false
load_balancer_type = "application"
Expand All @@ -318,6 +325,13 @@
tags = merge(var.tags, {
Name = "${var.project_name}-${var.environment}-alb"
})

lifecycle {
precondition {
condition = length("${var.project_name}-${var.environment}-alb") <= 32
error_message = "ALB name '${var.project_name}-${var.environment}-alb' exceeds the 32-character AWS limit. Shorten project_name (currently ${length(var.project_name)} characters)."
}
}
}

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -357,6 +371,11 @@

lifecycle {
create_before_destroy = true

precondition {
condition = length("${var.project_name}-${var.environment}-tg") <= 32
error_message = "Target group name '${var.project_name}-${var.environment}-tg' exceeds the 32-character AWS limit. Shorten project_name (currently ${length(var.project_name)} characters)."
}
}
}

Expand Down Expand Up @@ -390,6 +409,11 @@

lifecycle {
create_before_destroy = true

precondition {
condition = length("${var.project_name}-${var.environment}-fe-tg") <= 32
error_message = "Frontend target group name '${var.project_name}-${var.environment}-fe-tg' exceeds the 32-character AWS limit. Shorten project_name (currently ${length(var.project_name)} characters)."
}
}
}

Expand Down Expand Up @@ -505,7 +529,7 @@
# Route53 Record (optional)
# -----------------------------------------------------------------------------

data "aws_route53_zone" "main" {

Check warning on line 532 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

data "aws_route53_zone" "main" is declared but not used

Check warning on line 532 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

data "aws_route53_zone" "main" is declared but not used
count = var.domain_name != "" && var.route53_zone_id != "" ? 1 : 0

zone_id = var.route53_zone_id
Expand Down Expand Up @@ -542,7 +566,7 @@
ttl = 60
}

resource "aws_acm_certificate_validation" "main" {

Check warning on line 569 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

Missing version constraint for provider "aws" in `required_providers`

Check warning on line 569 in infrastructure/modules/alb/main.tf

View workflow job for this annotation

GitHub Actions / TFLint Analysis

Missing version constraint for provider "aws" in `required_providers`
count = var.domain_name != "" && var.certificate_arn == "" && var.route53_zone_id != "" ? 1 : 0

certificate_arn = aws_acm_certificate.main[0].arn
Expand Down
Loading