Terraform insists on using exclusively US availability zones for AWS VPC

Hey!

I have a relatively simple Terraform project where I want to do the following:

  • Create an ECR repository if it does not already exist.
  • Create a VPC.
  • Create an RDS instance running PostgreSQL 16.
  • Provision an application on AppRunner using my ECR registry.

Here are my files:

terraform.tf

terraform {
  cloud {
    organization = "my_org"

    workspaces {
      name = "my-workspace"
    }
  }
}

providers.tf

provider "aws" {
  region = var.region
}

vpc.tf

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"

  name                 = "my-production-vpc"
  cidr                 = "10.0.0.0/16"
  azs                  = ["eu-west-3a", "eu-west-3b", "eu-west-3c"]
  public_subnets       = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
  enable_dns_hostnames = true
  enable_dns_support   = true
}

resource "aws_db_subnet_group" "my-production-subnet-group" {
  name       = "my-production-subnet-group"
  subnet_ids = module.vpc.public_subnets

  tags = {
    Name = "my-production-subnet-group"
    Project = "my-project"
    Customer = "my-customer"
  }
}

ecr.tf

resource "aws_ecr_repository" "my-backend" {
  name = "my-backend"
  force_delete = false
  image_tag_mutability = "MUTABLE"

    image_scanning_configuration {
        scan_on_push = true
    }

    tags = {
        Name = "my-repository"
        Project = "my-project"
        Customer = "my-customer"
    }

}

rds.tf

resource "aws_db_instance" "my-postgresql" {
  identifier             = "my-postgresql"
  instance_class         = "db.t3.micro"
  allocated_storage      = 5
  engine                 = "postgres"
  engine_version         = "16.2"
  username               = "my_username"
  password               = var.db_password
  db_subnet_group_name   = aws_db_subnet_group.my-production-subnet-group.name
#   vpc_security_group_ids = [aws_security_group.rds.id]
  parameter_group_name   = aws_db_parameter_group.my-postgresql.name
  publicly_accessible    = true
  skip_final_snapshot    = true
}

resource "aws_db_parameter_group" "my-postgresql" {
  name   = "my-postgresql"
  family = "postgres16"

  parameter {
    name  = "log_connections"
    value = "1"
  }
}

apprunner.tf

resource "aws_apprunner_service" "my-backend" {
  service_name = "my-backend"

  source_configuration {
    image_repository {
      image_configuration {
        port = var.node_port
        runtime_environment_secrets = {
            DB_USER = aws_db_instance.my-postgresql.username
            DB_PASSWORD = var.db_password
            DB_HOST = aws_db_instance.my-postgresql.address
            DB_PORT = aws_db_instance.my-postgresql.port
            JWT_SECRET = var.node_jwt_secret
            JWT_REFRESH_SECRET = var.node_jwt_secret
            S3_ACCESS_ID = var.node_aws_access_key_id
            S3_ACCESS_SECRET = var.node_aws_secret_access_key
            ADMIN_USERNAME = var.node_admin_username
            ADMIN_PASSWORD = var.node_admin_password
            MQTT_USERNAME = var.node_mqtt_username
            MQTT_PASSWORD = var.node_mqtt_password
        }

        runtime_environment_variables = {
            JWT_EXPIRE = var.node_jwt_expire
            JWT_REFRESH_EXPIRE = var.node_jwt_expire
            S3_REGION = var.node_aws_region
            S3_BUCKET = var.node_aws_bucket
            ALGO_SERVER_API = var.node_algo_server_address
            RECO_SERVER_API = var.node_reco_server_address
            MQTT_HOST = var.node_mqtt_host
            MQTT_PORT = var.node_mqtt_port
        }
      }
      image_identifier      = "${aws_ecr_repository.my-backend.repository_url}:latest"
      image_repository_type = "ECR"
    }
    auto_deployments_enabled = false
  }

    health_check_configuration {
      path = "/elb-status"
    }

  tags = {
    Name = "my-backend-apprunner-service"
  }
}

When I run terraform plan, Terraform is happy and tells me it is ready to proceed.
It properly displays changes even in the Cloud UI.

When I run terraform apply, it proceeds with the apply and asks me to confirm in the Cloud UI.
When I do, I get the following obscure error:

╷
│ Error: creating EC2 Subnet: InvalidParameterValue: Value (eu-west-3b) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: us-west-1a, us-west-1c.
│       status code: 400, request id: 6ec008ba-f766-43bc-8847-a7e1ca8339ca
│ 
│   with module.vpc.aws_subnet.public[1],
│   on .terraform/modules/vpc/main.tf line 97, in resource "aws_subnet" "public":
│   97: resource "aws_subnet" "public" {
│ 
╵
╷
│ Error: creating EC2 Subnet: InvalidParameterValue: Value (eu-west-3a) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: us-west-1a, us-west-1c.
│       status code: 400, request id: 96051538-5906-49a7-b558-d5bc72fe9f35
│ 
│   with module.vpc.aws_subnet.public[0],
│   on .terraform/modules/vpc/main.tf line 97, in resource "aws_subnet" "public":
│   97: resource "aws_subnet" "public" {
│ 
╵
╷
│ Error: creating EC2 Subnet: InvalidParameterValue: Value (eu-west-3c) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: us-west-1a, us-west-1c.
│       status code: 400, request id: 6f24a9c0-b8f8-4742-b445-7bc0392106e7
│ 
│   with module.vpc.aws_subnet.public[2],
│   on .terraform/modules/vpc/main.tf line 97, in resource "aws_subnet" "public":
│   97: resource "aws_subnet" "public" {
│ 
╵
Operation failed: failed running terraform apply (exit 1)

I can also notice that Terraform polluted my AWS account with a VPC and subnets in inappropriate regions. I am on eu-west-3 and it is hellbent on using us-west-1 and nothing else.
What’s most surprising, is that I previously ran this configuration successfully. I must have changed something that broke it but the error message is so strange that I can’t understand what’s going on.

Could you help me fix this, please?

Hi @SmashingQuasar,

What is var.region set to?