%3CLINGO-SUB%20id%3D%22lingo-sub-1279910%22%20slang%3D%22en-US%22%3EUsing%20Terraform%20to%20create%20Private%20Endpoint%20for%20Azure%20Database%20for%20MySQL%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1279910%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fmysql%2Fconcepts-data-access-security-private-link%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EPrivate%20Link%3C%2FA%3E%20enables%20users%20to%20have%20private%20connectivity%20from%20a%20Microsoft%20Azure%20Virtual%20Network%20to%20Azure%20Database%20for%20MySQL.%20This%20feature%20creates%20a%20private%20endpoint%20that%20maps%20a%20private%20IP%20address%20from%20the%20Virtual%20Network%20to%20an%20Azure%20Database%20for%20MySQL%20instance.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CA%20href%3D%22https%3A%2F%2Fwww.terraform.io%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3EHashicorp%20Terraform%3C%2FA%3E%26nbsp%3Bis%20an%20open-source%20tool%20for%20provisioning%20and%20managing%20cloud%20infrastructure.%20It%20codifies%20infrastructure%20in%20configuration%20files%20that%20describe%20the%20topology%20of%20cloud%20resources.%20The%20Terraform%20CLI%20provides%20a%20simple%20mechanism%20to%20deploy%20and%20version%20the%20configuration%20files%20to%20Azure.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EStep-by-step%20instructions%20on%20how%20to%20use%20Terraform%20to%20provision%20private%20endpoint%20for%20Azure%20Database%20for%20MySQL%20are%20outlined%20below.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH4%20id%3D%22toc-hId--680031207%22%20id%3D%22toc-hId--680031207%22%3EPrerequisites%3A%3CBR%20%2F%3E%3CBR%20%2F%3E%3C%2FH4%3E%0A%3COL%3E%0A%3CLI%3EIf%20you%20don't%20have%20an%26nbsp%3BAzure%20subscription%2C%20create%20a%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fazure.microsoft.com%2Ffree%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Efree%3C%2FA%3E%26nbsp%3Baccount%20before%20you%20begin.%3C%2FLI%3E%0A%3CLI%3EInstall%20Azure%20CLI%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fcli%2Fazure%2Finstall-azure-cli%3Fview%3Dazure-cli-latest%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Elatest%20version%3C%2FA%3E%3C%2FLI%3E%0A%3CLI%3EDownload%20and%20Install%20Terraform%20%3CA%20href%3D%22https%3A%2F%2Fwww.terraform.io%2Fdownloads.html%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3Elatest%20version%3C%2FA%3E%3C%2FLI%3E%0A%3CLI%3EYou%20can%20also%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fcloud-shell%2Foverview%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EAzure%20Cloud%20Shell%3C%2FA%3E%20which%20has%20Azure%20CLI%20and%20Terraform%20installed%20already.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CH4%20id%3D%22toc-hId-1807481626%22%20id%3D%22toc-hId-1807481626%22%3E%26nbsp%3B%3C%2FH4%3E%0A%3CH4%20id%3D%22toc-hId-27163%22%20id%3D%22toc-hId-27163%22%3ESteps%3A%3C%2FH4%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E1.%20Login%20to%20the%20subscription%20in%20which%20you%20wish%20to%20create%20resources%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eaz%20login%0Aaz%20account%20set%20--subscription%3Dffffffff-ffff-ffff-ffff-ffffffffffff%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E2.%20Create%20resource%20group%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eaz%20group%20create%20-l%20australiaeast%20-n%20MysqlResourceGroup%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E3.%20Create%20service%20principal%20to%20be%20used%20by%20Terraform.%20Assign%20the%20service%20principal%20as%20Contributor%20for%20the%20subscription%20so%20that%20it%20can%20be%20used%20for%20creating%20resources.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eaz%20ad%20sp%20create-for-rbac%20--role%3D%22Contributor%22%20--scopes%3D%22%2Fsubscriptions%2Fffffffff-ffff-ffff-ffff-ffffffffffff%22%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ERecord%20output%20of%20the%20above%20command%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3E%7B%0A%20%20%22appId%22%3A%20%22917aeb14-bf7f-4687-8bdb-6d2f5b972eae%22%2C%0A%20%20%22displayName%22%3A%20%22azure-cli-2020-04-01-23-03-44%22%2C%0A%20%20%22name%22%3A%20%22http%3A%2F%2Fazure-cli-2020-04-01-23-03-44%22%2C%0A%20%20%22password%22%3A%20%224f6833a0-afdf-498d-99f9-02d9b59a06f0%22%2C%0A%20%20%22tenant%22%3A%20%2259297e42-ba2f-4eca-909a-bc93656bfdbc%22%0A%7D%0A%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E4.%20Create%20a%20file%20named%20main.tf%20with%20the%20following%20content.%20Replace%20subscription_id%2C%20client_id%20(appId)%2C%20client_secret%20(password)%2C%20tenant_id%20with%20appropriate%20values%20from%20above%20output%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eterraform%20%7B%0A%20%20required_version%20%3D%20%22%26gt%3B%3D%200.12%22%0A%7D%0A%0Aprovider%20%22azurerm%22%20%7B%0A%20%20version%20%3D%20%22%26gt%3B%3D1.29.0%22%0A%20%20subscription_id%20%3D%20%22ffffffff-ffff-ffff-ffff-ffffffffffff%22%0A%20%20client_id%20%20%20%20%20%20%20%3D%20%22917aeb14-bf7f-4687-8bdb-6d2f5b972eae%22%0A%20%20client_secret%20%20%20%3D%20%224f6833a0-afdf-498d-99f9-02d9b59a06f0%22%0A%20%20tenant_id%20%20%20%20%20%20%20%3D%20%2259297e42-ba2f-4eca-909a-bc93656bfdbc%22%0A%7D%0A%0Aresource%20%22random_string%22%20%22random%22%20%7B%0A%20%20length%20%3D%206%0A%20%20special%20%3D%20false%0A%20%20upper%20%3D%20false%0A%7D%0A%0Aresource%20%22azurerm_virtual_network%22%20%22example%22%20%7B%0A%20%20name%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22%24%7Brandom_string.random.result%7D-network%22%0A%20%20address_space%20%20%20%20%20%20%20%3D%20%5B%2210.0.0.0%2F16%22%5D%0A%20%20location%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22Australia%20East%22%0A%20%20resource_group_name%20%3D%20%22MysqlResourceGroup%22%0A%7D%0A%0Aresource%20%22azurerm_subnet%22%20%22example%22%20%7B%0A%20%20name%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22%24%7Brandom_string.random.result%7D-subnet%22%0A%20%20resource_group_name%20%20%3D%20%22MysqlResourceGroup%22%0A%20%20virtual_network_name%20%3D%20azurerm_virtual_network.example.name%0A%20%20address_prefix%20%20%20%20%20%20%20%3D%20%2210.0.1.0%2F24%22%0A%0A%20%20enforce_private_link_endpoint_network_policies%20%3D%20true%0A%7D%0A%0Aresource%20%22azurerm_mysql_server%22%20%22example%22%20%7B%0A%20%20name%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22%24%7Brandom_string.random.result%7D-mysql%22%0A%20%20location%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22Australia%20East%22%0A%20%20resource_group_name%20%3D%20%22MysqlResourceGroup%22%0A%0A%20%20sku_name%20%3D%20%22GP_Gen5_2%22%0A%0A%20%20storage_profile%20%7B%0A%20%20%20%20storage_mb%20%20%20%20%20%20%20%20%20%20%20%20%3D%2051200%0A%20%20%20%20backup_retention_days%20%3D%207%0A%20%20%20%20geo_redundant_backup%20%20%3D%20%22Disabled%22%0A%20%20%20%20auto_grow%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22Enabled%22%0A%20%20%7D%0A%0A%20%20administrator_login%20%20%20%20%20%20%20%20%20%20%3D%20%22mysqladmin%22%0A%20%20administrator_login_password%20%3D%20%22H%40Sh1CoR3!%22%0A%20%20version%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%225.7%22%0A%20%20ssl_enforcement%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22Enabled%22%0A%7D%0A%0Aresource%20%22azurerm_private_endpoint%22%20%22example%22%20%7B%0A%20%20name%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22%24%7Brandom_string.random.result%7D-endpoint%22%0A%20%20location%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22Australia%20East%22%0A%20%20resource_group_name%20%3D%20%22MysqlResourceGroup%22%0A%20%20subnet_id%20%20%20%20%20%20%20%20%20%20%20%3D%20azurerm_subnet.example.id%0A%0A%20%20private_service_connection%20%7B%0A%20%20%20%20name%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%22%24%7Brandom_string.random.result%7D-privateserviceconnection%22%0A%20%20%20%20private_connection_resource_id%20%3D%20azurerm_mysql_server.example.id%0A%20%20%20%20subresource_names%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%5B%20%22mysqlServer%22%20%5D%0A%20%20%20%20is_manual_connection%20%20%20%20%20%20%20%20%20%20%20%3D%20false%0A%20%20%7D%0A%7D%0A%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E5.%20Provision%20the%20above%20resources%20using%20the%20following%20commands%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eterraform%20init%0Arm%20terraform.tfstate%0Aterraform%20plan%0Aterraform%20apply%0A%3C%2FPRE%3E%0A%3CH4%20id%3D%22toc-hId--1807427300%22%20id%3D%22toc-hId--1807427300%22%3E%26nbsp%3B%3C%2FH4%3E%0A%3CH4%20id%3D%22toc-hId-680085533%22%20id%3D%22toc-hId-680085533%22%3ENOTE%3A%3C%2FH4%3E%0A%3COL%3E%0A%3CLI%3EPrivate%20endpoints%20feature%20is%20supported%20only%20on%20General%20Purpose%20and%20Memory%20Optimized%20pricing%20tiers%20of%20Azure%20Database%20for%20MySQL.%3C%2FLI%3E%0A%3CLI%3EFor%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fprivate-link%2Fmanage-private-endpoint%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Emanual%20approval%3C%2FA%3E%20of%20private%20endpoint%20connection%2C%20you%20can%20use%20is_manual_connection%20%3D%20true%3C%2FLI%3E%0A%3CLI%3EIf%20you%20already%20have%20a%20subnet%20and%20mysql%20server%2C%20you%20can%20just%20provision%20%E2%80%9Cazurerm_private_endpoint%E2%80%9D%20resource%20with%20appropriate%20values%20passed%20for%20subnet_id%20and%20private_connection_resource_id%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3EOnce%20the%20resources%20are%20provisioned%20successfully%20without%20any%20errors%2C%20you%20will%20be%20able%20to%20connect%20to%20the%20MySQL%20Server%20from%20the%20VNET%20using%20the%20following%20command.%20(Replace%20host%2C%20user%2C%20password%20with%20appropriate%20values)%3A%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Emysql%20--host%3D10.0.1.4%20--port%3D3306%20--database%3Dmysql%20--user%3Dmysqladmin%40server-mysql%20--ssl-mode%3DREQUIRED%20--password%3DH%40Sh1CoR3!%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH4%20id%3D%22toc-hId--1127368930%22%20id%3D%22toc-hId--1127368930%22%3ECleanup%3C%2FH4%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ERemove%20the%20service%20principal%20and%20resource%20group%20if%20needed%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%3Eaz%20ad%20sp%20delete%20--id%20917aeb14-bf7f-4687-8bdb-6d2f5b972eae%0Aaz%20group%20delete%20-n%20MysqlResourceGroup%26nbsp%3B%3C%2FPRE%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-1279910%22%20slang%3D%22en-US%22%3E%3CP%3EUsing%20Terraform%20to%20create%20Private%20Endpoint%20for%20Azure%20Database%20for%20MySQL%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22terraform-azure.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F182015i2EE4DA0741785F1C%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22terraform-azure.png%22%20alt%3D%22terraform-azure.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-TEASER%3E%3CLINGO-LABS%20id%3D%22lingo-labs-1279910%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EAzure%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Econnectivity%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Edatabase%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EEndpoints%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Ehashicorp%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Eip%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EMySQL%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Enetwork%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Eprivate%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3Esecure%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EServer%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3ETerraform%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E
Microsoft

