diff --git a/terraform/README.md b/terraform/README.md index 4c38d3b..e76c83e 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -130,7 +130,9 @@ If everything looks good, answer `yes` and wait for the new infrastructure to be ## Providers -No providers. +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 3.100.0 | ## Modules @@ -142,7 +144,16 @@ No providers. ## Resources -No resources. +| Name | Type | +|------|------| +| [azurerm_private_dns_a_record.private_link](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_a_record) | resource | +| [azurerm_private_dns_zone.private_link](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone) | resource | +| [azurerm_private_dns_zone_virtual_network_link.private_link](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone_virtual_network_link) | resource | +| [azurerm_private_endpoint.default](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource | +| [azurerm_subnet.private_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | +| [azurerm_subnet_route_table_association.private_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_route_table_association) | resource | +| [azurerm_route_table.private_endpoints](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/route_table) | data source | +| [azurerm_virtual_network.private_endpoints](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network) | data source | ## Inputs @@ -182,6 +193,7 @@ No resources. | [key\_vault\_access\_ipv4](#input\_key\_vault\_access\_ipv4) | List of IPv4 Addresses that are permitted to access the Key Vault | `list(string)` | n/a | yes | | [monitor\_email\_receivers](#input\_monitor\_email\_receivers) | A list of email addresses that should be notified by monitoring alerts | `list(string)` | n/a | yes | | [monitor\_endpoint\_healthcheck](#input\_monitor\_endpoint\_healthcheck) | Specify a route that should be monitored for a 200 OK status | `string` | n/a | yes | +| [private\_endpoint\_configurations](#input\_private\_endpoint\_configurations) | Map of private endpoint configurations, specifying the VNet name/resource-group and a new subnet CIDR. A subnet, private endpoint and DNS zone will be created within the specified VNet.
{
endpoint-name = {
vnet\_name: The Name of the VNet to create the private endpoint resources
vnet\_resource\_group\_name: The Name of the resource group containing the VNet
subnet\_cidr: The CIDR of the Private Endpoint subnet to be created
subresource\_name: The type of resource you are targeting (e.g. sqlServer)
target\_resource\_id: The Resource ID for the target resource you are trying to connect to
create\_private\_dns\_zone: Do you want to automatically create the Private DNS Zone?
private\_dns\_hostname: The hostname to use for the Private DNS Zone
subnet\_route\_table\_name: The Route Table ID to associate the subnet with (Optional)
}
} |
map(object({
vnet_name = string
vnet_resource_group_name = string
subnet_cidr = string
subresource_name = string
target_resource_id = string
create_private_dns_zone = optional(bool, true)
private_dns_hostname = string
subnet_route_table_name = optional(string, null)
}))
| `{}` | no | | [project\_name](#input\_project\_name) | Project name. Will be used along with `environment` as a prefix for all resources. | `string` | n/a | yes | | [registry\_admin\_enabled](#input\_registry\_admin\_enabled) | Do you want to enable access key based authentication for your Container Registry? | `bool` | `true` | no | | [registry\_managed\_identity\_assign\_role](#input\_registry\_managed\_identity\_assign\_role) | Assign the 'AcrPull' Role to the Container App User-Assigned Managed Identity. Note: If you do not have 'Microsoft.Authorization/roleAssignments/write' permission, you will need to manually assign the 'AcrPull' Role to the identity | `bool` | `false` | no | diff --git a/terraform/data.tf b/terraform/data.tf new file mode 100644 index 0000000..9591654 --- /dev/null +++ b/terraform/data.tf @@ -0,0 +1,15 @@ +data "azurerm_virtual_network" "private_endpoints" { + for_each = local.private_endpoint_configurations + + name = each.value["vnet_name"] + resource_group_name = each.value["vnet_resource_group_name"] +} + +data "azurerm_route_table" "private_endpoints" { + for_each = { + for k, v in local.private_endpoint_configurations : k => v if v["subnet_route_table_name"] != null + } + + name = each.value["subnet_route_table_name"] + resource_group_name = each.value["vnet_resource_group_name"] +} diff --git a/terraform/locals.tf b/terraform/locals.tf index c47ffcb..a70d46f 100644 --- a/terraform/locals.tf +++ b/terraform/locals.tf @@ -44,4 +44,7 @@ locals { statuscake_contact_group_name = var.statuscake_contact_group_name statuscake_contact_group_integrations = var.statuscake_contact_group_integrations statuscake_contact_group_email_addresses = var.statuscake_contact_group_email_addresses + + resource_prefix = "${local.environment}${local.project_name}" + private_endpoint_configurations = var.private_endpoint_configurations } diff --git a/terraform/private-endpoint.tf b/terraform/private-endpoint.tf new file mode 100644 index 0000000..3c0cb08 --- /dev/null +++ b/terraform/private-endpoint.tf @@ -0,0 +1,76 @@ +resource "azurerm_subnet" "private_endpoint" { + for_each = local.private_endpoint_configurations + + name = lower("${local.resource_prefix}-${each.value.subresource_name}privateendpoint") + virtual_network_name = "${local.resource_prefix}default" + resource_group_name = local.resource_prefix + address_prefixes = [each.value["subnet_cidr"]] + private_endpoint_network_policies_enabled = false +} + +resource "azurerm_subnet_route_table_association" "private_endpoint" { + for_each = { + for k, v in local.private_endpoint_configurations : k => v if v["subnet_route_table_name"] != null + } + + subnet_id = azurerm_subnet.private_endpoint[each.key].id + route_table_id = data.azurerm_route_table.private_endpoints[each.key].id +} + +resource "azurerm_private_endpoint" "default" { + for_each = local.private_endpoint_configurations + + name = "${each.value.vnet_resource_group_name}.${azurerm_subnet.private_endpoint[each.key].name}" + location = data.azurerm_virtual_network.private_endpoints[each.key].location + resource_group_name = each.value.vnet_resource_group_name + subnet_id = azurerm_subnet.private_endpoint[each.key].id + + custom_network_interface_name = "${local.resource_prefix}${each.key}-nic" + + private_service_connection { + name = "${local.resource_prefix}${each.key}" + private_connection_resource_id = each.value.target_resource_id + subresource_names = [each.value.subresource_name] + is_manual_connection = false + } + + private_dns_zone_group { + name = "${local.resource_prefix}${each.key}-${each.value.subresource_name}-private-link" + private_dns_zone_ids = [azurerm_private_dns_zone.private_link[each.key].id] + } + + tags = local.tags +} + +resource "azurerm_private_dns_a_record" "private_link" { + for_each = { + for k, v in local.private_endpoint_configurations : k => v if v["create_private_dns_zone"] + } + + name = "@" + zone_name = azurerm_private_dns_zone.private_link[each.key].name + resource_group_name = local.resource_prefix + ttl = 300 + records = [azurerm_private_endpoint.default[each.key].private_service_connection[0].private_ip_address] + tags = local.tags +} + +resource "azurerm_private_dns_zone" "private_link" { + for_each = { + for k, v in local.private_endpoint_configurations : k => v if v["create_private_dns_zone"] + } + + name = each.value.private_dns_hostname + resource_group_name = local.resource_prefix + tags = local.tags +} + +resource "azurerm_private_dns_zone_virtual_network_link" "private_link" { + for_each = local.private_endpoint_configurations + + name = "${local.resource_prefix}-${each.value.subresource_name}privatelink" + resource_group_name = local.resource_prefix + private_dns_zone_name = each.value["create_private_dns_zone"] ? azurerm_private_dns_zone.private_link[each.key].name : each.value.private_dns_hostname + virtual_network_id = module.azure_container_apps_hosting.networking.vnet_id + tags = local.tags +} diff --git a/terraform/variables.tf b/terraform/variables.tf index 1f80e1c..e141bdf 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -278,3 +278,32 @@ variable "statuscake_contact_group_email_addresses" { type = list(string) default = [] } + +variable "private_endpoint_configurations" { + description = <