Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Terraform sample for a Quickstart for Azure Private Link that creates a private endpoint for an Azure SQL server #312

Merged
merged 5 commits into from
Feb 21, 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
225 changes: 225 additions & 0 deletions quickstart/201-private-link-sql-database/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
resource "random_pet" "prefix" {
prefix = var.resource_group_name_prefix
length = 1
}

# Resource Group
resource "azurerm_resource_group" "rg" {
location = var.resource_group_location
name = "${random_pet.prefix.id}-rg"
}

# Virtual Network
resource "azurerm_virtual_network" "my_terraform_network" {
name = "${random_pet.prefix.id}-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}

# Subnet 1
resource "azurerm_subnet" "my_terraform_subnet_1" {
name = "subnet-1"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.my_terraform_network.name
address_prefixes = ["10.0.0.0/24"]
}

# Public IP address for NAT gateway
resource "azurerm_public_ip" "my_public_ip" {
name = "public-ip-nat"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
sku = "Standard"
}

# NAT Gateway
resource "azurerm_nat_gateway" "my_nat_gateway" {
asudbring marked this conversation as resolved.
Show resolved Hide resolved
name = "nat-gateway"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}

# Associate NAT Gateway with Public IP
resource "azurerm_nat_gateway_public_ip_association" "example" {
nat_gateway_id = azurerm_nat_gateway.my_nat_gateway.id
public_ip_address_id = azurerm_public_ip.my_public_ip.id
}

# Associate NAT Gateway with Subnet
resource "azurerm_subnet_nat_gateway_association" "example" {
subnet_id = azurerm_subnet.my_terraform_subnet_1.id
nat_gateway_id = azurerm_nat_gateway.my_nat_gateway.id
}

# Create public IP for virtual machine
resource "azurerm_public_ip" "my_public_ip_vm" {
name = "public-ip-vm"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
sku = "Standard"
}

# Create Network Security Group and rule
resource "azurerm_network_security_group" "my_terraform_nsg" {
name = "nsg-1"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name

security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}

# Create network interface
resource "azurerm_network_interface" "my_terraform_nic" {
name = "nic-1"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name

ip_configuration {
name = "my_nic_configuration"
subnet_id = azurerm_subnet.my_terraform_subnet_1.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.my_public_ip_vm.id
}
}

# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "example" {
network_interface_id = azurerm_network_interface.my_terraform_nic.id
network_security_group_id = azurerm_network_security_group.my_terraform_nsg.id
}

# Generate random text for a unique storage account name
resource "random_id" "random_id" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group = azurerm_resource_group.rg.name
}

byte_length = 8
}

# Create storage account for boot diagnostics
resource "azurerm_storage_account" "my_storage_account" {
name = "diag${random_id.random_id.hex}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
account_tier = "Standard"
account_replication_type = "LRS"
}

# Create virtual machine
resource "azurerm_linux_virtual_machine" "my_terraform_vm" {
name = "vm-1"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
network_interface_ids = [azurerm_network_interface.my_terraform_nic.id]
size = "Standard_DS1_v2"

os_disk {
name = "myOsDisk"
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}

source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}

computer_name = "hostname"
admin_username = var.username

admin_ssh_key {
username = var.username
public_key = jsondecode(azapi_resource_action.ssh_public_key_gen.output).publicKey
}

boot_diagnostics {
storage_account_uri = azurerm_storage_account.my_storage_account.primary_blob_endpoint
}
}

# Create SQL server name
resource "random_pet" "azurerm_mssql_server_name" {
prefix = "sql"
}

# Random password for SQL server
resource "random_password" "admin_password" {
count = var.admin_password == null ? 1 : 0
length = 20
special = true
min_numeric = 1
min_upper = 1
min_lower = 1
min_special = 1
}

locals {
admin_password = try(random_password.admin_password[0].result, var.admin_password)
}

# Create SQL server
resource "azurerm_mssql_server" "server" {
name = random_pet.azurerm_mssql_server_name.id
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
administrator_login = var.admin_username
administrator_login_password = local.admin_password
version = "12.0"
}

# Create SQL database
resource "azurerm_mssql_database" "db" {
name = var.sql_db_name
server_id = azurerm_mssql_server.server.id
}

# Create private endpoint for SQL server
resource "azurerm_private_endpoint" "my_terraform_endpoint" {
name = "private-endpoint-sql"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
subnet_id = azurerm_subnet.my_terraform_subnet_1.id

private_service_connection {
name = "private-serviceconnection"
private_connection_resource_id = azurerm_mssql_server.server.id
subresource_names = ["sqlServer"]
is_manual_connection = false
}

private_dns_zone_group {
name = "dns-zone-group"
private_dns_zone_ids = [azurerm_private_dns_zone.my_terraform_dns_zone.id]
}
}

# Create private DNS zone
resource "azurerm_private_dns_zone" "my_terraform_dns_zone" {
name = "privatelink.database.windows.net"
resource_group_name = azurerm_resource_group.rg.name
}