Private Link enables users to have private connectivity from a Microsoft Azure Virtual Network to Azure Database for MySQL. This feature creates a private endpoint that maps a private IP address from the Virtual Network to an Azure Database for MySQL instance.

 

Hashicorp Terraform is an open-source tool for provisioning and managing cloud infrastructure. It codifies infrastructure in configuration files that describe the topology of cloud resources. The Terraform CLI provides a simple mechanism to deploy and version the configuration files to Azure.

 

Step-by-step instructions on how to use Terraform to provision private endpoint for Azure Database for MySQL are outlined below.

 

Prerequisites:

  1. If you don't have an Azure subscription, create a free account before you begin.
  2. Install Azure CLI latest version
  3. Download and Install Terraform latest version
  4. You can also use Azure Cloud Shell which has Azure CLI and Terraform installed already.

 

Steps:

 

1. Login to the subscription in which you wish to create resources

 

az login
az account set --subscription=ffffffff-ffff-ffff-ffff-ffffffffffff

 

2. Create resource group

 

az group create -l australiaeast -n MysqlResourceGroup

 

3. Create service principal to be used by Terraform. Assign the service principal as Contributor for the subscription so that it can be used for creating resources.

 

az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff"

 

Record output of the above command

 

{
  "appId": "917aeb14-bf7f-4687-8bdb-6d2f5b972eae",
  "displayName": "azure-cli-2020-04-01-23-03-44",
  "name": "http://azure-cli-2020-04-01-23-03-44",
  "password": "4f6833a0-afdf-498d-99f9-02d9b59a06f0",
  "tenant": "59297e42-ba2f-4eca-909a-bc93656bfdbc"
}

 

