Skip to content
This repository has been archived by the owner on Dec 3, 2024. It is now read-only.

Define Private Endpoints in Terraform #52

Merged
merged 3 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ If everything looks good, answer `yes` and wait for the new infrastructure to be

## Providers

No providers.
| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.100.0 |

## Modules

Expand All @@ -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

Expand Down Expand Up @@ -182,6 +193,7 @@ No resources.
| <a name="input_key_vault_access_ipv4"></a> [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 |
| <a name="input_monitor_email_receivers"></a> [monitor\_email\_receivers](#input\_monitor\_email\_receivers) | A list of email addresses that should be notified by monitoring alerts | `list(string)` | n/a | yes |
| <a name="input_monitor_endpoint_healthcheck"></a> [monitor\_endpoint\_healthcheck](#input\_monitor\_endpoint\_healthcheck) | Specify a route that should be monitored for a 200 OK status | `string` | n/a | yes |
| <a name="input_private_endpoint_configurations"></a> [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.<br> {<br> endpoint-name = {<br> vnet\_name: The Name of the VNet to create the private endpoint resources<br> vnet\_resource\_group\_name: The Name of the resource group containing the VNet<br> subnet\_cidr: The CIDR of the Private Endpoint subnet to be created<br> subresource\_name: The type of resource you are targeting (e.g. sqlServer)<br> target\_resource\_id: The Resource ID for the target resource you are trying to connect to<br> create\_private\_dns\_zone: Do you want to automatically create the Private DNS Zone?<br> private\_dns\_hostname: The hostname to use for the Private DNS Zone<br> subnet\_route\_table\_name: The Route Table ID to associate the subnet with (Optional)<br> }<br> } | <pre>map(object({<br> vnet_name = string<br> vnet_resource_group_name = string<br> subnet_cidr = string<br> subresource_name = string<br> target_resource_id = string<br> create_private_dns_zone = optional(bool, true)<br> private_dns_hostname = string<br> subnet_route_table_name = optional(string, null)<br> }))</pre> | `{}` | no |
| <a name="input_project_name"></a> [project\_name](#input\_project\_name) | Project name. Will be used along with `environment` as a prefix for all resources. | `string` | n/a | yes |
| <a name="input_registry_admin_enabled"></a> [registry\_admin\_enabled](#input\_registry\_admin\_enabled) | Do you want to enable access key based authentication for your Container Registry? | `bool` | `true` | no |
| <a name="input_registry_managed_identity_assign_role"></a> [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 |
Expand Down
15 changes: 15 additions & 0 deletions terraform/data.tf
Original file line number Diff line number Diff line change
@@ -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"]
}
3 changes: 3 additions & 0 deletions terraform/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
76 changes: 76 additions & 0 deletions terraform/private-endpoint.tf
Original file line number Diff line number Diff line change
@@ -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
}
29 changes: 29 additions & 0 deletions terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,32 @@ variable "statuscake_contact_group_email_addresses" {
type = list(string)
default = []
}

variable "private_endpoint_configurations" {
description = <<EOT
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)
}
}
EOT
type = 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)
}))
default = {}
}