# Create virtual network link
resource "azurerm_private_dns_zone_virtual_network_link" "my_terraform_vnet_link" {
name = "vnet-link"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.my_terraform_dns_zone.name
virtual_network_id = azurerm_virtual_network.my_terraform_network.id
}
28 changes: 28 additions & 0 deletions quickstart/201-private-link-sql-database/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
output "resource_group_name" {
description = "The name of the created resource group."
value = azurerm_resource_group.rg.name
}

output "virtual_network_name" {
description = "The name of the created virtual network."
value = azurerm_virtual_network.my_terraform_network.name
}

output "subnet_name_1" {
description = "The name of the created subnet 1."
value = azurerm_subnet.my_terraform_subnet_1.name
}

output "nat_gateway_name" {
description = "The name of the created NAT gateway."
asudbring marked this conversation as resolved.
Show resolved Hide resolved
value = azurerm_nat_gateway.my_nat_gateway.name
}

output "sql_server_name" {
value = azurerm_mssql_server.server.name
}

output "admin_password" {
sensitive = true
value = local.admin_password
}
24 changes: 24 additions & 0 deletions quickstart/201-private-link-sql-database/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
terraform {
required_providers {
azapi = {
source = "azure/azapi"
version = "~>1.5"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~>3.0"
}
random = {
source = "hashicorp/random"
version = "~>3.0"
}
}
}

provider "azurerm" {
asudbring marked this conversation as resolved.
Show resolved Hide resolved
features {
resource_group {
prevent_deletion_if_contains_resources = false
}
}
}
39 changes: 39 additions & 0 deletions quickstart/201-private-link-sql-database/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Azure Private Link private endpoint for Azure SQL Database

This template deploys an Azure Virtual Network, a subnet, a Azure NAT Gateway, a two public IP addresses, a Linux virtual machine, an Azure SQL server and database, and a private endpoint for the Azure SQL server.

## Terraform resource types

- [azurerm_resource_group](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group)
- [azurerm_virtual_network](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network)
- [azurerm_subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet)
- [azurerm_public_ip](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip)
- [azurerm_nat_gateway](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/nat_gateway)
- [azurerm_nat_gateway_public_ip_association](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/nat_gateway_public_ip_association)
- [azurerm_subnet_nat_gateway_association](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association)
- [azurerm_network_security_group](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group)
- [azurerm_linux_virtual_machine](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine)
- [azurerm_network_interface](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface)
- [azurerm_network_interface_security_group_association](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface_security_group_association)
- [azurerm_storage_account](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account)
- [random_id](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id)
- [random_pet](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet)
- [random_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password)
- [azurerm_mssql_server](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server)
- [azurerm_mssql_database](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_database)
- [azurerm_private_endpoint](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint)
- [azurerm_private_dns_zone](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone)
- [azurerm_private_dns_zone_virtual_network_link](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone_virtual_network_link)

## Variables

| Name | Description | Default |
|-|-|-|
| `resource_group_name_prefix` | Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription. | rg |
| `resource_group_location` | Location of the resource group. | eastus |
| `username` | Username of the administrator account of the virtual machine. | azureuser |
| `sql_db_name` | The name of the SQL Database. | SampleDB |
| `admin_username` | The administrator username of the SQL logical server. | azureadmin |
| `admin_password` | The administrator password of the SQL logical server. | null; If value is null, a random password is generated. |

## Example
24 changes: 24 additions & 0 deletions quickstart/201-private-link-sql-database/ssh.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
resource "random_pet" "ssh_key_name" {
prefix = "ssh"
separator = ""
}

resource "azapi_resource_action" "ssh_public_key_gen" {
type = "Microsoft.Compute/sshPublicKeys@2022-11-01"
resource_id = azapi_resource.ssh_public_key.id
action = "generateKeyPair"
method = "POST"

response_export_values = ["publicKey", "privateKey"]
}

resource "azapi_resource" "ssh_public_key" {
type = "Microsoft.Compute/sshPublicKeys@2022-11-01"
name = random_pet.ssh_key_name.id
location = azurerm_resource_group.rg.location
parent_id = azurerm_resource_group.rg.id
}

output "key_data" {
value = jsondecode(azapi_resource_action.ssh_public_key_gen.output).publicKey
}
36 changes: 36 additions & 0 deletions quickstart/201-private-link-sql-database/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
variable "resource_group_location" {
type = string
default = "eastus"
description = "Location of the resource group."
}

variable "resource_group_name_prefix" {
type = string
default = "rg"
description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription."
}

variable "username" {
type = string
description = "The username for the local account that will be created on the new VM."
default = "azureuser"
}

variable "sql_db_name" {
type = string
description = "The name of the SQL Database."
default = "SampleDB"
}

variable "admin_username" {
type = string
description = "The administrator username of the SQL logical server."
default = "azureadmin"
}

variable "admin_password" {
type = string
description = "The administrator password of the SQL logical server."
sensitive = true
default = null
}
Loading