4. Create a file named main.tf with the following content. Replace subscription_id, client_id (appId), client_secret (password), tenant_id with appropriate values from above output

 

terraform {
  required_version = ">= 0.12"
}

provider "azurerm" {
  version = ">=1.29.0"
  subscription_id = "ffffffff-ffff-ffff-ffff-ffffffffffff"
  client_id       = "917aeb14-bf7f-4687-8bdb-6d2f5b972eae"
  client_secret   = "4f6833a0-afdf-498d-99f9-02d9b59a06f0"
  tenant_id       = "59297e42-ba2f-4eca-909a-bc93656bfdbc"
}

resource "random_string" "random" {
  length = 6
  special = false
  upper = false
}

resource "azurerm_virtual_network" "example" {
  name                = "${random_string.random.result}-network"
  address_space       = ["10.0.0.0/16"]
  location            = "Australia East"
  resource_group_name = "MysqlResourceGroup"
}

resource "azurerm_subnet" "example" {
  name                 = "${random_string.random.result}-subnet"
  resource_group_name  = "MysqlResourceGroup"
  virtual_network_name = azurerm_virtual_network.example.name
  address_prefix       = "10.0.1.0/24"

  enforce_private_link_endpoint_network_policies = true
}

resource "azurerm_mysql_server" "example" {
  name                = "${random_string.random.result}-mysql"
  location            = "Australia East"
  resource_group_name = "MysqlResourceGroup"

  sku_name = "GP_Gen5_2"

  storage_profile {
    storage_mb            = 51200
    backup_retention_days = 7
    geo_redundant_backup  = "Disabled"
    auto_grow             = "Enabled"
  }

  administrator_login          = "mysqladmin"
  administrator_login_password = "H@Sh1CoR3!"
  version                      = "5.7"
  ssl_enforcement              = "Enabled"
}

