Code Monkey home page Code Monkey logo

terraform-aws-route53's Introduction

Route53 Terraform module

Terraform module which creates Route53 resources.

SWUbanner

There are independent submodules:

Usage

Create Route53 zones and records

module "zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 3.0"

  zones = {
    "terraform-aws-modules-example.com" = {
      comment = "terraform-aws-modules-examples.com (production)"
      tags = {
        env = "production"
      }
    }

    "myapp.com" = {
      comment = "myapp.com"
    }
  }

  tags = {
    ManagedBy = "Terraform"
  }
}

module "records" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "~> 3.0"

  zone_name = keys(module.zones.route53_zone_zone_id)[0]

  records = [
    {
      name    = "apigateway1"
      type    = "A"
      alias   = {
        name    = "d-10qxlbvagl.execute-api.eu-west-1.amazonaws.com"
        zone_id = "ZLY8HYME6SFAD"
      }
    },
    {
      name    = ""
      type    = "A"
      ttl     = 3600
      records = [
        "10.10.10.10",
      ]
    },
  ]

  depends_on = [module.zones]
}

Examples

Authors

Module is maintained by Anton Babenko with help from these awesome contributors.

License

Apache 2 Licensed. See LICENSE for full details.

Additional information for users from Russia and Belarus

terraform-aws-route53's People

Contributors

antonbabenko avatar atikhono avatar betajobot avatar bhutkovskyysos avatar bobsut avatar bryantbiggs avatar chas0amx avatar dayned89 avatar dev-slatto avatar dmitriy-lukyanchikov avatar docmarten avatar eagleusb avatar egarbi avatar flora-five avatar hawkesn avatar nshenry03 avatar renebarbosafl avatar semantic-release-bot avatar sfstar avatar slavasubotskiy avatar takumin avatar wolffberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

terraform-aws-route53's Issues

Unknown output type for module zones causing TFLint to crash

Description

we are using the terraform sub-module zone and it's working just fine. In the recent update to tflint v0.47.0 we got a crash issue and it's due to an Unknown output type for the output route53_zone_zone_arn

Further details can be found in this reported tflint issue: terraform-linters/tflint#1831

  • βœ‹ I have searched the open/closed issues and my issue is not listed.

Versions

  • Module version: v2.10.2
  • Terraform version: 1.5.2
  • AWS Provider version: 5.14.0

Avoid records re-creation imposed by data.aws_route53_zone.this

Using depends_on in terraform configuration that source records module, will propagate depends_on to data source used to get zone_id by zone_name. This impose records recreation like seen in AWS Route 53 record recreation

citation: This forces the data source to in a sense be marked as something that can't be known until apply time. As a result, Terraform must plan on the ZoneID changing

This is the code identified in record module:

data "aws_route53_zone" "this" {
  count = var.create && (var.zone_id != null || var.zone_name != null) ? 1 : 0

  zone_id      = var.zone_id
  name         = var.zone_name
  private_zone = var.private_zone
}

This happen expecially if we use a map of "zones" =>{ record = [{...}]} with multiple zones as keys. Removing one zone in the variable will produce a re-creation of all records in all other zones.

Unfortunately in some configuration we tried introducing implicit dependency like this below but this doesn't works (not really clear why):

resource "aws_route53_zone" "route53_phz" {
...
}

module "records" {
  source = "../../modules/records"

