Managing Azure Private Link with Terraform
Learn how to set up and manage Azure Private Link using Terraform, including private endpoints and service connections
Managing Azure Private Link with Terraform
Azure Private Link provides secure and private connectivity to Azure PaaS services, customer-owned services, and Microsoft partner services. This guide demonstrates how to set up and manage Private Link using Terraform.
Video Tutorial
Learn more about managing Azure Private Link with Terraform in this comprehensive video tutorial:
Prerequisites
- Azure CLI configured with appropriate permissions
- Terraform installed (version 1.0.0 or later)
- Resource group created
- Understanding of networking concepts
Project Structure
terraform-azure-privatelink/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── privatelink/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── configs/
└── services.json
Private Link Configuration
Create modules/privatelink/main.tf
:
# Virtual Network
resource "azurerm_virtual_network" "main" {
name = "${var.project_name}-vnet"
address_space = ["10.0.0.0/16"]
location = var.location
resource_group_name = var.resource_group_name
tags = var.tags
}
# Subnet for Private Endpoints
resource "azurerm_subnet" "endpoint" {
name = "endpoint-subnet"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.1.0/24"]
enforce_private_link_endpoint_network_policies = true
}
# Private DNS Zone
resource "azurerm_private_dns_zone" "blob" {
name = "privatelink.blob.core.windows.net"
resource_group_name = var.resource_group_name
tags = var.tags
}
resource "azurerm_private_dns_zone" "sql" {
name = "privatelink.database.windows.net"
resource_group_name = var.resource_group_name
tags = var.tags
}
resource "azurerm_private_dns_zone" "keyvault" {
name = "privatelink.vaultcore.azure.net"
resource_group_name = var.resource_group_name
tags = var.tags
}
# Virtual Network Links
resource "azurerm_private_dns_zone_virtual_network_link" "blob" {
name = "${var.project_name}-blob-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.blob.name
virtual_network_id = azurerm_virtual_network.main.id
registration_enabled = false
tags = var.tags
}
resource "azurerm_private_dns_zone_virtual_network_link" "sql" {
name = "${var.project_name}-sql-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.sql.name
virtual_network_id = azurerm_virtual_network.main.id
registration_enabled = false
tags = var.tags
}
resource "azurerm_private_dns_zone_virtual_network_link" "keyvault" {
name = "${var.project_name}-kv-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.keyvault.name
virtual_network_id = azurerm_virtual_network.main.id
registration_enabled = false
tags = var.tags
}
# Storage Account Private Endpoint
resource "azurerm_private_endpoint" "blob" {
name = "${var.project_name}-blob-pe"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.endpoint.id
private_service_connection {
name = "${var.project_name}-blob-connection"
private_connection_resource_id = var.storage_account_id
is_manual_connection = false
subresource_names = ["blob"]
}
private_dns_zone_group {
name = "blob-group"
private_dns_zone_ids = [azurerm_private_dns_zone.blob.id]
}
tags = var.tags
}
# SQL Server Private Endpoint
resource "azurerm_private_endpoint" "sql" {
name = "${var.project_name}-sql-pe"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.endpoint.id
private_service_connection {
name = "${var.project_name}-sql-connection"
private_connection_resource_id = var.sql_server_id
is_manual_connection = false
subresource_names = ["sqlServer"]
}
private_dns_zone_group {
name = "sql-group"
private_dns_zone_ids = [azurerm_private_dns_zone.sql.id]
}
tags = var.tags
}
# Key Vault Private Endpoint
resource "azurerm_private_endpoint" "keyvault" {
name = "${var.project_name}-kv-pe"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.endpoint.id
private_service_connection {
name = "${var.project_name}-kv-connection"
private_connection_resource_id = var.key_vault_id
is_manual_connection = false
subresource_names = ["vault"]
}
private_dns_zone_group {
name = "keyvault-group"
private_dns_zone_ids = [azurerm_private_dns_zone.keyvault.id]
}
tags = var.tags
}
# Private Link Service
resource "azurerm_private_link_service" "main" {
name = "${var.project_name}-pls"
location = var.location
resource_group_name = var.resource_group_name
nat_ip_configuration {
name = "primary"
private_ip_address = "10.0.1.17"
private_ip_address_version = "IPv4"
subnet_id = azurerm_subnet.service.id
primary = true
}
load_balancer_frontend_ip_configuration_ids = [
var.load_balancer_frontend_ip_configuration_id
]
visibility_subscription_ids = [data.azurerm_client_config.current.subscription_id]
auto_approval_subscription_ids = [data.azurerm_client_config.current.subscription_id]
tags = var.tags
}
# Network Security Group
resource "azurerm_network_security_group" "endpoint" {
name = "${var.project_name}-endpoint-nsg"
location = var.location
resource_group_name = var.resource_group_name
security_rule {
name = "AllowVnetInBound"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "VirtualNetwork"
destination_address_prefix = "VirtualNetwork"
}
tags = var.tags
}
resource "azurerm_subnet_network_security_group_association" "endpoint" {
subnet_id = azurerm_subnet.endpoint.id
network_security_group_id = azurerm_network_security_group.endpoint.id
}
## Network Configuration
1. **Service Subnet**
```hcl
resource "azurerm_subnet" "service" {
name = "service-subnet"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.2.0/24"]
enforce_private_link_service_network_policies = true
}
resource "azurerm_network_security_group" "service" {
name = "${var.project_name}-service-nsg"
location = var.location
resource_group_name = var.resource_group_name
security_rule {
name = "AllowHttpsInBound"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags = var.tags
}
resource "azurerm_subnet_network_security_group_association" "service" {
subnet_id = azurerm_subnet.service.id
network_security_group_id = azurerm_network_security_group.service.id
}
Route Configuration
- Route Table
resource "azurerm_route_table" "endpoint" {
name = "${var.project_name}-endpoint-rt"
location = var.location
resource_group_name = var.resource_group_name
route {
name = "ToInternet"
address_prefix = "0.0.0.0/0"
next_hop_type = "Internet"
}
tags = var.tags
}
resource "azurerm_subnet_route_table_association" "endpoint" {
subnet_id = azurerm_subnet.endpoint.id
route_table_id = azurerm_route_table.endpoint.id
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "privatelink" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_private_link_service.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "privatelink" {
name = "${var.project_name}-connection-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_private_link_service.main.id]
description = "Alert when private link connections fail"
criteria {
metric_namespace = "Microsoft.Network/privateLinkServices"
metric_name = "PrivateEndpointConnectionsCount"
aggregation = "Average"
operator = "LessThan"
threshold = 1
}
action {
action_group_id = var.action_group_id
}
}
Best Practices
-
Performance
- Plan subnet sizing
- Configure DNS properly
- Optimize routing
- Monitor latency
-
Security
- Use network policies
- Configure NSGs
- Implement monitoring
- Control access
-
High Availability
- Use multiple endpoints
- Configure failover
- Monitor connections
- Implement backup
-
Cost Optimization
- Plan endpoint usage
- Monitor traffic
- Optimize connections
- Review configurations
Conclusion
You’ve learned how to set up and manage Azure Private Link using Terraform. This setup provides:
- Private connectivity
- Service isolation
- DNS integration
- Network security
Remember to:
- Monitor connections
- Review security
- Update configurations
- Maintain endpoints