resource "azurerm_private_endpoint" "example" {
  name                = "${random_string.random.result}-endpoint"
  location            = "Australia East"
  resource_group_name = "MysqlResourceGroup"
  subnet_id           = azurerm_subnet.example.id

  private_service_connection {
    name                           = "${random_string.random.result}-privateserviceconnection"
    private_connection_resource_id = azurerm_mysql_server.example.id
    subresource_names              = [ "mysqlServer" ]
    is_manual_connection           = false
  }
}

 

5. Provision the above resources using the following commands

 

terraform init
rm terraform.tfstate
terraform plan
terraform apply

 

NOTE:

  1. Private endpoints feature is supported only on General Purpose and Memory Optimized pricing tiers of Azure Database for MySQL.
  2. For manual approval of private endpoint connection, you can use is_manual_connection = true
  3. If you already have a subnet and mysql server, you can just provision “azurerm_private_endpoint” resource with appropriate values passed for subnet_id and private_connection_resource_id

Once the resources are provisioned successfully without any errors, you will be able to connect to the MySQL Server from the VNET using the following command. (Replace host, user, password with appropriate values):

 

mysql --host=10.0.1.4 --port=3306 --database=mysql --user=mysqladmin@server-mysql --ssl-mode=REQUIRED --password=H@Sh1CoR3!

 

Cleanup

 

Remove the service principal and resource group if needed

 

az ad sp delete --id 917aeb14-bf7f-4687-8bdb-6d2f5b972eae
az group delete -n MysqlResourceGroup