  zone_name = aws_route53_zone.route53_phz.name
...

Describe the solution you'd like.

Unkown.

I ask you how to call your records module so it can be dependent by zone non created by your zone module without using depends_on and without create resources in sequence to avoid error:

β”‚ Error: no matching Route53Zone found
β”‚   with ...data.aws_route53_zone.this[0],
β”‚   on .../modules/records/main.tf line 10, in data "aws_route53_zone" "this":
β”‚   10: data "aws_route53_zone" "this" {

Describe alternatives you've considered.

  • 2 step apply (first) create zone (second) create records
  • depends_on but this impose uselessly record re-creation (sometime many records - aws is slow on records management)

Additional context

Proposal: To delete data resource from records module

What i propose:
to delete data resource, and pass zone_id through global variable,

Why i want to do this:
for example i want to create infrastructure use with terragrunt
example of the structure:

|_domain.example
   |_zone
   |_records

Where record depends on zone
And when i try to run plan or apply i get error

β•·
β”‚ Error: no matching Route53Zone found
β”‚ 
β”‚   with data.aws_route53_zone.this[0],
β”‚   on main.tf line 23, in data "aws_route53_zone" "this":
β”‚   23: data "aws_route53_zone" "this" {
β”‚ 

How do you think, maybe better way it is to pass zone_id to this module through variable?

I have not a lot of experience in this, but it is just proposal.

Issue with aws_route53_zone lookup

Description

When performing a Terraform plan using this module for a Route 53 record with changes, the data source wants to perform changes. This causes the record to want to destroy and recreate itself.

# module.route53.data.aws_route53_zone.this[0] will be read during apply
  # (config refers to values not yet known)
 <= data "aws_route53_zone" "this"  {
      ~ arn                        = "arn:aws:route53:::hostedzone/Z0000000000000" -> (known after apply)
      ~ caller_reference           = "terraform-20200402162825661200000001" -> (known after apply)
      ~ comment                    = "Private Hosted Zone for my.domain.int" -> (known after apply)
      ~ id                         = "Z0000000000000" -> (known after apply)
      + linked_service_description = (known after apply)
      + linked_service_principal   = (known after apply)
      ~ name                       = "my.domain.int" -> (known after apply)
      ~ name_servers               = [
          - "ns-0.awsdns-00.com.",
          - "ns-1024.awsdns-00.org.",
          - "ns-1536.awsdns-00.co.uk.",
          - "ns-512.awsdns-00.net.",
        ] -> (known after apply)
      ~ resource_record_set_count  = 11 -> (known after apply)
      ~ tags                       = {
          - "Benefit"             = "Sometext"
          - "Cost_Centre"         = "Sometext"
          - "Description"         = ""
          - "Name"                = "my.domain.int"
          - "Owner"               = "Sometext"
          - "Project"             = "Sometext"
          - "Source_Account"      = ""
          - "Source_Account_Type" = ""
        } -> (known after apply)
      + vpc_id                     = (known after apply)
        # (2 unchanged attributes hidden)
    }

  # module.route53.aws_route53_record.this["my CNAME"] must be replaced
-/+ resource "aws_route53_record" "this" {
      + allow_overwrite = false
      ~ fqdn            = "my.domain.int" -> (known after apply)
      ~ id              = "Z0000000000000_my.domain.int_CNAME" -> (known after apply)
      ~ name            = "my.domain.int" -> (known after apply) # forces replacement
        # (4 unchanged attributes hidden)
    }



If the below line

name                             = each.value.name != "" ? (lookup(each.value, "full_name_override", false) ? each.value.name : "${each.value.name}.${data.aws_route53_zone.this[0].name}") : data.aws_route53_zone.this[0].name

Is changed with

name                             = each.value.name != "" ? (lookup(each.value, "full_name_override", false) ? each.value.name : "${each.value.name}.my.domain.int") : data.aws_route53_zone.this[0].name

The issue with the record wanting to destroy and recreate itself disappears. This because the name field is known after apply in the data lookup.

~ name                       = "my.domain.int" -> (known after apply)

I have tried to think of a way to fix this but can't come up with a nice way without requiring zone_name to be required as an input. This actually looks like it could be an issue with the TF provider.

If your request is for a new feature, please use the Feature request template.

  • βœ‹ I have searched the open/closed issues and my issue is not listed.

⚠️ Note

Before you submit an issue, please perform the following first:

  1. Remove the local .terraform directory (! ONLY if state is stored remotely, which hopefully you are following that best practice!): rm -rf .terraform/
  2. Re-initialize the project root to pull down modules: terraform init
  3. Re-attempt your terraform plan or apply and check if the issue still persists

Versions

  • Module version [2.10.1]:

  • Terraform version:
    1.0.2

  • Provider version(s):
    hashicorp/aws v4.22.0

Reproduction Code [Required]

module "route53" {
  source = "[email protected]:terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=v2.10.1"

  zone_id = local.hosted_zones[var.stage]
  private_zone = true

  records = [
    {
      name    = "${var.environment}-${var.service_name}"
      type    = var.record_type
      records = ["${module.create-windows-fsx.dns_name[0]}"]
      ttl     = var.record_ttl
    }
  ]

  depends_on = [
    module.create-windows-fsx.dns_name
  ]
}

Steps to reproduce the behavior:

No

Yes

Terraform init

Make the simplest change to a resource.

Terraform plan

Expected behavior

Route53 record resource not to be destroyed and recreated.

Actual behavior

Route53 record resource is destroyed and recreated.

Terminal Output Screenshot(s)

Haven't included as it reveals sensitive information.

Additional context

Zones outputs are not easily consumable, they are not primitives but objects.

Description

When the Zones subpart is used as a module, it returns non-primitive outputs that are not easily consumable by other modules - they need to be transformed first to get a distilled value.
I cannot find any justification by myself to provide objects in outputs that are perfect to return primitive values like string or array and where their names suggest one can expect a primitive values there.

To get the route53_zone_name value I needed to use:

values(dependency.route53_public_zone.outputs.route53_zone_name)[0]

Instead of:

dependency.route53_public_zone.outputs.route53_zone_name

Which introduces unnecessary complications to the code and is not a common outputs usage - I have never met complex outputs for simple things like this before.

  • βœ‹ I have searched the open/closed issues and my issue is not listed.

Versions

  • Module version [Required]: 2.10.2

  • Terraform version: Terraform v1.3.9

  • Provider version(s): + provider registry.terraform.io/hashicorp/aws v5.8.0

Reproduction Code [Required]

include "root" {
  path = find_in_parent_folders()
}

terraform {
  source = "tfr:///terraform-aws-modules/route53/aws//modules/zones?version=2.10.2"
}

inputs = {
  # AWS provider settings
  aws_role_arn = "my.role.arn"
  aws_region   = "eu-central-1"

  zones = {
    "my.example.com" = {
      comment = "my.example.com (internal)"
    }
  }

}

Steps to reproduce the behavior:

  1. Use zones module in one place.
  2. Try to consume outputs in records module in another place (basically any module that could use e.g. zone_name)

Expected behavior

Outputs look like this:

route53_zone_name = "my.example.com"
route53_zone_name_servers = [
    "ns-1.awsdns-2.org",
    "ns-3.awsdns-4.co.uk",
    "ns-5.awsdns-6.com",
    "ns-7.awsdns-8.net",
  ]
route53_zone_zone_arn = "arn:aws:route53:::hostedzone/IDOFTHEZONE"
route53_zone_zone_id = "IDOFTHEZONE"

Actual behavior

Outputs look like this:

route53_zone_name = {
  "my.example.com" = "my.example.com"
}
route53_zone_name_servers = {
  "my.example.com" = tolist([
    "ns-1.awsdns-2.org",
    "ns-3.awsdns-4.co.uk",
    "ns-5.awsdns-6.com",
    "ns-7.awsdns-8.net",
  ])
}
route53_zone_zone_arn = {
  "my.example.com" = "arn:aws:route53:::hostedzone/IDOFTHEZONE"
}
route53_zone_zone_id = {
  "my.example.com" = "IDOFTHEZONE"
}

Additional context

I use it with Terragrunt, but that shouldn't change much to the initial problem I think.
I might try to prepare PR with fix if you are OK with that.

New terraform version does not allow zone_id and zone_name to be used together

Description

It seems that somewhere between terraform vesion 1.2.3 and 1.3.4 TF no longer allows zone_id and zone_name to be used together for some reason.

This means that the records data block on line 10 is failing

Error: zone_id and name arguments can't be used together
β”‚
β”‚   with module.route53_records["domain.com"].data.aws_route53_zone.this[0],
β”‚   on .terraform/modules/route53_records/modules/records/main.tf line 10, in data "aws_route53_zone" "this":
β”‚   10: data "aws_route53_zone" "this" {
  • βœ‹ I have searched the open/closed issues and my issue is not listed.

Versions

  • Module version [Required]:

  • Terraform version: 1.3.4

  • Provider version(s): provider registry.terraform.io/hashicorp/aws v4.39.0

Reproduction Code [Required]

Steps to reproduce the behavior:

Are you using workspaces? Yes
Have you cleared the local cache (see Notice section above)? Yes
List steps in order that led up to the issue you encountered Upgraded to terraform 1.3.4

Expected behavior

$ tfenv use 1.2.3
$ terraform import module.route53_records[\"domain.com\"].aws_route53_record.this[\"\ NS\"] Z035010000000LTCJGV2E_domain.com_NS
Acquiring state lock. This may take a few moments...

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

Actual behavior

$ tfenv use 1.3.4
$ terraform import module.route53_records[\"domain.com\"].aws_route53_record.this[\"\ NS\"] Z035010000000LTCJGV2E_domain.com_NS
Acquiring state lock. This may take a few moments...
β•·
β”‚ Error: zone_id and name arguments can't be used together
β”‚
β”‚   with module.route53_records["domain.com"].data.aws_route53_zone.this[0],
β”‚   on .terraform/modules/route53_records/modules/records/main.tf line 10, in data "aws_route53_zone" "this":
β”‚   10: data "aws_route53_zone" "this" {
β”‚

Unable to pass 2 different zone_ids (private and public) in a single module call

Description

Please provide a clear and concise description of the issue you are encountering, and a reproduction of your configuration (see the examples/* directory for references that you can copy+paste and tailor to match your configs if you are unable to copy your exact configuration). The reproduction MUST be executable by running terraform init && terraform apply without any further changes.

If your request is for a new feature, please use the Feature request template.

  • [ yes] βœ‹ I have searched the open/closed issues and my issue is not listed.

⚠️ Note

Before you submit an issue, please perform the following first:

  1. Remove the local .terraform directory (! ONLY if state is stored remotely, which hopefully you are following that best practice!): rm -rf .terraform/
  2. Re-initialize the project root to pull down modules: terraform init
  3. Re-attempt your terraform plan or apply and check if the issue still persists

Versions

  • Module version [Required]:

  • Terraform version:
    Terraform v1.1.9

  • Provider version(s):
    Terraform v1.1.9
    on linux_amd64 + provider registry.terraform.io/hashicorp/aws v4.25.0

Reproduction Code [Required]

module "records" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "~> 2.0"

  zone_id = "<zone-id-1>"

  records = [
    {
      name    = "example-test-1"
      type    = "CNAME"
      ttl     = 3600
      records = [
        "10.10.10.10",
      ]
    }
  ]


  zone_id = "<zone-id-2>"
  private_zone = true

  records = [
    {
      name    = "example-test-1"
      type    = "CNAME"
      ttl     = 3600
      records = [
        "10.10.10.20",
      ]
    }
  ]
}

Steps to reproduce the behavior:
terraform apply

Expected behavior

There is a record name "example-test-1" and I want to create entry for it for 2 hosted zone, one is public and other is private.

Actual behavior

Unable to find a way to perform this.

Terminal Output Screenshot(s)

Additional context

I am not able to figure out how to provide 2 different zone_id(s) in the same module block, one with passing private_zone = true and other without it (public).

Please add clear documentation to warn other users of the risks related to #66

Description

Escalating #66 and requesting that extra documentation be provided to explain and warn future users of this module to it's expected module when a zone is changed.

I just used this module and had to make a zone change, and experienced an outage of an extended duration. This outage would Not have occurred if this module's behavior were more conventional, and so I think it's only prudent that clear and obvious warnings / disclaimers be published for this module.

Suggested documentation could include guidance such as:

  • only using 1 item in each zone module collection (to limit blast radius).
  • Not using the zone module in production environments

Versions

  • Module version [Required]:
    2.10.2

  • Terraform version:
    1.5.1

  • Provider version(s):
    4.40.0

Reproduction Code [Required]

module "zones_com_domain" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 2.0"

  zones = {
    "domain.com" = {
      comment = "Primary domain"
      create = false
    }

    "sub.domain.com" = {
      comment = "This zone is a subdomain."
      create = false
    }
  }
}

Steps to reproduce the behavior:

See also #66 for additional context

Yes, we are using workspaces, but only 1 workspace for this project
Any of the following change can result in Terraform forcing replacement of all module resources

  • Add another zone to this collections of zones.
  • Modify the comment
  • Remove a zone item from the collection

Expected behavior

Production resources are Not destroyed when they are not explicitly modified

Actual behavior

Production resources (Route53 records) were destroyed (before being recreated), when they were not explicitly modified

Invalid for_each argument in v1.6.0

Error: Invalid for_each argument

  on .terraform/modules/records-private-ro/modules/records/main.tf line 15, in resource "aws_route53_record" "this":
  15:   for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : tomap({})

The "for_each" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the for_each depends on.

v1.5.0 works perfectly

The true and false result expressions must have consistent types. The given expressions are object and map of dynamic, respectively.

I raised the version to 1.5.0 and got an error in the title.

It seems to have been changed from object to tomap at the time of false, but if you check the specification of tomap, you will find the following.

Since Terraform's concept of a map requires all of the elements to be of the same type, mixed-typed elements will be converted to the most general type

If this is correct then I think it would be an error because what is defined in bool is not of the correct type, but isn't this kind of problem happening?

Thanks

Not possible to use variable as zone name

Because zone name place as key terraform doesn't allow to use a variable for it.

terraform plan

Error: Ambiguous attribute key

  on dns.tf line 6, in module "zones":
   6:     var.domain_name_com = {

If this expression is intended to be a reference, wrap it in parentheses. If
it's instead intended as a literal name containing periods, wrap it in quotes
to create a string literal.

Zone Modules Example Fails

Description

Following the documentation for using the zones module fails.

Steps

  1. Copy/Pasted Example
    module "zones" {
      source  = "terraform-aws-modules/route53/aws//modules/zones"
      version = "~> 1.2.0"
    
      zones = {
        "terraform-aws-modules-example.com" = {
          comment = "terraform-aws-modules-examples.com (preprod)"
          tags = {
            env = "preprod"
          }
        }
    
        "leadr.local" = {
          comment = "leadr.local"
        }
      }
    }
  2. terraform init && terraform plan

Expected Results

This would work.

Actual Results

Error: Invalid value for module argument

  on intranet_zones.tf line 5, in module "zones":
   5:   zones = {
   6:     "terraform-aws-modules-example.com" = {
   7:       comment = "terraform-aws-modules-examples.com (preprod)"
   8:       tags = {
   9:         env = "preprod"
  10:       }
  11:     }
  13:     "mycompany.local" = {
  14:       comment = "mycompany.local"
  15:     }
  16:   }

The given value is not suitable for child module variable "zones" defined at
.terraform/modules/zones/modules/zones/variables.tf:7,1-17: all map elements
must have the same type.

DNS records are recreated on hosted zone change

Description

I've tried to use the example code for configuring zone and records in our setup, but noticed an annoying thing, terraform wants to recreate all zone records on change Hosted Zone comment or tags.

Versions

  • Terraform: v1.0.8
  • Provider(s): registry.terraform.io/hashicorp/aws v3.69.0
  • Module: 2.5.0

Reproduction

Steps to reproduce the behavior:

  1. Apply the module example code to create zones and records.
  2. Update Zone comment or tags
  3. Try to apply changes and see that terraform forces to replace all zone records

Code Snippet to Reproduce

module "zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 2.5"

  zones = {
    "terraform-aws-modules-example.com" = {
      comment = "terraform-aws-modules-examples.com (production)"
      tags = {
        env = "production"
      }
    }

    "myapp.com" = {
      comment = "myapp.com updated comment"
    }
  }

  tags = {
    ManagedBy = "Terraform"
  }
}

module "records" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "~> 2.5"

  zone_name = keys(module.zones.route53_zone_zone_id)[0]

  records = [
    {
      name    = "test1"
      type    = "A"
      ttl     = 3600
      records = [
        "10.10.10.10",
      ]
    },
    {
      name    = "test2"
      type    = "A"
      ttl     = 3600
      records = [
        "10.10.10.20",
      ]
    },
    {
      name    = ""
      type    = "A"
      ttl     = 3600
      records = [
        "10.10.10.30",
      ]
    },
  ]

  depends_on = [module.zones]
}

Expected behavior

Zone configuration is updated in-place without recreation and changes in records

Actual behavior

Zone configuration updated in-place but all zone records recreated

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement
 <= read (data resources)

Terraform will perform the following actions:

  # module.records.data.aws_route53_zone.this[0] will be read during apply
  # (config refers to values not yet known)
 <= data "aws_route53_zone" "this"  {
      ~ arn                        = "arn:aws:route53:::hostedzone/Z01457301C71HTVBG3RXM" -> (known after apply)
      ~ caller_reference           = "terraform-20220124083615109700000001" -> (known after apply)
      ~ comment                    = "myapp.com" -> (known after apply)
      ~ id                         = "Z01457301C71HTVBG3RXM" -> (known after apply)
      + linked_service_description = (known after apply)
      + linked_service_principal   = (known after apply)
        name                       = "myapp.com"
      ~ name_servers               = [
          - "ns-451.awsdns-56.com",
          - "ns-1461.awsdns-54.org",
          - "ns-1580.awsdns-05.co.uk",
          - "ns-731.awsdns-27.net",
        ] -> (known after apply)
      ~ resource_record_set_count  = 2 -> (known after apply)
      ~ tags                       = {
          - "ManagedBy" = "Terraform"
        } -> (known after apply)
      + vpc_id                     = (known after apply)
      ~ zone_id                    = "Z01457301C71HTVBG3RXM" -> (known after apply)
        # (1 unchanged attribute hidden)
    }

  # module.records.aws_route53_record.this[" A"] must be replaced
-/+ resource "aws_route53_record" "this" {
      ~ fqdn            = "myapp.com" -> (known after apply)
      ~ id              = "Z01457301C71HTVBG3RXM_myapp.com_A" -> (known after apply)
        name            = "myapp.com"
      ~ zone_id         = "Z01457301C71HTVBG3RXM" -> (known after apply) # forces replacement
        # (4 unchanged attributes hidden)
    }

  # module.records.aws_route53_record.this["test1 A"] must be replaced
-/+ resource "aws_route53_record" "this" {
      ~ fqdn            = "test1.myapp.com" -> (known after apply)
      ~ id              = "Z01457301C71HTVBG3RXM_test1.myapp.com_A" -> (known after apply)
        name            = "test1.myapp.com"
      ~ zone_id         = "Z01457301C71HTVBG3RXM" -> (known after apply) # forces replacement
        # (4 unchanged attributes hidden)
    }

  # module.records.aws_route53_record.this["test2 A"] must be replaced
-/+ resource "aws_route53_record" "this" {
      ~ fqdn            = "test2.myapp.com" -> (known after apply)
      ~ id              = "Z01457301C71HTVBG3RXM_test2.myapp.com_A" -> (known after apply)
        name            = "test2.myapp.com"
      ~ zone_id         = "Z01457301C71HTVBG3RXM" -> (known after apply) # forces replacement
        # (4 unchanged attributes hidden)
    }

  # module.zones.aws_route53_zone.this["myapp.com"] will be updated in-place
  ~ resource "aws_route53_zone" "this" {
      ~ comment       = "myapp.com" -> "myapp.com updated comment"
        id            = "Z01457301C71HTVBG3RXM"
        name          = "myapp.com"
        tags          = {
            "ManagedBy" = "Terraform"
        }
        # (5 unchanged attributes hidden)
    }

Plan: 3 to add, 1 to change, 3 to destroy.

Terminal Output Screenshot(s)

Additional context

Multiple records return error: element types must all match for conversion to map

Description

Hi, I created a hosted zone using the modules/zones and now I'm trying to create multiple records for this zone using the modules/records. These records are simple CNAME, MX, TXT, etc...

Can someone provide some insight on what I am doing wrong?

Versions

  • Terraform: v1.0.0
  • Provider(s): hashicorp/aws v3.47.0
  • Module: terraform-aws-modules/route53/aws v2.1.0

Reproduction

The hosted zone:

module "zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "2.1.0"

  zones = {
    "example.org" = {
      tags = {
        Environment = "main"
      }
    }
  }
}

The records:

module "records_souadiferenca_org" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "2.1.0"

  zone_id    = module.zones.route53_zone_zone_id["example.org"]
  depends_on = [module.zones]

  records = [
    {
      name    = "www"
      type    = "CNAME"
      ttl     = 5
      records = ["example.org"]
    },
    {
      name    = ""
      type    = "MX"
      ttl     = 5
      records = ["10 mx.zoho.com", "20 mx2.zoho.com", "50 mx3.zoho.com"]
    },
    {
      name    = ""
      type    = "TXT"
      ttl     = 300
      records = ["zoho-verification=example.zoho.com"]
    },
    {
      name = ""
      type = "NS"
      ttl  = 172800
      records = [
        module.zones.route53_zone_name_servers["example.org"][0],
        module.zones.route53_zone_name_servers["example.org"][1],
        module.zones.route53_zone_name_servers["example.org"][2],
        module.zones.route53_zone_name_servers["example.org"][3],
      ]
    }
  ]
}

P.S.: I tried replacing the module.zones.route53_zone_name_servers["example.org"][0] with the actual NS records and it didn't worked as well. The module.zones.route53_zone_name_servers["example.org"][0] does indeed returns the name_servers from the hosted zone. The terraform console output of [0] is: "ns-1304.awsdns-35.org", it is apparently a string.

Expected behavior and Actual behavior

It should create the records. Looks like the variables are the same type of one another.
The output is Error: Inconsistent conditional result types and The true result value has the wrong type: element types must all match for conversion to map. as the screenshot below shows.

Seems likes the module is not correctly converting all the records to the for_each tomap({}) function.

Terminal Output Screenshot(s)

image

Unable to use module from git

Description

I'm trying to utilize this module by cloning it from git with https://

Versions

Terraform v0.14.9

  • provider registry.terraform.io/hashicorp/aws v3.59.0

Reproduction

Steps to reproduce the behavior:
I am using workspaces and I've attempted this terraform init after deleting the .terraform directory.

Code Snippet to Reproduce

module "records" {
  source = "https://github.com/terraform-aws-modules/terraform-aws-route53.git"
  zone_id = var.zone_id
  records = [
     {
      name           = var.record_name
      type           = "CNAME"
      ttl            = 5
      records        = var.records
      set_identifier = var.identifier
      weighted_routing_policy = {
        weight = 100
      }
     }
  ]
}

Expected behavior

I expect terraform to clone the module and utilize it.

Actual behavior

Error: Failed to download module

Could not download module "records" (main.tf:26) source code from
"https://github.com/terraform-aws-modules/terraform-aws-route53.git": error
downloading
'https://github.com/terraform-aws-modules/terraform-aws-route53.git': no
source URL was returned

Still having for_each issue on version 2.10.1

Description

Please provide a clear and concise description of the issue you are encountering, and a reproduction of your configuration (see the examples/* directory for references that you can copy+paste and tailor to match your configs if you are unable to copy your exact configuration). The reproduction MUST be executable by running terraform init && terraform apply without any further changes.

If your request is for a new feature, please use the Feature request template.

  • βœ‹ I have searched the open/closed issues and my issue is not listed.

⚠️ Note

Before you submit an issue, please perform the following first:

  1. Remove the local .terraform directory (! ONLY if state is stored remotely, which hopefully you are following that best practice!): rm -rf .terraform/
  2. Re-initialize the project root to pull down modules: terraform init
  3. Re-attempt your terraform plan or apply and check if the issue still persists

Versions

  • Module version [2.10.1]:

  • Terraform version:
    <v1.3.5>

  • Provider version(s):
    <4.36.1>

Reproduction Code [Required]


locals {
    lb_zone_id = module.pub_alb.lb_zone_id
    lb_dns_name = module.pub_alb.lb_dns_name
    zone_id = data.aws_route53_zone.default_zone.zone_id
    record_meta = {
        create = true
        private_zone = false
        zone_name = local.zone_name #data.aws_route53_zone.default_zone.name
        records = [
            {
                name    = local.record1_name
                type    = "A"
                alias   = {
                    name                   = local.lb_dns_name
                    zone_id                = local.lb_zone_id
                    evaluate_target_health = false
                }
            },
            {
                name    = local.record2_name
                type    = "A"
                ttl     = 3600
                records = [
                    "10.10.10.10",
                ]
            },
        ]
    }
}
module "pub_alb" {
  source  = "terraform-aws-modules/alb/aws"
  version = "~> 8.2.0"

  name = "test-alb"

  load_balancer_type = "application"

  vpc_id             = "vpc-051b60448f53f3505"
  subnets         =  ["subnet-0e238ae12be89f11b", "subnet-0fae5ee2659056e38"]
  security_groups = [module.pub_alb_sg.security_group.security_group_id]
  internal = false
   http_tcp_listeners = [
    {
      port        = 80
      protocol    = "HTTP"
      action_type = "fixed-response"
      fixed_response = {
        content_type = "text/html"
        message_body = "<html><body><h1>Hello World!</h1><p>This would usually be to a target group of web servers.. but this is just a demo to returning a fixed response\n\n</p></body></html>"
        status_code  = "200"
      }
    },
   ]
 
}
module "records" {
    source  = "terraform-aws-modules/route53/aws//modules/records"
    version = "~> 2.10.1"
    create = try(local.record_meta.create, true)
    private_zone = try(local.record_meta.private_zone, false)

    zone_name = try(local.record_meta.zone_name, null)
    zone_id = try(local.record_meta.zone_id, null)
    records = try(local.record_meta.records, [])
    depends_on = [
      module.pub_alb
    ]
}

Steps to reproduce the behavior:

Expected behavior

Actual behavior

Terminal Output Screenshot(s)

β”‚ 19: for_each = { for k, v in local.recordsets : k => v if var.create && (var.zone_id != null || var.zone_name != null) }
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ local.recordsets will be known only after apply
β”‚ β”‚ var.create is true
β”‚ β”‚ var.zone_id is null
β”‚ β”‚ var.zone_name is "test.online"
β”‚
β”‚ The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys
β”‚ that will identify the instances of this resource.
β”‚
β”‚ When working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map
β”‚ values.
β”‚
β”‚ Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to
β”‚ fully converge.

Additional context

The "count" value depends on resource attributes that cannot be determined until apply

Description

Hi, I have the same issue like this Issue:59
I am creating CloudFront distributions and all other related resources using for_each , here is the full code for those:

module "route53_clients_zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 2.10"
  zones = { for domain, client in var.clients_domain : domain => {
    name    = domain
    comment = domain
    tags    = var.project_tags
  } }

  tags = var.project_tags
}

module "route53_clients_records" {
  source     = "terraform-aws-modules/route53/aws//modules/records"
  version    = "~> 2.10"
  depends_on = [module.acm_client_domains_cloudfront]
  for_each   = var.clients_domain
  create     = each.value.dns_pointing_to_our_nameservers
  zone_id    = module.route53_clients_zones.route53_zone_zone_id[each.key]
  records = [
    {
      name = ""
      type = "A"
      alias = {
        name    = module.cloudfront[each.key].cloudfront_distribution_domain_name
        zone_id = module.cloudfront[each.key].cloudfront_distribution_hosted_zone_id
      }
    }
  ]
}



module "acm_client_domains_cloudfront" {
  source  = "terraform-aws-modules/acm/aws"
  version = "~> 5.0"
  providers = {
    aws = aws.us-east-1
  }
  depends_on                         = [module.route53_zones]
  for_each                           = var.clients_domain
  create_certificate                 = each.value.dns_pointing_to_our_nameservers
  validation_method                  = "DNS"
  validate_certificate               = true
  validation_allow_overwrite_records = false
  create_route53_records             = true
  domain_name                        = each.key
  zone_id                            = module.route53_clients_zones.route53_zone_zone_id[each.key]
  wait_for_validation                = true
  tags                               = var.project_tags
}

module "cloudfront" {
  source                         = "terraform-aws-modules/cloudfront/aws"
  version                        = "~> 3.2"
  for_each                       = var.clients_domain
  create_distribution            = each.value.dns_pointing_to_our_nameservers
  depends_on                     = [module.route53_clients_zones]
  aliases                        = [each.key]
  comment                        = each.key
  enabled                        = true
  http_version                   = "http2and3"
  is_ipv6_enabled                = false
  price_class                    = each.value.cloudfront_price_class
  wait_for_deployment            = false
  retain_on_delete               = false
  default_root_object            = "index.html"
  create_monitoring_subscription = false
  create_origin_access_identity  = false
  create_origin_access_control   = true
  origin_access_control = {
    "OAC_${each.key}" : {
      description      = "CloudFront access to S3 for ${each.key}"
      origin_type      = "s3"
      signing_behavior = "always"
      signing_protocol = "sigv4"
    }
  }

  origin = {
    s3_bucket = {
      domain_name           = module.s3_bucket[each.key].s3_bucket_bucket_regional_domain_name
      origin_access_control = "OAC_${each.key}"
    }
  }

  default_cache_behavior = {
    target_origin_id           = "s3_bucket"
    viewer_protocol_policy     = "allow-all"
    allowed_methods            = ["GET", "HEAD", "OPTIONS", "PUT", "PATCH", "POST", "DELETE"]
    cached_methods             = ["GET", "HEAD"]
    compress                   = true
    query_string               = true
    response_headers_policy_id = "67f7725c-6f97-4210-82d7-5512b31e9d03"
  }

  viewer_certificate = {
    acm_certificate_arn = module.acm_client_domains_cloudfront[each.key].acm_certificate_arn
    ssl_support_method  = "sni-only"
  }

  custom_error_response = [
    {
      error_code         = 404
      response_code      = 404
      response_page_path = "/index.html"
    },
    {
      error_code         = 403
      response_code      = 403
      response_page_path = "/index.html"
    },
    {
      error_code         = 500
      response_code      = 500
      response_page_path = "/500/index.html"
    },
  ]

  tags = var.project_tags
}

module "s3_bucket" {
  source        = "terraform-aws-modules/s3-bucket/aws"
  version       = "~> 3.15"
  depends_on    = [module.route53_clients_zones]
  for_each      = var.clients_domain
  bucket        = "${each.key}--${var.s3_bucket_name_cloudfront_suffix}"
  force_destroy = true
  website = {
    index_document = "index.html"
    error_document = "index.html"
  }
  tags = var.project_tags
}

data "aws_iam_policy_document" "s3_policy" {
  for_each = var.clients_domain
  statement {
    actions   = ["s3:GetObject"]
    resources = ["${module.s3_bucket[each.key].s3_bucket_arn}/*"]
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = [module.cloudfront[each.key].cloudfront_distribution_arn]
    }
  }
}

resource "aws_s3_bucket_policy" "bucket_policy" {
  for_each = data.aws_iam_policy_document.s3_policy
  bucket   = module.s3_bucket[each.key].s3_bucket_id
  policy   = each.value.json
}

And here is the variable:

variable "clients_domain" {
  type = map(map(string))
}

I have also tried with map object but the same issue, like this:

variable "clients_domain" {
  type = map(object({
    cloudfront_price_class          = string
    dns_pointing_to_our_nameservers = bool
  }))
}

And here is my tfvars:

clients_domain = {
  "dev.somedomain.de" = {
    cloudfront_price_class          = "PriceClass_100"
    dns_pointing_to_our_nameservers = true
  }
  "www.adomain.com" = {
    cloudfront_price_class          = "PriceClass_100"
    dns_pointing_to_our_nameservers = true
  }
  "www.bdomain.eu" = {
    cloudfront_price_class          = "PriceClass_100"
    dns_pointing_to_our_nameservers = false
  }
}

This happens only when I try to add new domain on tfvars.

  • βœ‹ I have searched the open/closed issues and my issue is not listed.
    Note, as mentioned the issue is closed but still same issue

Versions

  • Module version [Required]: Route53 version: ~> 2.10.2

  • Terraform version and Provider version(s):

$ terraform -version
Terraform v1.6.6
on windows_amd64
+ provider registry.terraform.io/hashicorp/aws v5.30.0
+ provider registry.terraform.io/hashicorp/random v3.6.0

Reproduction Code [Required]

Steps to reproduce the behavior:
Are you using workspaces? --> NO
Have you cleared the local cache (see Notice section above)? --> NO, but tried also in another PC
List steps in order that led up to the issue you encountered:
Simply copy the code above and try to run, the issue is known.

Expected behavior

Plan and apply should suceed

Actual behavior

β”‚ Error: Invalid count argument
β”‚
β”‚   on .terraform\modules\route53_clients_records\modules\records\main.tf line 11, in data "aws_route53_zone" "this":
β”‚   11:   count = var.create && (var.zone_id != null || var.zone_name != null) ? 1 : 0
β”‚
β”‚ The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict
β”‚ how many instances will be created. To work around this, use the -target argument to first apply only the resources
β”‚ that the count depends on.

Terminal Output Screenshot(s)

image

Variable Type not working when specific

Description

Unable to specify a defined type for the variable records, only works with any
Not sure how much it is a bug but if we want to define a better type it won't work.

  • βœ‹ I have searched the open/closed issues and my issue is not listed.

Versions

  • Module version [Required]: 2.10.2

  • Terraform version:

1.6.4
  • Provider version(s):
5.29.0

Reproduction Code [Required]

Steps to reproduce the behavior:

No Yes

Using a type of any like here works well
But when trying to define records like that:

    records = list(object({
      name    = string
      type    = string
      ttl     = optional(number, null)
      records = optional(list(string), null)
      alias = optional(object({
        name                   = string
        zone_id                = string
        evaluate_target_health = optional(bool, null)
      }), null)

fails due to the lookup being done with this code

Expected behavior

Terraform run should work when alias object is set to null, (meaning for this entry im using records)

Actual behavior

Fails with following error:


β”‚ Error: Invalid function argument
β”‚
β”‚   on .terraform/modules/route53_records/modules/records/main.tf line 33, in resource "aws_route53_record" "this":
β”‚   33:     for_each = length(keys(lookup(each.value, "alias", {}))) == 0 ? [] : [true]
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ while calling keys(inputMap)
β”‚     β”‚ each.value is object with 5 attributes
β”‚
β”‚ Invalid value for "inputMap" parameter: argument must not be null.
β•΅

Additional context

Must add of course than using any for the variable type solve this but its always nicer to have your type specifically defined

Error on record alias

I'm using the example provided and when the alias is configured i have this error:

Error: Inconsistent conditional result types

on .terraform/modules/records/terraform-aws-route53-1.0.0/modules/records/main.tf line 15, in resource "aws_route53_record" "this":
15: for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : {}
|----------------
| local.recordsets is object with 2 attributes
| var.create is true
| var.zone_id is null
| var.zone_name is "myapp.com"

The true and false result expressions must have consistent types. The given
expressions are object and object, respectively.

OBS: Terraform v0.12.28

Could you help me please?

Support Lifecycle config in modules

Is your request related to a new offering from AWS?

No.

Is your request related to a problem? Please describe.

It will be great if we could support lifecycle configuration within the modules.

Describe the solution you'd like.

Something like:

  lifecycle {
    ignore_changes = var.ignore_changes
  }

Describe alternatives you've considered.

N/A

Additional context

N/A

[Module 'Records'] Add support for Latency routing policies

Is your request related to a new offering from AWS?

Is this functionality available in the AWS provider for Terraform? See CHANGELOG.md, too.

Is your request related to a problem? Please describe.

I cannot import the already created records into the module since all of them use a latency routing policy to find the nearest region

Describe the solution you'd like.

Just add an extra input for the required routing policy

Describe alternatives you've considered.

The only workaround would be not using this module for records that need this kind of policy

Additional context

Wrong plan in second execution

Hi,

When executing Plan command for this module after first Apply (which passed successfully), it will give wrong Plan output.
It tells that there's a change:
vpc_id -> null
region -> null

Expected:
Plan: 0 to add, 0 to change, 0 to destroy
Actual:
Plan: 0 to add, 1 to change, 0 to destroy

Are you aware about this issue ?

zone_id and zone_name are not allowed to use together, have ability to use additional name

Description

Providing zone_name as per module '[email protected]:terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=v2.0.0"' throws an error.

module "r53_record_public" {
  source         = "[email protected]:terraform-aws-modules/terraform-aws-route53.git//modules/records?ref=v2.0.0"
  zone_id        = var.r53_public_zone_id
  zone_name  = "${local.aws_tags.project}-${terraform.workspace}.${var.r53_public_zone_domain}"
 
 records = [{
    name = "${local.aws_tags.project}-${terraform.workspace}.${var.r53_public_zone_domain}"
    type = "A"
    alias = {
      name                   = module.cf_alb_distribution.cloudfront_distribution_domain_name
      zone_id                = module.cf_alb_distribution.cloudfront_distribution_hosted_zone_id
      evaluate_target_health = true
    }
  }]
}

As per TF doc, both cannot be used together.
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone

Versions

  • Terraform: 0.13.4
  • Provider(s): aws 3.28.0
  • Module: 2.0.0

Expected behavior

user should have the ability to input custom zone name which should not join with data "aws_route53_zone"

Actual behavior

when we provide zone_name it returns an error

Error: zone_id and name arguments can't be used together.

Additional context

I am not sure if this is the correct approach, but when I tweaked the module and replace name as:

From:
name = each.value.name != "" ? "${each.value.name}.${data.aws_route53_zone.this[0].name}" : data.aws_route53_zone.this[0].name

To:
name = each.value.name != "" ? "${each.value.name}" : data.aws_route53_zone.this[0].name

This helped me to have the ability to input custom zone_name and hope if this is a right approach we can work on this bug.
I apologize if I missed providing more information and appreciate any further feedbacks.

[Zones] Add support for passing more than 1 VPC to associate with a private zone

Is your request related to a new offering from AWS?

No

Is this functionality available in the AWS provider for Terraform? See CHANGELOG.md, too.

  • Yes βœ…: please list the AWS provider version which introduced this functionality
    Don't know which specific version, but you can see below more than 1 VPC can be defined for a zone

Screenshot 2022-10-07 at 11 49 16

Is your request related to a problem? Please describe.

The module doesn't support adding more than one VPC for z private zone. if I add it manually it will try to revert it

Terraform will perform the following actions:

  # module.zones.aws_route53_zone.this["example.com"] will be updated in-place
  ~ resource "aws_route53_zone" "this" {
        id            = "XXXXXXXXXXXXXXXX"
        name          = "example.com"
        tags          = {
            "Environment" = "Test"
        }
        # (6 unchanged attributes hidden)

      - vpc {
          - vpc_id     = "vpc-aaaaabbbbbcccccc" -> null
          - vpc_region = "eu-west-1" -> null
        }

        # (1 unchanged block hidden)
    }

Describe the solution you'd like.

I would like the module to be able to support something like

locals {
  vpcs = {
      frankfurt_vpc = {
        vpc_id = "vpc-aaaaabbbb"
        vpc_region = "eu-central-1"
      }
      local_vpc = {
        vpc_id = data.aws_vpc.default.id
        vpc_region = local.region
      }
   }
}
module "zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 2.0"
  
  zones = {
    "example.com" = {
      tags = {
        Environment = "Data"
        Terraform = true
      }
      vpcs = local.vpcs
      }
    }
  }

Describe alternatives you've considered.

An alternative would be not defining VPCs at all and using a resource "aws_route53_zone_association" in a loop.

Additional context

I didn't try the alternative proposed yet, but not sure if not passing VPC for a private zone is possible

Issue upgrading from 2.0.0 to 2.1.0

Description

Hello, I just started using this module in its latest version (2.1.0); but encountered a bug that's fixed when I use 2.0.0.
I have this setup for route53, which is not too far from the one in the examples.

module "zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "2.1.0"

  zones = {
    (var.account_domain_name) = {
      comment = var.account_domain_name
      tags = {
        Name = var.account_domain_name
      }
    }
  }

  tags = {
    ManagedBy = "Terraform"
  }
}

module "records" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "2.1.0"

  zone_name = keys(module.zones.route53_zone_zone_id)[0]

  records = [
    {
      name    = module.instance_a.tags[0].Name # module.instance_a is an ec2 instance created with the module terraform-aws-modules/ec2-instance/aws
      type    = "A"
      ttl     = 86400  # 1 day
      records = module.instance_a.private_ip
      zone_id = module.zones.route53_zone_zone_id
    }
  ]

  depends_on = [module.zones]
}

The thing is, when I apply this config, it tells me:

β•·
β”‚ Error: Invalid for_each argument
β”‚ 
β”‚   on .terraform/modules/records/modules/records/main.tf line 19, in resource "aws_route53_record" "this":
β”‚   19:   for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : tomap({})
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ local.recordsets will be known only after apply
β”‚     β”‚ var.create is true
β”‚     β”‚ var.zone_id is null
β”‚     β”‚ var.zone_name is "test-project.com"
β”‚ 
β”‚ The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this,
β”‚ use the -target argument to first apply only the resources that the for_each depends on.
β•΅

Again, when I downgrade to 2.0.0 I don't have this issue!

⚠️ Note

Before you submit an issue, please perform the following first:

  1. Remove the local .terraform directory (! ONLY if state is stored remotely, which hopefully you are following that best practice!): rm -rf .terraform/
  2. Re-initialize the project root to pull down modules: terraform init
  3. Re-attempt your terraform plan or apply and check if the issue still persists

Versions

  • Terraform: v1.0.0
  • Provider(s): provider registry.terraform.io/hashicorp/aws v3.45.0
  • Module: 2.1.0

Reproduction

Steps to reproduce the behavior:

Code Snippet to Reproduce

Provided above

Expected behavior

I expected it to work as it used to, by seeing that my records object is not jsonencoded, and thus iterating over it properly.

Actual behavior

I guess try() or jsondecode() does not behave correctly, so locals.records does not contain the right value.

Terminal Output Screenshot(s)

stdout provided above

Additional context

N/A

Route53 Record module does not support weighted_records

Currently the route53 record module doesn't support weighted_records.

Using a dynamic block would solve one part of the problem:

  dynamic "weighted_routing_policy" {
    for_each = length(keys(lookup(each.value, "weighted_routing_policy", {}))) == 0 ? [] : [true]

    content {
      weight = each.value.weighted_routing_policy.weight
    }
  }

Unfortunately, the locals calculated would produce non-unique keys as the name and type would be identical. Re-writing the for loop would produce unique keys:

recordsets = { for idx, rs in var.records : "${rs.name} ${idx}" => rs }

Issue with multiple values for MX (and possibly other TXT) record type for bare domain resulting in mixed types in map??

Description

Unless I'm doing something wrong, multiple values for MX (and possibly other TXT-style) record types are not supported and throw a Terraform error due to mixed map types in the local.recordsets value... I hope I'm missing something particularly obvious...

Reproduction

Code Snippet to Reproduce

module "server_com_records" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "~> 2.0"

  zone_name = keys(module.root_zones.route53_zone_zone_id)[0]

  records = [
    {
      name = "" # Apex A Record (Works)
      type = "A"
      ttl  = 3600
      records = [
        "1.3.3.7",
        "1.2.3.4"
      ]
    },
    {
      name = "" # Apex MX Record (Sometimes works with 1 records)
      type = "MX"
      ttl  = 300
      records = [
        "5 mx1.mailserver.com"
      ]
    },
    {
      name = "" # Apex MX Record (Doesn't Work with >= 2 records)
      type = "MX"
      ttl  = 300
      records = [
        "5 mx1.mailserver.com",
        "5 mx2.mailserver.com"
      ]
    },
  ]

  depends_on = [module.root_zones]
}

Expected behavior

MX record is created with 2 records

Actual behavior

β”‚ Error: Inconsistent conditional result types
β”‚
β”‚   on .terraform/modules/server_com_records/modules/records/main.tf line 15, in resource "aws_route53_record" "this":
β”‚   15:   for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : tomap({})
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ local.recordsets is object with (2|3) attributes
β”‚
β”‚ The true result value has the wrong type: element types must all match for conversion to map.

Terminal Output Screenshot(s)

βœ— terraform --version
Terraform v0.15.4
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v3.42.0

Additional context

It sometimes doesn't work even with 1 record when multiple bare records are present...

I manually added output to print local.recordsets in the .terraform/modules/server_com_records/modules/records/outputs.tf and printed it in terraform console:

> module.server_com_records
{
  "route53_record_fqdn" = {
    " A" = "server.com"
  }
  "route53_record_name" = {
    " A" = "server.com"
  }
  "route53_recordsets" = {
    " A" = {
      "name" = ""
      "records" = [
        "1.3.3.7",
        "1.2.3.4",
      ]
      "ttl" = 3600
      "type" = "A"
    }
    " MX" = {
      "name" = ""
      "records" = [
        "5 mx1.mailserver.com",
        "5 mx2.mailserver.com",
      ]
      "ttl" = 300
      "type" = "MX"
    }
  }
}

Invalid count argument, and zones applied 0

I have the following configuration:

locals {
  group = "acc"
  tags = {
    Group     = local.group
    Env       = var.env
    Terraform = true
  }
  domain   = "${local.group}.some-domain.net"
  zone_int = "${var.env}.${local.group}.internal.${local.domain}"
  zone_ext = "${var.env}.${local.group}.${local.domain}"
}

module "zones" {
  source = "terraform-aws-modules/route53/aws//modules/zones"

  zones = {
    (local.zone_ext) = {
      comment = local.zone_ext

      tags = local.tags
    }

    (local.zone_int) = {
      comment = local.zone_int
      vpc = {
        vpc_id = module.main_vpc.vpc_id
      }

      tags = local.tags
    }
  }
}

module "records_internal" {
  source       = "terraform-aws-modules/route53/aws//modules/records"
  zone_id      = module.zones.this_route53_zone_zone_id[local.zone_int]
  private_zone = true

  records = [
    {
      name    = "account-db.${local.zone_int}"
      type    = "CNAME"
      records = [module.db.this_rds_cluster_endpoint]
    }
  ]

  depends_on = [module.zones]
}

I would expect this to create two zones: one public acc-dev.some-domain.net and acc-dev.internal.some-domain.net. The latter being in the vpc.

Then I intend to create a CNAME pointing to the db endpoint in the internal zone.

However, when I run plan, I get:

terraform plan                      

Error: Invalid count argument

  on .terraform/modules/acc_dev.records_internal/modules/records/main.tf line 7, in data "aws_route53_zone" "this":
   7:   count = var.create && (var.zone_id != null || var.zone_name != null) ? 1 : 0

The "count" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the count depends on.

Releasing state lock. This may take a few moments...

So, I attempt to build the zones first:

terraform apply -target module.zones

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Releasing state lock. This may take a few moments...

But I assure you, no zones are created, and the plan still returns the same output. What am I missing?

version info:

terraform version
Terraform v0.14.4
+ provider registry.terraform.io/hashicorp/aws v3.23.0
+ provider registry.terraform.io/hashicorp/random v3.0.1

Inconsistent conditional result types (with more than one zone)

Description

I get same issue as #39 and #47 but for zone. It works with only one zone defined, adding a second zone in a simple configuration

Returns:

β”‚ Error: Inconsistent conditional result types
β”‚
β”‚   on ..../modules/zones/main.tf line 2, in resource "aws_route53_zone" "this":
β”‚    2:   for_each = var.create ? var.zones : tomap({})
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ var.zones is object with 2 attributes
β”‚
β”‚ The true result value has the wrong type: element types must all match for
β”‚ conversion to map.

Versions

  • Module version: 2.8.1

  • Terraform version: 1.2.2

  • Provider version(s): registry.terraform.io/hashicorp/aws v4.12.0

Reproduction Code

module "route53_hz_root" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "2.8.1"

  zones =  {
    "domain1.net" = {
      comment = "Production Base hosted zone"
      tags    = {
        "Environment" = "prod"
      }
    }
    "domain2.net" = {
      comment = "Production Base hosted zone"
      tags    = {
        "Environment" = "prod"
      }
    }
  }

  tags = {
    Terraform = "true"
  }
}

Steps to reproduce the behavior:

step1: apply this config with one zone:

module "route53_hz_root" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "2.8.1"

  zones =  {
    "domain1.net" = {
      comment = "Production Base hosted zone"
      tags    = {
        "Environment" = "prod"
      }
    }
  }

  tags = {
    Terraform = "true"
  }
}

step2: Then change as above (Reproduction Code) and apply.

Additional context

Probably also for zones will work the same solution as records: changing tomap({}) to {} will solve the issue.

Note: wrapping var.zone inside tomap({...}) allow to create hosted zones but this is not a clean solution. Not sure if tied to this issue but every change in any of the zone destroy and recreate every subzones based on root zones also if zone id remains the same.

There is no function named "object" (v0.13.3)

Error: Call to unknown function

on .terraform/modules/coginto_route53/modules/records/main.tf line 15, in resource "aws_route53_record" "this":
15: for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : object({})

There is no function named "object".

Example doesn't work for me

Hey,
I tried to do the example but I got the following error:

$ terraform plan
Error: Reserved argument name in module block

  on dns.tf line 43, in module "records":
  43:   depends_on = [module.zones]

The name "depends_on" is reserved for use in a future version of Terraform.

Trying to get the route53_zone_name_servers but getting subdomain name instead

I think maybe this is a beginner question

I'm creating these two zones

module "zones" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 2.0"

  zones = {
    "dev-env.com" = {
      tags = {
        env = "dev"
      }
    }
    "sub.dev-env.com" = {
      tags = {
        env = "dev"
      }
    }
  }
}

Then I want to create a NS record on dev-env pointing to the subdomain name servers

module "records_sub_on_env" {
  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "~> 2.0"
  zone_name = keys(module.zones.route53_zone_zone_id)[0]
  records = [
    {
      name    = "sub"
      type    = "NS"
      ttl     = 3600
      records = [keys(module.zones.route53_zone_name_servers)[1]]
    }
  ]

  depends_on = [module.zones]
}

But terraform plan is getting "sub.dev-env.com" instead of the dns name server values... Am I doing something wrong?

Modifying record type causes the record to be deleted and recreated

Is your request related to a new offering from AWS?

Is this functionality available in the AWS provider for Terraform?

  • Yes βœ…

Is your request related to a problem? Please describe.

When updating the type of a route53 record, the record gets deleted and recreated. This causes the domain to be unavailable for some time.
This is because recordset name is created by concatenating name and type of record.

Describe the solution you'd like.

Describe alternatives you've considered.

Additional context

The "for_each" value depends on resource attributes that cannot be determined until apply

Description

Please provide a clear and concise description of the issue you are encountering and a reproduction of your configuration (see the examples/* directory for references that you can copy+paste and tailor to match your configs if you are unable to copy your exact configuration). The reproduction MUST be executable by running terraform init && terraform apply without any further changes.

If your request is for a new feature, please use the Feature request template.

  • βœ‹ I have searched the open/closed issues and my issue is not listed.

I tried looking through the solution on issue 59, but wasn't able to fully resolve it as it's the same, but a little different as well.

Follow up/similar to the following issue:
#59

⚠️ Note

Before you submit an issue, please perform the following first:

  1. Remove the local .terraform directory (! ONLY if state is stored remotely, which hopefully you are following that best practice!): rm -rf .terraform/
  2. Re-initialize the project root to pull down modules: terraform init
  3. Re-attempt your terraform plan or apply and check if the issue still persists

Versions

  • Module version [Required]: 2.10.12

  • Terraform version: 1.5.2

  • Provider version(s):

Reproduction Code [Required]:

resource "aws_vpc_endpoint_service" "this" {
  count = var.create && var.create_endpoint_service ? 1 : 0

  acceptance_required        = true
  network_load_balancer_arns = var.network_load_balancer_arns
  allowed_principals         = var.allowed_principals
  private_dns_name           = var.private_dns_name

  tags = merge({
    Name = format("%s-endpoint-service", var.name)
  })
}

module "r53_dns" {
  source  = "terraform-aws-modules/route53/aws//modules/zones"
  version = "~> 2.0"	

  zone_id = var.zone_id

  records_jsonencoded = jsonencode([
    {
      name = aws_vpc_endpoint_service.this[0].private_dns_name_configuration[0].name
      type = "TXT"
      ttl  = 1800
      records = [
        aws_vpc_endpoint_service.this[0].private_dns_name_configuration[0].value
      ]
    },
  ])
}

Steps to reproduce the behavior:

  1. Not using workspaces,
  2. Cleared local cache
  3. Run terraform init && terraform plan -out=tfplan

Expected behavior

  • Expect the r53 record to be able to be created from the created endoint resource.

Actual behavior

β”‚ Error: Invalid for_each argument
β”‚ 
β”‚   on .terraform/modules/private_link_host.private_svc_endpoint_dns_verification/modules/records/main.tf line 19, in resource "aws_route53_record" "this":
β”‚   19:   for_each = { for k, v in local.recordsets : k => v if var.create && (var.zone_id != null || var.zone_name != null) }
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ local.recordsets will be known only after apply
β”‚     β”‚ var.create is true
β”‚     β”‚ var.zone_id is "Z3RSZW2EMHYAKV"
β”‚     β”‚ var.zone_name is null
β”‚ 
β”‚ The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.
β”‚ 
β”‚ When working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.
β”‚ 
β”‚ Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge.

Terminal Output Screenshot(s)

Additional context

I have tried depends_on with many of the resources in there, but still met with the same error unfortunately.

DNS record recreated every time

Description

Using record module, terraform recreate every-time the record name
aws_route53_zone data seems responsible of that.
It seems that it retrieves value but for terraform are like new also if you do not changed anything.

As workaroud is it possible to add a variable for the zone_id so we can pass it to the module?

Remove non original vpc (cannot use vpc association)

Description

This module doesn't support Route53 Private Hosted Zone with VPC associations. Every new VPC accociation will impose new vpc be removed remove from Private hosted zone makign impossible to be used.

I know lifecycle in terraform does not support variables, probably a temporary workaround can be added like making 2 aws_route53_zone, one with:

 lifecycle {
    ignore_changes = [vpc]
  }

another without lifecycle, so it will be possible to use this module in this scenario.

There is something I missed ? Some workaround without changing module internal code ?

Versions

  • Module version [Required]: 2.9.0

  • Terraform version: v1.2.2

  • Provider version(s): 4.19.0

Reproduction Code [Required]

resource "aws_route53_zone" "example" {
  name = "example.com"

  vpc {
    vpc_id = "vpc-...1"
  }
}
resource "aws_route53_vpc_association_authorization" "example" {
  vpc_id  = "vpc-...2"
  zone_id = "..."
}

resource "aws_route53_zone_association" "example" {
  vpc_id  = "vpc-...2"
  zone_id = "..."
}

Steps to reproduce the behavior:

  1. apply aws_route53_zone resource
  2. apply association authorization
  3. apply association
  4. apply all or aws_route53_zone resource

terraform remove all associate vpc apart original one (vpc-...1)

Expected behavior

Associated Extra vpc will remain associated

Actual behavior

All vpc apart the original will be removed from hz

Add prevent_destroy to zone's module.

Is this feature available in the AWS provider for Terraform?

Yes, https://www.terraform.io/docs/language/meta-arguments/lifecycle.html

Is your request related to a problem? Please describe.

Accidental or malicious deletion of DNS records is one important cause of IT service unavailability. For instance, if a DNS record is deleted from a domain controller, users might not be able to log in or access the service. It would be safer if there was an option to enable the prevent_destroy option by default in the aws_route53_one resource

Describe the solution you'd like.

An option to enable the prevent_destroy option by default in the aws_route53_one resource

Describe alternatives you've considered.

Add to zone's module this option:

lifecycle {
    prevent_destroy = var.prevent_destroy
  }

Additional context

n/a

allow records with latency routing policy

Is your request related to a new offering from AWS?

This feature is available on the aws_route53_record resource.

Is your request related to a problem? Please describe.

It is not.

Describe the solution you'd like.

I would like to be able to create records featuring a latency policy using the terraform-aws-modules/route53/aws//modules/records module.

Describe alternatives you've considered.

I have considered using the resource directly instead of using the module.

Additional context

I have what I believe to be a working solution, and will be submitting a pull request here soon :)

Add mx and txt examples

Is your request related to a new offering from AWS?

Is this functionality available in the AWS provider for Terraform? See CHANGELOG.md, too.

  • Yes βœ…: please list the AWS provider version which introduced this functionality

Is your request related to a problem? Please describe.

I'm unable to get the correct formatting for multiple MX and TXT records

Describe the solution you'd like.

Please update the complete example to include samples with the correct formats for multiple records of these types.

Describe alternatives you've considered.

I tried adding set_identifiers to the records, but that didn't work.

Additional context

Error: Duplicate object key
β”‚
β”‚ on ../modules/records/main.tf line 7, in locals:
β”‚ 7: recordsets = { for rs in local.records : try(rs.key, join(" ", compact(["${rs.name} ${rs.type}", try(rs.set_identifier, "")]))) => rs }
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ rs.name is ""
β”‚ β”‚ rs.type is "TXT"
β”‚
β”‚ Two different items produced the key " TXT" in this 'for' expression. If duplicates are expected, use the ellipsis
β”‚ (...) after the value expression to enable grouping by key.
β•΅
β•·

The "for_each" value depends on resource attributes that cannot be determined until apply

Description

Hello. When using the latest module version and running the plan to create a record based on the value of a CloudFront distribution created using a for_each:

  source  = "terraform-aws-modules/route53/aws//modules/records"
  version = "2.3.0"

  …

  zone_id = local.dns_zone_id
  depends_on = [module.cloudfront]

  records = [
    {
      name = ""
      type = "A"
      alias = {
        name    = module.cloudfront.web.cloudfront_distribution_domain_name
        zone_id = module.cloudfront.web.cloudfront_distribution_hosted_zone_id
      }
    }
  ]

The plan fails with the following error when running locally or on Terraform Cloud:

Configuring remote state backend...
Initializing Terraform configuration...
β•·
β”‚ Error: Invalid for_each argument
β”‚
β”‚   on .terraform/modules/records/modules/records/main.tf line 32, in resource "aws_route53_record" "this":
β”‚   32:   for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : tomap({})
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ local.recordsets will be known only after apply
β”‚     β”‚ var.create is true
β”‚     β”‚ var.zone_id is "ZLHLLCNNHTTH8"
β”‚     β”‚ var.zone_name is null
β”‚
β”‚ The "for_each" value depends on resource attributes that cannot be
β”‚ determined until apply, so Terraform cannot predict how many instances will
β”‚ be created. To work around this, use the -target argument to first apply
β”‚ only the resources that the for_each depends on.

Versions

Terraform v1.0.8
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v3.61.0

Reproduction

Steps to reproduce the behavior:

  • Are you using workspaces?: Yes
  • Have you cleared the local cache: Yes and this error is even shows in TF Cloud.

Code Snippet to Reproduce

Additionally to the above code, this is the extra relevant part:

main.tf

module "cloudfront" {
  source = "./modules/aws-cloudfront"

  for_each = {
    for k, v in var.projects : k => v
    if v.cdn
  }

  …

varaibles.tf

variable "projects" {
  type        = map(map(string))
  default = {
    "web" = {
      name = "…",
      cdn  = true,
    },
  }
}

Expected behavior

The plan should end successfully.

Actual behavior

The error is shown in the "plan" state and thus the apply is impossible.

Terminal Output Screenshot(s)

image

Workaround

On local backend, the -target argument can be used to first plan and apply the dependencies. On Terraform Cloud there is the TF_CLI_ARGS_plan environment variable, which is supported since version 0.13, e.g.:
TF_CLI_ARGS_plan="-target=module.cloudfront"

Additional context

When first creating the AWS CloudFront dependency, then the records can be planned correctly, as the resources now exists. But running per parts is not ideal.

The error is about "local.recordsets will be known only after apply". I wonder if it is possible to have this refactor to avoid the for_each issue, or if this is a deeper rooted Terraform limitation?

recordsets = {
for rs in local.records :
join(" ", compact(["${rs.name} ${rs.type}", lookup(rs, "set_identifier", "")])) => merge(rs, {
records = jsonencode(try(rs.records, null))
})
}

Thanks.

Inconsistent conditional result types error in resource "aws_route53_record" / module records / terraform1.0.0

Description

After upgrading terraform from 0.14.5 to 1.0.0 the module stopped working correctly. It fails with the following error:

β”‚ Error: Inconsistent conditional result types
β”‚ 
β”‚   on .terraform/modules/aws_route53_records_zeronorthinternal_com/modules/records/main.tf line 19, in resource "aws_route53_record" "this":
β”‚   19:   for_each = var.create && (var.zone_id != null || var.zone_name != null) ? local.recordsets : tomap({})
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ local.recordsets is object with 8 attributes
β”‚ 
β”‚ The true result value has the wrong type: element types must all match for conversion to map.

⚠️ Note

Before you submit an issue, please perform the following first:

  1. Remove the local .terraform directory (! ONLY if state is stored remotely, which hopefully you are following that best practice!): rm -rf .terraform/
  2. Re-initialize the project root to pull down modules: terraform init
  3. Re-attempt your terraform plan or apply and check if the issue still persists

Versions

  • Terraform: 1.0.0
  • Provider(s):
    • hashicorp/aws v3.44.0
    • hashicorp/local v2.1.0
  • Module:
    • app.terraform.io/0-North/cloudwatch-sharing/aws - 1.0.0
    • terraform-aws-modules/notify-slack/aws - 4.15.0
    • terraform-aws-modules/lambda/aws - 1.47.0
    • terraform-aws-modules/route53/aws - 2.1.0

Reproduction

Steps to reproduce the behavior:

  1. Use the module with terraform 0.14.5
  2. have at least one AWS Route 53 zone defined in terraform-aws-modules/route53/aws//modules/zones module
  3. have a set of few different records - I got one MX, one A, two TXT, 4 CNAME
  4. apply the module to create resources
  5. upgrade terraform to the ver. 1.0.0
  6. apply the module again

Terraform workspaces are not used.

Local terraform cache was cleared.

Code Snippet to Reproduce

Expected behavior

Just be able to create/ update Route53 resources after upgrading terraform.

Actual behavior

It's not possible to use the module after upgrading terraform because it isn't able to run it successfully.

Terminal Output Screenshot(s)

Additional context

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.