AWS Route53 Terraform modules

May 1, 2026 ยท View on GitHub

Terraform modules which creates Route53 resources.

SWUbanner

Usage

Public Hosted Zone

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

  name    = "terraform-aws-modules-example.com"
  comment = "Public zone for terraform-aws-modules example"

  records = {
    s3 = {
      name = "s3-bucket-z1bkctxd74ezpe.terraform-aws-modules-example.com"
      type = "A"
      alias = {
        name    = "s3-website-eu-west-1.amazonaws.com"
        zone_id = "Z1BKCTXD74EZPE"
      }
    }
    mail = {
      full_name = "terraform-aws-modules-example.com"
      type = "MX"
      ttl  = 3600
      records = [
        "1 aspmx.l.google.com",
        "5 alt1.aspmx.l.google.com",
        "5 alt2.aspmx.l.google.com",
        "10 alt3.aspmx.l.google.com",
        "10 alt4.aspmx.l.google.com",
      ]
    }
    geo = {
      type           = "CNAME"
      ttl            = 5
      records        = ["europe.test.example.com."]
      set_identifier = "europe"
      geolocation_routing_policy = {
        continent = "EU"
      }
    }
    geoproximity-aws-region = {
      type           = "CNAME"
      ttl            = 5
      records        = ["us-east-1.test.example.com."]
      set_identifier = "us-east-1-region"
      geoproximity_routing_policy = {
        aws_region = "us-east-1"
        bias       = 0
      }
    }
    geoproximity-coordinates = {
      type           = "CNAME"
      ttl            = 5
      records        = ["nyc.test.example.com."]
      set_identifier = "nyc"
      geoproximity_routing_policy = {
        coordinates = [{
          latitude  = "40.71"
          longitude = "-74.01"
        }]
      }
    }
    cloudfront_ipv4 = {
      name = "cloudfront"
      type = "A"
      alias = {
        name    = "d3778kt32cqdww.cloudfront.net"
        zone_id = "EF3T6981F7M1"
      }
    }
    cloudfront_ipv6 = {
      name = "cloudfront"
      type = "AAAA"
      alias = {
        name    = "d3778kt32cqdww.cloudfront.net"
        zone_id = "EF3T6981F7M1"
      }
    }
    blue = {
      name           = "test"
      type           = "CNAME"
      ttl            = 5
      records        = ["test.example.com."]
      set_identifier = "test-primary"
      weighted_routing_policy = {
        weight = 90
      }
    }
    green = {
      name           = "test"
      type           = "CNAME"
      ttl            = 5
      records        = ["test2.example.com."]
      set_identifier = "test-secondary"
      weighted_routing_policy = {
        weight = 10
      }
    }
    failover-primary = {
      type            = "A"
      set_identifier  = "failover-primary"
      health_check_id = "d641c34c-a992-4edd-8a63-c540a4b18d0a"
      alias = {
        name    = "d3778kt32cqdww.cloudfront.net"
        zone_id = "EF3T6981F7M1"
      }
      failover_routing_policy = {
        type = "PRIMARY"
      }
    }
    failover-secondary = {
      type           = "A"
      set_identifier = "failover-secondary"
      alias = {
        name    = "s3-website-eu-west-1.amazonaws.com"
        zone_id = "Z1BKCTXD74EZPE"
      }
      failover_routing_policy = {
        type = "SECONDARY"
      }
    }
    latency-test = {
      type           = "A"
      set_identifier = "latency-test"
      alias = {
        name    = "d3778kt32cqdww.cloudfront.net"
        zone_id = "EF3T6981F7M1"
        evaluate_target_health = true
      }
      latency_routing_policy = {
        region = "eu-west-1"
      }
    }
  }

  tags = {
    Environment = "example"
    Project     = "terraform-aws-route53"
  }
}

Private Hosted Zone

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

  name    = "terraform-aws-modules-example.com"
  comment = "Private zone for terraform-aws-modules example"

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

  vpc = {
    one = {
      vpc_id     = "vpc-1234556abcdef"
      vpc_region = "eu-west-1"
    }
  }

  tags = {
    Environment = "example"
    Project     = "terraform-aws-route53"
  }
}

