diff --git a/.github/labeler.yaml b/.github/labeler.yaml
index 3e337f8..0483802 100644
--- a/.github/labeler.yaml
+++ b/.github/labeler.yaml
@@ -17,6 +17,9 @@
":floppy_disk: public-zone":
- modules/public-zone/**/*
+":floppy_disk: registered-domain":
+- modules/registered-domain/**/*
+
":floppy_disk: resolver-inbound-endpoint":
- modules/resolver-inbound-endpoint/**/*
diff --git a/.github/labels.yaml b/.github/labels.yaml
index 6666889..81207a8 100644
--- a/.github/labels.yaml
+++ b/.github/labels.yaml
@@ -58,6 +58,9 @@
- color: "fbca04"
description: "This issue or pull request is related to public-zone module."
name: ":floppy_disk: public-zone"
+- color: "fbca04"
+ description: "This issue or pull request is related to registered-domain module."
+ name: ":floppy_disk: registered-domain"
- color: "fbca04"
description: "This issue or pull request is related to resolver-inbound-endpoint module."
name: ":floppy_disk: resolver-inbound-endpoint"
diff --git a/README.md b/README.md
index 5517960..65e2689 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ Terraform module which creates Route53 related resources on AWS.
- [private-ca-issued-cert](./modules/private-ca-issued-cert)
- [private-zone](./modules/private-zone)
- [public-zone](./modules/public-zone)
+- [registered-domain](./modules/registered-domain)
- [resolver-inbound-endpoint](./modules/resolver-inbound-endpoint)
- [resolver-query-logging](./modules/resolver-query-logging)
@@ -21,6 +22,8 @@ Terraform module which creates Route53 related resources on AWS.
Terraform Modules from [this package](https://github.com/tedilabs/terraform-aws-domain) were written to manage the following AWS Services with Terraform.
- **Route53**
+ - Registrar
+ - Registered Domain
- Hosted Zone
- Public Hosted Zone
- Private Hosted Zone
diff --git a/modules/registered-domain/README.md b/modules/registered-domain/README.md
new file mode 100644
index 0000000..b50fdc7
--- /dev/null
+++ b/modules/registered-domain/README.md
@@ -0,0 +1,72 @@
+# registered-domain
+
+This module creates following resources.
+
+- `aws_route53domains_registered_domain`
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.6 |
+| [aws](#requirement\_aws) | >= 5.41 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 5.47.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_route53domains_registered_domain.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53domains_registered_domain) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [name](#input\_name) | (Required) The name of the registred domain. | `string` | n/a | yes |
+| [admin\_contact](#input\_admin\_contact) | (Optional) The configuration of the domain administrative contact. `admin_contact` as defined below.
(Optional) `type` - Whether the contact is a person, company, association, or public organization. Valid values are `PERSON`, `COMPANY`, `ASSOCIATION`, or `PUBLIC_BODY`, `RESELLER`. Defaults to `PERSON`.
(Optional) `organization` - The name of the organization for contact types other than `PERSON`.
(Optional) `first_name` - First name of contact.
(Optional) `last_name` - Last name of contact.
(Optional) `email` - The email address of the contact.
(Optional) `phone` - The phone number of the contact. Phone number must be specified in the format `+[country dialing code].[number including any area code]`.
(Optional) `fax` - The fax number of the contact. Fax number must be specified in the format `+[country dialing code].[number including any area code]`.
(Optional) `country_code` - The ISO-3166 two-letter country code for the contact address.
(Optional) `state` - The state or province of the contact's city.
(Optional) `city` - The city of the contact's address.
(Optional) `address_line_1` - The first line of the contact address.
(Optional) `address_line_2` - The second line of the contact address, if any.
(Optional) `postal_code` - The zip or postal code of the contact's address.
(Optional) `extra_params` - A key-value map of parameters required by certain top-level domains.
(Optional) `privacy_protection_enabled` - Whether domain contact information is concealed from WHOIS queries. Defaults to `true`. |
object({| `{}` | no | +| [auto\_renew\_enabled](#input\_auto\_renew\_enabled) | (Optional) Whether the domain registration is set to renew automatically. Defaults to `true`. | `bool` | `true` | no | +| [billing\_contact](#input\_billing\_contact) | (Optional) The configuration of the domain billing contact. `billing_contact` as defined below.
type = optional(string, "PERSON")
organization = optional(string)
first_name = optional(string)
last_name = optional(string)
email = optional(string)
phone = optional(string)
fax = optional(string)
country_code = optional(string)
state = optional(string)
city = optional(string)
address_line_1 = optional(string)
address_line_2 = optional(string)
postal_code = optional(string)
extra_params = optional(map(string), {})
privacy_protection_enabled = optional(bool, true)
})
object({| `{}` | no | +| [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | +| [name\_servers](#input\_name\_servers) | (Optional) A set of fully qualified host name of name servers for the registered domain. | `set(string)` | `[]` | no | +| [registrant\_contact](#input\_registrant\_contact) | (Optional) The configuration of the domain registrant contact. `registrant_contact` as defined below.
type = optional(string, "PERSON")
organization = optional(string)
first_name = optional(string)
last_name = optional(string)
email = optional(string)
phone = optional(string)
fax = optional(string)
country_code = optional(string)
state = optional(string)
city = optional(string)
address_line_1 = optional(string)
address_line_2 = optional(string)
postal_code = optional(string)
extra_params = optional(map(string), {})
privacy_protection_enabled = optional(bool, true)
})
object({| `{}` | no | +| [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | +| [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | +| [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | +| [technical\_contact](#input\_technical\_contact) | (Optional) The configuration of the domain technical contact. `technical_contact` as defined below.
type = optional(string, "PERSON")
organization = optional(string)
first_name = optional(string)
last_name = optional(string)
email = optional(string)
phone = optional(string)
fax = optional(string)
country_code = optional(string)
state = optional(string)
city = optional(string)
address_line_1 = optional(string)
address_line_2 = optional(string)
postal_code = optional(string)
extra_params = optional(map(string), {})
privacy_protection_enabled = optional(bool, true)
})
object({| `{}` | no | +| [transfer\_lock\_enabled](#input\_transfer\_lock\_enabled) | (Optional) Whether the domain is locked for transfer. Defaults to `true`. | `bool` | `true` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [abuse\_contact](#output\_abuse\_contact) | The contact informations to report incorrect contact information for a domain, to report that the domain is being used to send spam, to report that someone is cybersquatting on a domain name, or report some other type of abuse. | +| [admin\_contact](#output\_admin\_contact) | The configuration of the domain administrative contact. | +| [auto\_renew\_enabled](#output\_auto\_renew\_enabled) | Whether the domain registration is set to renew automatically. | +| [billing\_contact](#output\_billing\_contact) | The configuration of the domain billing contact. | +| [created\_at](#output\_created\_at) | The date when the domain was created as found in the response to a WHOIS query. | +| [expired\_at](#output\_expired\_at) | The date when the registration for the domain is set to expire. | +| [id](#output\_id) | The ID of the registered domain. | +| [name](#output\_name) | The name of the registered domain. | +| [name\_servers](#output\_name\_servers) | A list of name servers for the registered domain. | +| [registrant\_contact](#output\_registrant\_contact) | The configuration of the domain registrant contact. | +| [registrar](#output\_registrar) | The informations about the registrar for the domain. | +| [reseller](#output\_reseller) | Reseller of the domain. | +| [status\_codes](#output\_status\_codes) | A list of domain name status codes. | +| [technical\_contact](#output\_technical\_contact) | The configuration of the domain technical contact. | +| [transfer\_lock\_enabled](#output\_transfer\_lock\_enabled) | Whether the domain is locked for transfer. | +| [updated\_at](#output\_updated\_at) | The last updated date of the domain as found in the response to a WHOIS query. | +| [whois\_server](#output\_whois\_server) | The fully qualified name of the WHOIS server that can answer the WHOIS query for the domain. | + diff --git a/modules/registered-domain/main.tf b/modules/registered-domain/main.tf new file mode 100644 index 0000000..cc9240e --- /dev/null +++ b/modules/registered-domain/main.tf @@ -0,0 +1,130 @@ +locals { + metadata = { + package = "terraform-aws-domain" + version = trimspace(file("${path.module}/../../VERSION")) + module = basename(path.module) + name = var.name + } + module_tags = var.module_tags_enabled ? { + "module.terraform.io/package" = local.metadata.package + "module.terraform.io/version" = local.metadata.version + "module.terraform.io/name" = local.metadata.module + "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" + "module.terraform.io/instance" = local.metadata.name + } : {} +} + + +################################################### +# Registred Domain in Route53 Registry +################################################### + +# INFO: Not supported attributes +# - `name_server.glue_ips` +resource "aws_route53domains_registered_domain" "this" { + domain_name = var.name + + auto_renew = var.auto_renew_enabled + transfer_lock = var.transfer_lock_enabled + + + ## Name Servers + dynamic "name_server" { + for_each = var.name_servers + + content { + name = name_server.value + } + } + + + ## Privacy Protection + admin_privacy = var.admin_contact.privacy_protection_enabled + # billing_privacy = var.privacy_protection_enabled + registrant_privacy = var.registrant_contact.privacy_protection_enabled + tech_privacy = var.technical_contact.privacy_protection_enabled + + + ## Contacts + admin_contact { + contact_type = var.admin_contact.type + organization_name = var.admin_contact.organization + first_name = var.admin_contact.first_name + last_name = var.admin_contact.last_name + email = var.admin_contact.email + phone_number = var.admin_contact.phone + fax = var.admin_contact.fax + + country_code = var.admin_contact.country_code + state = var.admin_contact.state + city = var.admin_contact.city + address_line_1 = var.admin_contact.address_line_1 + address_line_2 = var.admin_contact.address_line_2 + zip_code = var.admin_contact.postal_code + + extra_params = var.admin_contact.extra_params + } + billing_contact { + contact_type = var.billing_contact.type + organization_name = var.billing_contact.organization + first_name = var.billing_contact.first_name + last_name = var.billing_contact.last_name + email = var.billing_contact.email + phone_number = var.billing_contact.phone + fax = var.billing_contact.fax + + country_code = var.billing_contact.country_code + state = var.billing_contact.state + city = var.billing_contact.city + address_line_1 = var.billing_contact.address_line_1 + address_line_2 = var.billing_contact.address_line_2 + zip_code = var.billing_contact.postal_code + + extra_params = var.admin_contact.extra_params + } + registrant_contact { + contact_type = var.registrant_contact.type + organization_name = var.registrant_contact.organization + first_name = var.registrant_contact.first_name + last_name = var.registrant_contact.last_name + email = var.registrant_contact.email + phone_number = var.registrant_contact.phone + fax = var.registrant_contact.fax + + country_code = var.registrant_contact.country_code + state = var.registrant_contact.state + city = var.registrant_contact.city + address_line_1 = var.registrant_contact.address_line_1 + address_line_2 = var.registrant_contact.address_line_2 + zip_code = var.registrant_contact.postal_code + + extra_params = var.admin_contact.extra_params + } + tech_contact { + contact_type = var.technical_contact.type + organization_name = var.technical_contact.organization + first_name = var.technical_contact.first_name + last_name = var.technical_contact.last_name + email = var.technical_contact.email + phone_number = var.technical_contact.phone + fax = var.technical_contact.fax + + country_code = var.technical_contact.country_code + state = var.technical_contact.state + city = var.technical_contact.city + address_line_1 = var.technical_contact.address_line_1 + address_line_2 = var.technical_contact.address_line_2 + zip_code = var.technical_contact.postal_code + + extra_params = var.admin_contact.extra_params + } + + + tags = merge( + { + "Name" = local.metadata.name + }, + local.module_tags, + var.tags, + ) +} diff --git a/modules/registered-domain/outputs.tf b/modules/registered-domain/outputs.tf new file mode 100644 index 0000000..229051d --- /dev/null +++ b/modules/registered-domain/outputs.tf @@ -0,0 +1,170 @@ +output "id" { + description = "The ID of the registered domain." + value = aws_route53domains_registered_domain.this.id +} + +output "name" { + description = "The name of the registered domain." + value = aws_route53domains_registered_domain.this.domain_name +} + +output "auto_renew_enabled" { + description = "Whether the domain registration is set to renew automatically." + value = aws_route53domains_registered_domain.this.auto_renew +} + +output "transfer_lock_enabled" { + description = "Whether the domain is locked for transfer." + value = aws_route53domains_registered_domain.this.transfer_lock +} + +output "name_servers" { + description = "A list of name servers for the registered domain." + value = aws_route53domains_registered_domain.this.name_server[*].name +} + +output "admin_contact" { + description = "The configuration of the domain administrative contact." + value = { + type = one(aws_route53domains_registered_domain.this.admin_contact[*].contact_type) + organization = one(aws_route53domains_registered_domain.this.admin_contact[*].organization_name) + first_name = one(aws_route53domains_registered_domain.this.admin_contact[*].first_name) + last_name = one(aws_route53domains_registered_domain.this.admin_contact[*].last_name) + email = one(aws_route53domains_registered_domain.this.admin_contact[*].email) + phone = one(aws_route53domains_registered_domain.this.admin_contact[*].phone_number) + fax = one(aws_route53domains_registered_domain.this.admin_contact[*].fax) + + country_code = one(aws_route53domains_registered_domain.this.admin_contact[*].country_code) + state = one(aws_route53domains_registered_domain.this.admin_contact[*].state) + city = one(aws_route53domains_registered_domain.this.admin_contact[*].city) + address_line_1 = one(aws_route53domains_registered_domain.this.admin_contact[*].address_line_1) + address_line_2 = one(aws_route53domains_registered_domain.this.admin_contact[*].address_line_2) + postal_code = one(aws_route53domains_registered_domain.this.admin_contact[*].zip_code) + + extra_prams = one(aws_route53domains_registered_domain.this.admin_contact[*].extra_params) + privacy_protection_enabled = aws_route53domains_registered_domain.this.admin_privacy + } +} + +output "billing_contact" { + description = "The configuration of the domain billing contact." + value = { + type = one(aws_route53domains_registered_domain.this.billing_contact[*].contact_type) + organization = one(aws_route53domains_registered_domain.this.billing_contact[*].organization_name) + first_name = one(aws_route53domains_registered_domain.this.billing_contact[*].first_name) + last_name = one(aws_route53domains_registered_domain.this.billing_contact[*].last_name) + email = one(aws_route53domains_registered_domain.this.billing_contact[*].email) + phone = one(aws_route53domains_registered_domain.this.billing_contact[*].phone_number) + fax = one(aws_route53domains_registered_domain.this.billing_contact[*].fax) + + country_code = one(aws_route53domains_registered_domain.this.billing_contact[*].country_code) + state = one(aws_route53domains_registered_domain.this.billing_contact[*].state) + city = one(aws_route53domains_registered_domain.this.billing_contact[*].city) + address_line_1 = one(aws_route53domains_registered_domain.this.billing_contact[*].address_line_1) + address_line_2 = one(aws_route53domains_registered_domain.this.billing_contact[*].address_line_2) + postal_code = one(aws_route53domains_registered_domain.this.billing_contact[*].zip_code) + + extra_prams = one(aws_route53domains_registered_domain.this.billing_contact[*].extra_params) + privacy_protection_enabled = aws_route53domains_registered_domain.this.billing_privacy + } +} + +output "registrant_contact" { + description = "The configuration of the domain registrant contact." + value = { + type = one(aws_route53domains_registered_domain.this.registrant_contact[*].contact_type) + organization = one(aws_route53domains_registered_domain.this.registrant_contact[*].organization_name) + first_name = one(aws_route53domains_registered_domain.this.registrant_contact[*].first_name) + last_name = one(aws_route53domains_registered_domain.this.registrant_contact[*].last_name) + email = one(aws_route53domains_registered_domain.this.registrant_contact[*].email) + phone = one(aws_route53domains_registered_domain.this.registrant_contact[*].phone_number) + fax = one(aws_route53domains_registered_domain.this.registrant_contact[*].fax) + + country_code = one(aws_route53domains_registered_domain.this.registrant_contact[*].country_code) + state = one(aws_route53domains_registered_domain.this.registrant_contact[*].state) + city = one(aws_route53domains_registered_domain.this.registrant_contact[*].city) + address_line_1 = one(aws_route53domains_registered_domain.this.registrant_contact[*].address_line_1) + address_line_2 = one(aws_route53domains_registered_domain.this.registrant_contact[*].address_line_2) + postal_code = one(aws_route53domains_registered_domain.this.registrant_contact[*].zip_code) + + extra_prams = one(aws_route53domains_registered_domain.this.registrant_contact[*].extra_params) + privacy_protection_enabled = aws_route53domains_registered_domain.this.registrant_privacy + } +} + +output "technical_contact" { + description = "The configuration of the domain technical contact." + value = { + type = one(aws_route53domains_registered_domain.this.tech_contact[*].contact_type) + organization = one(aws_route53domains_registered_domain.this.tech_contact[*].organization_name) + first_name = one(aws_route53domains_registered_domain.this.tech_contact[*].first_name) + last_name = one(aws_route53domains_registered_domain.this.tech_contact[*].last_name) + email = one(aws_route53domains_registered_domain.this.tech_contact[*].email) + phone = one(aws_route53domains_registered_domain.this.tech_contact[*].phone_number) + fax = one(aws_route53domains_registered_domain.this.tech_contact[*].fax) + + country_code = one(aws_route53domains_registered_domain.this.tech_contact[*].country_code) + state = one(aws_route53domains_registered_domain.this.tech_contact[*].state) + city = one(aws_route53domains_registered_domain.this.tech_contact[*].city) + address_line_1 = one(aws_route53domains_registered_domain.this.tech_contact[*].address_line_1) + address_line_2 = one(aws_route53domains_registered_domain.this.tech_contact[*].address_line_2) + postal_code = one(aws_route53domains_registered_domain.this.tech_contact[*].zip_code) + + extra_prams = one(aws_route53domains_registered_domain.this.tech_contact[*].extra_params) + privacy_protection_enabled = aws_route53domains_registered_domain.this.tech_privacy + } +} + +output "abuse_contact" { + description = "The contact informations to report incorrect contact information for a domain, to report that the domain is being used to send spam, to report that someone is cybersquatting on a domain name, or report some other type of abuse." + value = { + email = aws_route53domains_registered_domain.this.abuse_contact_email + phoen = aws_route53domains_registered_domain.this.abuse_contact_phone + } +} + +output "registrar" { + description = "The informations about the registrar for the domain." + value = { + name = aws_route53domains_registered_domain.this.registrar_name + url = aws_route53domains_registered_domain.this.registrar_url + } +} + +output "reseller" { + description = "Reseller of the domain." + value = aws_route53domains_registered_domain.this.reseller +} + +output "whois_server" { + description = "The fully qualified name of the WHOIS server that can answer the WHOIS query for the domain." + value = aws_route53domains_registered_domain.this.whois_server +} + +output "status_codes" { + description = "A list of domain name status codes." + value = aws_route53domains_registered_domain.this.status_list +} + +output "created_at" { + description = "The date when the domain was created as found in the response to a WHOIS query." + value = aws_route53domains_registered_domain.this.creation_date +} + +output "expired_at" { + description = "The date when the registration for the domain is set to expire." + value = aws_route53domains_registered_domain.this.expiration_date +} + +output "updated_at" { + description = "The last updated date of the domain as found in the response to a WHOIS query." + value = aws_route53domains_registered_domain.this.updated_date +} + +# output "debug" { +# value = { +# for k, v in aws_route53domains_registered_domain.this : +# k => v +# if !contains(["id", "domain_name", "tags", "tags_all", "auto_renew", "transfer_lock", "timeouts", "creation_date", "expiration_date", "updated_date", "registrar_name", "registrar_url", "whois_server", "reseller", "abuse_contact_email", "abuse_contact_phone", "admin_contact", "registrant_contact", "tech_contact", "admin_privacy", "registrant_privacy", "tech_privacy", "billing_contact", "billing_privacy", "status_list"], k) +# } +# } diff --git a/modules/registered-domain/resource-group.tf b/modules/registered-domain/resource-group.tf new file mode 100644 index 0000000..7487ba0 --- /dev/null +++ b/modules/registered-domain/resource-group.tf @@ -0,0 +1,31 @@ +locals { + resource_group_name = (var.resource_group_name != "" + ? var.resource_group_name + : join(".", [ + local.metadata.package, + local.metadata.module, + replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), + ]) + ) +} + + +module "resource_group" { + source = "tedilabs/misc/aws//modules/resource-group" + version = "~> 0.10.0" + + count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 + + name = local.resource_group_name + description = var.resource_group_description + + query = { + resource_tags = local.module_tags + } + + module_tags_enabled = false + tags = merge( + local.module_tags, + var.tags, + ) +} diff --git a/modules/registered-domain/variables.tf b/modules/registered-domain/variables.tf new file mode 100644 index 0000000..8f651fd --- /dev/null +++ b/modules/registered-domain/variables.tf @@ -0,0 +1,368 @@ +variable "name" { + description = "(Required) The name of the registred domain." + type = string + nullable = false +} + +variable "auto_renew_enabled" { + description = "(Optional) Whether the domain registration is set to renew automatically. Defaults to `true`." + type = bool + default = true + nullable = false +} + +variable "transfer_lock_enabled" { + description = "(Optional) Whether the domain is locked for transfer. Defaults to `true`." + type = bool + default = true + nullable = false +} + +variable "name_servers" { + description = <
type = optional(string, "PERSON")
organization = optional(string)
first_name = optional(string)
last_name = optional(string)
email = optional(string)
phone = optional(string)
fax = optional(string)
country_code = optional(string)
state = optional(string)
city = optional(string)
address_line_1 = optional(string)
address_line_2 = optional(string)
postal_code = optional(string)
extra_params = optional(map(string), {})
privacy_protection_enabled = optional(bool, true)
})