Aws_instance with specific AZ

I have created my VPC and Subnets using the terraform-aws-vpc Terraform module.

My goal is to specify the availability_zone under the aws_instance resource, and it should automatically pick up the necessary subnet_id.

The data source is as follows:

data "aws_subnet_ids" "database" {
  vpc_id = data.terraform_remote_state.network.outputs.vpc_id

  filter {
    name   = "tag:Name"
    values = ["*-db-*"]
  }

  filter {
    name   = "tag:Environment"
    values = [local.workspace["environment"]]
  }

  filter {
    name   = "tag:Terraform"
    values = ["true"]
  }
}

The issue is that tolist(data.aws_subnet_ids.database.ids)[0] will always return a random subnet_id.

How can I achieve that?

Looks like this worked:

 db_subnets                      = data.terraform_remote_state.network.outputs.database_subnets
resource "aws_instance" "slave01" {
  subnet_id                   = element(var.db_subnets, 0)

resource "aws_instance" "slave02" {
  subnet_id                   = element(var.db_subnets, 1)

resource "aws_instance" "slave03" {
  subnet_id                   = element(var.db_subnets, 2)

But is there a better way to achieve this?

Hi @lpossamai,

I believe the aws_instance resource type is designed so that you provide it with subnet_id and it will automatically infer availability zone, rather than the other way around. Therefore I think your goal here is to, in essence, build a mapping table from availability zone to subnet id so that you can then specify the subnet id for the availability zone you intend to use.

aws_subnet_ids only returns ids, and so to find the availability zone for each one will require an additional lookup using for_each with the aws_subnet data source:

data "aws_subnet_ids" "database" {
 # (all of the same settings you already have)
}

data "aws_subnet" "database" {
  for_each = data.aws_subnet_ids.database.ids

  id = each.value
}

local {
  az_subnet_ids = {
    for subnet in aws_subnet.database :
    subnet.availability_zone => subnet.id
  }
}

local.az_subnet_ids will then be a mapping from availability zone name to subnet id, and so you could populate your aws_instance resource like this, if you intend to use e.g. us-east-1a:

resource "aws_instance" "example" {
  # ...
  subnet_id = local.az_subnet_ids["us-east-1a"]
}
1 Like