Cross Account Zone Association

Note

Association (aws_route53_zone_association) must be performed by the account that owns the VPC.

Association authorization (aws_route53_vpc_association_authorization) must be performed by the account that owns the zone.

Hence why the aws_route53_zone_association resource is outside the scope of the module, but the authorization (aws_route53_vpc_association_authorization) is inside the scope of the module.

Caution

Since Terraform does not support variables in the lifecycle_block, the ignore_vpc variable is used to switch between two resources: aws_route53_zone.this and aws_route53_zone.ignore_vpc. Therefore, if you changes this value after resources have been created, Terraform will attempt to destroy and recreate the Route53 zone which is usually not desired. To avoid this, you will need to perform the appropriate state move commands/blocks between the two resources.

Changing from ignore_vpc = false to ignore_vpc = true:

terraform state mv 'module.zone.aws_route53_zone.this[0]' 'module.zone.aws_route53_zone.ignore_vpc[0]'

Or using a state block:

moved {
 from = module.zone.aws_route53_zone.this[0]
 to   = module.zone.aws_route53_zone.ignore_vpc[0]
}

Changing from ignore_vpc = true to ignore_vpc = false:

terraform state mv 'module.zone.aws_route53_zone.ignore_vpc[0]' 'module.zone.aws_route53_zone.this[0]'

Or using a state block:

moved {
 from = module.zone.aws_route53_zone.ignore_vpc[0]
 to   = module.zone.aws_route53_zone.this[0]
}
module "zone" {
  source = "terraform-aws-modules/route53/aws"

  name    = "terraform-aws-modules-example.com"
  comment = "Private zone for terraform-aws-modules example"

  # Ignore VPC after creation to avoid disruptive diff with associations
  ignore_vpc = true
  vpc = {
    default = {
      vpc_id     = "vpc-1234556abcdef"
      vpc_region = "eu-west-1"
    }
  }

  vpc_association_authorizations = {
    external = {
      vpc_id     = "vpc-987564fedcba"
      vpc_region = "eu-west-1"
    }
    external_region = {
      vpc_id     = "vpc-1a2b3c4d56e7f8"
      vpc_region = "us-east-1"
    }
  }

  tags = {
    Environment = "example"
    Project     = "terraform-aws-route53"
  }
}

Sub-Modules

The following independent sub-modules are available:

See the respective module directories for examples and documentation.

Examples

Requirements

NameVersion
terraform>= 1.5.7
aws>= 6.28

Providers

NameVersion
aws>= 6.28

Modules

NameSourceVersion
route53_dnssec_kmsterraform-aws-modules/kms/aws4.0.0

Resources

NameType
aws_route53_hosted_zone_dnssec.thisresource
aws_route53_key_signing_key.thisresource
aws_route53_record.thisresource
aws_route53_vpc_association_authorization.thisresource
aws_route53_zone.ignore_vpcresource
aws_route53_zone.thisresource
aws_route53_zone.thisdata source

Inputs

NameDescriptionTypeDefaultRequired
commentA comment for the hosted zone. Defaults to Managed by Terraformstringnullno
createWhether to create Route53 zonebooltrueno
create_dnssec_kms_keyWhether to create a KMS key for DNSSEC signingbooltrueno
create_zoneDetermines whether to create the Route53 zone or lookup an existing zonebooltrueno
delegation_set_idThe ID of the reusable delegation set whose NS records you want to assign to the hosted zone. Conflicts with vpc as delegation sets can only be used for public zonesstringnullno
dnssec_key_signing_key_nameName of the Route 53 key signing key (KSK). When null, the hosted zone name is used. Set this to match an existing KSK when importing or adopting DNSSEC without recreating the keystringnullno
dnssec_kms_key_aliasesA list of aliases to create. Note - due to the use of toset(), values must be static strings and not computed valueslist(string)[]no
dnssec_kms_key_arnThe ARN of the KMS key to use for DNSSEC signing. Required when create_dnssec_kms_key is falsestringnullno
dnssec_kms_key_descriptionThe description of the key as viewed in AWS consolestring"Route53 DNSSEC KMS Key"no
dnssec_kms_key_tagsAdditional tags to apply to the KMS key created for DNSSEC signingmap(string){}no
enable_accelerated_recoveryWhether to enable Route 53 Accelerated Recovery for the public hosted zone. When enabled, provides a 60-minute RTO for resuming DNS record management if the US East (N. Virginia) Region becomes unavailable. Only applies to public hosted zonesboolnullno
enable_dnssecWhether to enable DNSSEC for the Route53 zoneboolfalseno
force_destroyWhether to destroy all records (possibly managed outside of Terraform) in the zone when destroying the zoneboolnullno
ignore_vpcDetermines whether to ignore VPC association changes after creation to avoid disruptive diffs when using aws_route53_zone_association resource(s). Changing is a destructive action; users should be prepared to use Terraform state move commands/blocks when changing this valueboolfalseno
nameThis is the name of the hosted zonestring""no
private_zoneWhether the hosted zone is private. Only applicable when create_zone = falseboolfalseno
recordsA map of Route53 records to create in the zone. The key can be used as the subdomain name, or name can be used to specify the full name
map(object({
alias = optional(object({
evaluate_target_health = optional(bool, false)
name = string
zone_id = string
}))
allow_overwrite = optional(bool)
cidr_routing_policy = optional(object({
collection_id = string
location_name = string
}))
failover_routing_policy = optional(object({
type = string
}))
geolocation_routing_policy = optional(object({
continent = optional(string)
country = optional(string)
subdivision = optional(string)
}))
geoproximity_routing_policy = optional(object({
aws_region = optional(string)
bias = optional(number)
coordinates = optional(list(object({
latitude = number
longitude = number
})))
local_zone_group = optional(string)
}))
health_check_id = optional(string)
latency_routing_policy = optional(object({
region = string
}))
multivalue_answer_routing_policy = optional(bool)
name = optional(string)
full_name = optional(string)
records = optional(list(string))
set_identifier = optional(string)
ttl = optional(number)
type = string
weighted_routing_policy = optional(object({
weight = number
}))
timeouts = optional(object({
create = optional(string)
update = optional(string)
delete = optional(string)
}))
}))
{}no
tagsTags added to all zones. Will take precedence over tags from the 'zones' variablemap(string){}no
timeoutsTimeouts for the Route53 zone operations
object({
create = optional(string)
update = optional(string)
delete = optional(string)
})
nullno
vpcConfiguration block(s) specifying VPC(s) to associate with a private hosted zone. Conflicts with the delegation_set_id argument in this resource and any aws_route53_zone_association resource specifying the same zone ID
map(object({
vpc_id = string
vpc_region = optional(string)
}))
nullno
vpc_association_authorizationsA map of VPC association authorizations to create for the Route53 zone
map(object({
vpc_id = string
vpc_region = optional(string)
}))
nullno
vpc_idThe ID of the VPC associated with the existing hosted zone. Only applicable when create_zone = falsestringnullno

Outputs

NameDescription
arnZone ARN of Route53 zone
dnssec_kms_key_arnThe Amazon Resource Name (ARN) of the key
dnssec_kms_key_idThe globally unique identifier for the key
dnssec_kms_key_policyThe IAM resource policy set on the key
dnssec_kms_key_regionThe region for the key
dnssec_signing_key_digest_valueA cryptographic digest of a DNSKEY resource record (RR). DNSKEY records are used to publish the public key that resolvers can use to verify DNSSEC signatures that are used to secure certain kinds of information provided by the DNS system
dnssec_signing_key_dnskey_recordA string that represents a DNSKEY record
dnssec_signing_key_ds_recordA string that represents a delegation signer (DS) record
dnssec_signing_key_idRoute 53 Hosted Zone identifier and KMS Key identifier, separated by a comma (,)
dnssec_signing_key_public_keyThe public key, represented as a Base64 encoding, as required by RFC-4034 Page 5
dnssec_signing_key_tagAn integer used to identify the DNSSEC record for the domain name. The process used to calculate the value is described in RFC-4034 Appendix B
idZone ID of Route53 zone
nameName of Route53 zone
name_serversName servers of Route53 zone
primary_name_serverThe Route 53 name server that created the SOA record.
recordsRecords created in the Route53 zone

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