Deploy Azure Key Vault + Windows VM using Terraform - azure

I'm trying to deploy infrastructure using Terraform.
My intention is to deploy a VM with a WinRM listener and for this reason, I need to use a certificate.
I first deploy a Key vault in which I put the certificate and then I retrieve the certificate from the Vault to register it into the Virtual Machine.
###############################################################################################################
# PROVIDERS
###############################################################################################################
provider "azurerm" {
features {}
}
###############################################################################################################
# RESOURCES
###############################################################################################################
data "azurerm_client_config" "current" {}
resource "azurerm_resource_group" "rg" {
name = "runner"
location = "West Europe"
}
resource "azurerm_key_vault" "testrunnerkeyvault" {
name = "test-runner-keyvault"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
certificate_permissions = [
"create",
"delete",
"deleteissuers",
"get",
"getissuers",
"import",
"list",
"listissuers",
"managecontacts",
"manageissuers",
"purge",
"recover",
"setissuers",
"update",
]
key_permissions = [
"backup",
"create",
"decrypt",
"delete",
"encrypt",
"get",
"import",
"list",
"purge",
"recover",
"restore",
"sign",
"unwrapKey",
"update",
"verify",
"wrapKey",
]
secret_permissions = [
"backup",
"delete",
"get",
"list",
"purge",
"recover",
"restore",
"set",
]
storage_permissions = [
"Backup",
"Delete",
"DeleteSAS",
"Get",
"GetSAS",
"List",
"ListSAS",
"Purge",
"Recover",
"RegenerateKey",
"Restore",
"Set",
"SetSAS",
"Update"
]
}
}
resource "azurerm_key_vault_certificate" "testrunnercertificate" {
name = "test-winrm-cert"
key_vault_id = azurerm_key_vault.testrunnerkeyvault.id
certificate {
contents = filebase64("files/winrm_cert.pfx")
password = "*********"
}
}
resource "azurerm_virtual_network" "vn" {
name = "runner_vn"
address_space = ["10.0.0.0/8"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "subnet" {
name = "runner_subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vn.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_network_security_group" "nsg" {
name = "Runner-Security-Group"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
tags = {
environment = "Test"
}
}
resource "azurerm_network_security_rule" "ssh-rule" {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.rg.name
network_security_group_name = azurerm_network_security_group.nsg.name
}
resource "azurerm_network_security_rule" "winrm-https-rule" {
name = "WinRM-Https"
priority = 300
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5986"
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.rg.name
network_security_group_name = azurerm_network_security_group.nsg.name
}
resource "azurerm_network_security_rule" "winrm-http-rule" {
name = "WinRM-Http"
priority = 301
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5985"
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.rg.name
network_security_group_name = azurerm_network_security_group.nsg.name
}
resource "azurerm_network_security_rule" "rdp-rule" {
name = "RDP"
priority = 302
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.rg.name
network_security_group_name = azurerm_network_security_group.nsg.name
}
resource "azurerm_subnet_network_security_group_association" "secgroup-assoc" {
subnet_id = azurerm_subnet.subnet.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
resource "azurerm_public_ip" "runner_public_ip" {
name = "runner-ip"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Dynamic"
sku = "Basic"
}
resource "azurerm_network_interface" "network_interface" {
name = "runner-network-interface"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
internal_dns_name_label = "runnertest"
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "static"
private_ip_address = "10.0.1.5"
public_ip_address_id = azurerm_public_ip.runner_public_ip.id
}
}
resource "azurerm_network_interface_security_group_association" "nisecuritygroup" {
network_interface_id = azurerm_network_interface.network_interface.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
resource "azurerm_windows_virtual_machine" "runner" {
name = "runner"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = "Standard_B2s"
admin_username = "******"
admin_password = "******"
network_interface_ids = [azurerm_network_interface.network_interface.id]
secret {
certificate {
store = "/CurrentUser/My"
url = azurerm_key_vault_certificate.testrunnercertificate.secret_id
}
key_vault_id = azurerm_key_vault.testrunnerkeyvault.id
}
winrm_listener {
protocol = "Https"
certificate_url = azurerm_key_vault_certificate.testrunnercertificate.secret_id
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
disk_size_gb = 64
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2022-datacenter-azure-edition-smalldisk"
version = "latest"
}
}
data "azurerm_public_ip" "runner-ip" {
name = azurerm_public_ip.runner_public_ip.name
resource_group_name = azurerm_windows_virtual_machine.runner.resource_group_name
depends_on = [azurerm_windows_virtual_machine.runner]
}
output "public_ip_address" {
value = data.azurerm_public_ip.runner-ip.ip_address
}
During the deployment of the virtual machine I receive the following error:
Error: waiting for creation of Windows Virtual Machine "runner" (Resource Group "runner"):
Code="KeyVaultAccessForbidden" Message="Key Vault
https://test-runner-keyvault.vault.azure.net/secrets/test-winrm-cert/23e7d5ab76914841b2c6e58d1e68b9b1 either has not been enabled for deployment or the vault id provided, /subscriptions/<subscriptionid>/resourceGroups/runner/providers/Microsoft.KeyVault/vaults/test-runner-keyvault, does not match the Key Vault's true resource id."
│
│ with azurerm_windows_virtual_machine.runner,
│ on main.tf line 224, in resource "azurerm_windows_virtual_machine" "runner":
│ 224: resource "azurerm_windows_virtual_machine" "runner" {

You need to switch to true the following optional params (in your key-vault resource) :
enabled_for_deployment - (Optional) Boolean flag to specify whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault. Defaults to false.
found here : https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault#argument-reference

Related

Terraform azurerm_linux_web_app dynamic ip_restriction

i'm trying to create several applications in one go and i can successfully do it with count = length(var.webapp_name) but the problem that i'm facing is that some of the apps are required to communicate with each other and i need to whitelist outbound_ip_addresses on each app
the code that i use which is causing issues is the following:
resource "azurerm_linux_web_app" "API" {
depends_on = [azurerm_subnet.subnet]
count = length(var.webapp_name)
name = lower("${var.customer4letter}-${var.env3letter}-${var.locationid3letter}-${var.servicetype}-${element(var.webapp_name, count.index)}")
location = var.location //West US 2
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.api-farm.id
https_only = "true"
app_settings = {
"WEBSITE_USE_DIAGNOSTIC_SERVER" = "True"
}
identity {
type = "SystemAssigned"
}
site_config {
ftps_state = "FtpsOnly"
websockets_enabled = "false"
use_32_bit_worker = "false"
always_on = "true"
application_stack {
dotnet_version = "6.0"
}
dynamic "ip_restriction" {
for_each = local.ip_address_list3
content{
action = "Allow"
name = ip_restriction.value["name"]
service_tag = ip_restriction.value["service_tag"]
priority = ip_restriction.value["prior"]
} }
dynamic "ip_restriction" {
for_each = azurerm_linux_web_app.API[0].outbound_ip_addresses
content {
ip_address = cidrhost(ip_restriction.value,0)
} } } }
Local and variables set are
variable "webapp_name" {
default = [ "app1", "app2", "app3" ]
}
locals {
ip_address_list3 = [
{
service_tag = "AppService"
prior : "102",
name = "VirtualNetwork"
}
]
}
the error that i have is the following:
I Tried to reproduce the same in my environment to azure web app with outbound IP using Terraform:
Terraform Code:
provider "azurerm" {
features {}
}
locals {
resource_group_name = "test-rg"
location = "East US"
app_name_prefix = "venkatdemoapp"
}
resource "azurerm_resource_group" "test-rg" {
name = local.resource_group_name
location = local.location
}
# Create multiple web apps
resource "azurerm_app_service_plan" "test_plan" {
count = 2
name = "${local.app_name_prefix}-plan-${count.index}"
location = local.location
resource_group_name = azurerm_resource_group.test-rg.name
sku {
tier = "Basic"
size = "B1"
}
}
resource "azurerm_app_service" "thejawebapp" {
count = 2
name = "${local.app_name_prefix}-${count.index}"
location = local.location
resource_group_name = azurerm_resource_group.test-rg.name
app_service_plan_id = azurerm_app_service_plan.test_plan[count.index].id
}
# Restrict access to each web app
resource "azurerm_network_security_group" "test_nsg" {
count = 2
name = "${local.app_name_prefix}-nsg-${count.index}"
location = local.location
resource_group_name = azurerm_resource_group.test-rg.name
security_rule {
name = "Allow_HTTP_Traffic"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "Deny_All_Traffic"
priority = 200
direction = "Inbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# Associate each web app with its NSG.
resource "azurerm_network_interface" "test_nic" {
count = 2
name = "${local.app_name_prefix}-nic-${count.index}"
location = local.location
resource_group_name = azurerm_resource_group.test-rg.name
ip_configuration {
name = "${local.app_name_prefix}-ipconfig-${count.index}"
subnet_id = azurerm_subnet.test_subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_subnet" "test_subnet" {
name = "${local.app_name_prefix}-subnet"
resource_group_name = azurerm_resource_group.test-rg.name
virtual_network_name = azurerm_virtual_network.test_vnet.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_virtual_network" "test_vnet" {
name = "${local.app_name_prefix}-vnet"
location = local.location
resource_group_name = azurerm_resource_group.test-rg.name address_space = ["10.0.0.0/16"]
}
Terraform Apply:
Once ran the above code resources are created automatically with restriction.
NSG Rule:

Error Key Vault object_id is an invalid UUID - Terraform/Azure

I'm deploying an Azure Application Gateway in Terraform and I want to store my SSL private certificate for the https between Internet and my App-gtw in an Azure Key Vault.
The code, omitting useless information in the application gateway module, is:
module "agw_user_assigned_identity" {
source = "../modules/resources-blocks/user_assigned_identity"
user_assigned_identity_name = "agw-user-signed-id"
resource_group_name = module.resource_group.name
resource_group_location = module.resource_group.location
}
module "key_vault" {
source = "../modules/resources/key_vault"
key_vault_name = local.key_vault_name
resource_group_location = module.resource_group.location
resource_group_name = module.resource_group.name
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = module.agw_user_assigned_identity.id
soft_delete_retention_days = 90
log_analytics_workspace_id = module.log_analytics_workspace.id
enable_diagnostic_setting = true
}
module "key_vault_private_certificate" {
source = "../modules/resources-blocks/key_vault_certificate"
key_vault_id = module.key_vault.id
certificate_name = local.agw_certificate_name
certificate_path = "./certificates/xxxxx.pfx"
certificate_password = var.SSL_CERTIFICATE_PASSWORD
}
resource "null_resource" "previous" {}
module "agw_time_sleep" {
source = "../modules/resources-blocks/time_sleep"
select_module = module.key_vault
seconds = "200s"
}
module "application_gateway" {
source = "../modules/resources-hub/application_gateway"
resource_group_name = module.resource_group.name
resource_group_location = module.resource_group.location
application_gateway_name = local.agw_name
key_vault_private_certificate_id = module.key_vault_private_certificate.certificate_id
key_vault_private_certificate_id = azurerm_key_vault_certificate.kv_certificate.secret_id
ssl_certificate_name = local.agw_certificate_name
agw_time_sleep = module.agw_time_sleep.id
frontend_ports = [
{
name = "myFrontendPort"
port = 443
}
]
http_listeners = [
{
name = "devListener"
frontend_ip_configuration = local.frontend_ip_configuration_name
frontend_port_name = "myFrontendPort"
protocol = "Https"
hostname = "xxxxxxxxxxxxx.be"
ssl_certificate_name = local.agw_certificate_name
}
]
}
The key_vault resource is:
resource "azurerm_key_vault" "kv" {
name = var.key_vault_name
location = var.resource_group_location
resource_group_name = var.resource_group_name
enabled_for_disk_encryption = true
tenant_id = var.tenant_id
soft_delete_retention_days = var.soft_delete_retention_days
purge_protection_enabled = false
sku_name = "standard"
access_policy {
tenant_id = var.tenant_id
object_id = var.object_id
key_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Recover", ]
secret_permissions = ["Get", "List", "Set", "Delete", "Recover", "Backup", "Restore", "Purge"]
storage_permissions = ["Get", "Set", "Delete", "Recover", "Backup", "Restore"]
certificate_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore", "Purge"]
}
lifecycle {
ignore_changes = [access_policy]
}
}
The key_vault_certificate resource is:
resource "azurerm_key_vault_certificate" "kv_certificate" {
name = var.certificate_name
key_vault_id = var.key_vault_id
certificate {
contents = filebase64(var.certificate_path)
password = var.certificate_password
}
certificate_policy {
issuer_parameters {
name = "Self"
}
key_properties {
exportable = true
key_size = 2048
key_type = "RSA"
reuse_key = false
}
secret_properties {
content_type = "application/x-pkcs12"
}
}
}
The application gateway resource is (omitting useless information):
resource "azurerm_application_gateway" "app_gw" {
name = var.application_gateway_name
resource_group_name = var.resource_group_name
location = var.resource_group_location
identity {
type = "UserAssigned"
identity_ids = [var.user_assigned_identity_id]
}
ssl_certificate {
name = var.ssl_certificate_name
key_vault_secret_id = var.key_vault_private_certificate_id
}
dynamic "http_listener" {
for_each = var.http_listeners
content {
name = http_listener.value.name
frontend_ip_configuration_name = http_listener.value.frontend_ip_configuration
frontend_port_name = http_listener.value.frontend_port_name
protocol = http_listener.value.protocol
host_name = http_listener.value.hostname
firewall_policy_id = var.firewall_policy_id
ssl_certificate_name = http_listener.value.ssl_certificate_name
}
}
depends_on = [var.agw_time_sleep]
}
The error that I get when I use the command terraform plan -var-file="variables.tfvars" is:
Error: expected "access_policy.0.object_id" to be a valid UUID, got /subscriptions/xxxxxxxx/resourceGroups/xxxxxxxxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/agw-user-signed-id
│
│ with azurerm_key_vault.kv,
│ on main.tf line 344, in resource "azurerm_key_vault" "kv":
│ 344: object_id = module.agw_user_assigned_identity.id
Apparently seems that the problem is related to the object_id that I specify in the key_vault, but I don't know how to solve it.
Error Explanation
Error: expected "access_policy.0.object_id" to be a valid UUID .......
with azurerm_key_vault.kv,
│ on main.tf line 344, in resource "azurerm_key_vault" "kv":
│ 344: object_id = module.agw_user_assigned_identity.id
This means that in your resource azurerm_key_vault in the access_policy block the object_id attribute is getting the incorrect value more simply the incorrect value that azure API accepts for it.
It expects the principal_id output from the azurerm_user_assigned_identity resource in spite of id.
in azure id would be the URI of the resource itself in azure namespaces /subscriptions/<sub-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<resource-name>
So you need principal_id output in your module module.agw_user_assigned_identity and then use it in your key_vault module as follows
Terraform code
## inside module.agw_user_assigned_identity add an output , ignore if already exists
output "principal_id" {
value = azurerm_user_assigned_identity.base.principal_id
description = "Set accordingly or from terraform documentation"
}
## then use the above the output in key_vault module
module "key_vault" {
source = "../modules/resources/key_vault"
key_vault_name = local.key_vault_name
resource_group_location = module.resource_group.location
resource_group_name = module.resource_group.name
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = module.agw_user_assigned_identity.principal_id
soft_delete_retention_days = 90
log_analytics_workspace_id = module.log_analytics_workspace.id
enable_diagnostic_setting = true
}
That will solve the above error message.

Azure synapse linked service for Azure Function in Terraform

I'm writing a terraform script to create a azure synapse workspace.
I've created a linked service for Azure Function but I'm unable to use it in pipeline, where it gives me an error of missing function key.
This is what i'm using now. I'm sure the problem is in the type_properties_json parameter.
resource "azurerm_synapse_linked_service" "FunctionName" {
name = "FunctionName"
synapse_workspace_id = azurerm_synapse_workspace.synapse.id
type = "AzureFunction"
type_properties_json = <<JSON
{
"functionAppUrl": "https://${data.azurerm_function_app.FunctionName.default_hostname}",
"authentication": "Anonymous",
"functionKey": "${data.azurerm_function_app_host_keys.FunctionName.default_function_key}"
}
JSON
depends_on = [
azurerm_synapse_firewall_rule.allowAll,
data.azurerm_function_app.FunctionName,
data.azurerm_function_app_host_keys.FunctionName
]
}
And this does create a linked service but when i use it in a pipeline, the run fails with the error
Azure function activity missing function key.
It appears to me after checking the output for azurerm_function_app there is no export for connectionString.
I tried to reproduce the scenario in my environment.
Tried below code:
resource "azurerm_synapse_linked_service" "example" {
name = "kavya-fnapplinked"
synapse_workspace_id = azurerm_synapse_workspace.example.id
type = "AzureFunction"
type_properties_json = <<JSON
{
"functionAppUrl": "https://${data.azurerm_function_app.example.default_hostname}",
"authentication": "Anonymous",
"functionKey": "${data.azurerm_function_app_host_keys.example.default_function_key}"
}
JSON
depends_on = [
azurerm_synapse_firewall_rule.allowAll,
data.azurerm_function_app.example,
data.azurerm_function_app_host_keys.example
]
}
Got errors due to the json property and function key not being generated as expected as they are not in correct format.
For this ,note two important points:
Function key is only generated after the function app is created first and is a sensitive value.
Json format for sensitive values must be in below format
"secret":
{
"type": "SecureString",
"value": “{value}"
}
I have first stored the function key in keyvalut , so that it takes time to generate and get stored in secret.
Code:
resource "azurerm_role_assignment" "role_assignment" {
scope = azurerm_storage_account.stfn.id
role_definition_name = "Storage Blob Data Owner"
principal_id = data.azurerm_client_config.current.object_id
}
# used Sleep to wait for role assignment to take its time to propagate
resource "time_sleep" "role_assignment_sleep" {
create_duration = "60s"
triggers = {
role_assignment = azurerm_role_assignment.role_assignment.id
}
}
resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
name = "kavdatalakexample123"
storage_account_id = azurerm_storage_account.stfn.id
depends_on = [time_sleep.role_assignment_sleep]
}
resource "azurerm_synapse_workspace" "example" {
name = "exmple-workspace"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_storage_account.example.location
storage_data_lake_gen2_filesystem_id = azurerm_storage_data_lake_gen2_filesystem.example.id
sql_administrator_login = "sqladminuser"
sql_administrator_login_password = "H#Sh1CoR3!"
managed_virtual_network_enabled = true
identity {
type = "SystemAssigned"
}
}
resource "azurerm_synapse_firewall_rule" "allowAll" {
name = "allowAll"
synapse_workspace_id = azurerm_synapse_workspace.example.id
start_ip_address = "0.0.0.0"
end_ip_address = "255.255.255.255"
}
resource "azurerm_storage_account" "stfn" {
name = "kaexpleaccforfunct"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_storage_account.example.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_app_service_plan" "example" {
name = "exm-kavya-app-service-plan"
resource_group_name = data.azurerm_resource_group.example.name
location =data.azurerm_storage_account.example.location
kind = "FunctionApp"
sku {
tier = "Dynamic"
size = "Y1"
}
}
resource "azurerm_function_app" "example" {
name = "exm-kavya-function-app"
resource_group_name = data.azurerm_resource_group.example.name
location = data.azurerm_resource_group.example.location
// storage_connection_string = azurerm_storage_account.stfn.primary_connection_string
storage_account_name = azurerm_storage_account.stfn.name
storage_account_access_key = azurerm_storage_account.stfn.primary_access_key
app_service_plan_id = azurerm_app_service_plan.example.id
}
data "azurerm_function_app_host_keys" "example" {
resource_group_name = data.azurerm_resource_group.example.name
name= azurerm_function_app.example.name
}
output "function_key" {
value = data.azurerm_function_app_host_keys.example.default_function_key
sensitive = true
}
output "function_appurl" {
value = "https://${azurerm_function_app.example.default_hostname}"
}
resource "azurerm_key_vault" "example" {
name = "kavyaexamplekeyvault"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
enabled_for_disk_encryption = true
tenant_id = data.azurerm_client_config.current.tenant_id
soft_delete_retention_days = 7
purge_protection_enabled = false
sku_name = "standard"
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
key_permissions = [
"Create",
"Get",
]
secret_permissions = [
"Set",
"Get",
"Delete",
"Purge",
"Recover",
"List"
]
storage_permissions = [
"Get","Set"
]
}
}
resource "azurerm_key_vault_secret" "example" {
name = "functionkey"
value = data.azurerm_function_app_host_keys.example.default_function_key
key_vault_id = azurerm_key_vault.example.id
}
resource "azurerm_synapse_linked_service" "example" {
name = "kav-fnapplinked"
synapse_workspace_id = azurerm_synapse_workspace.example.id
type = "AzureFunction"
type_properties_json = <<JSON
{
"functionAppUrl": "https://${azurerm_function_app.example.default_hostname}",
"authentication": "Anonymous",
"functionKey":
{
"type": "SecureString",
"value": "${azurerm_key_vault_secret.example.value}"
}
"authentication": "Anonymous",
"functionKey":
{
"type": "SecureString",
"value": "${azurerm_key_vault_secret.example.value}"
}
}
JSON
depends_on = [
azurerm_synapse_firewall_rule.allowAll,
azurerm_function_app.example,
data.azurerm_function_app_host_keys.example
]
}
With abovecode I could successfully, create linked service.
Linked service for azure synapse workspace:
Reference: azure - Terraform issue creating the resource "azurerm_synapse_linked_service" specifically with the "type_properties_json" field - Stack Overflow

Terraform StorageProfile.dataDisks.lun does not have required value(s) for image specified in storage profile

I am trying to provision a linux image from my gallery that was generalized. However I am getting an error StorageProfile.dataDisks.lun does not have required value(s) for image specified in storage profile. However, the lun for datadisk is already set?
Looking around the closest I find is created linux image in azure, cant seem to deploy however as mentioned, the lun for the data disk has been set.
I am assuming the lun is for the OS disk but I don't set it in the [documentation][1]?
The image is based on Ubuntu 18.04 with one data disk attached on lun 0. It was customised and then generalized.
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.72.0"
}
}
}
provider "azurerm" {
features {}
}
#get my ip
data "http" "icanhazip" {
url = "http://icanhazip.com"
}
data "azurerm_ssh_public_key" "publickey" {
name = "x"
resource_group_name = "x"
}
data "azurerm_shared_image_version" "asgi" {
name = "x"
image_name = "x-generalized"
gallery_name = "x"
resource_group_name = data.azurerm_ssh_public_key.publickey.resource_group_name
}
output "public_ip" {
value = azurerm_public_ip.publicip.ip_address
}
data "azurerm_resource_group" "main" {
name = var.resource_group_name
}
data "azurerm_subnet" "vnet" {
name = var.subnet_name
virtual_network_name = var.virtual_network_name
resource_group_name = var.resource_group_name
}
# Create a Network Security Group with some rules
resource "azurerm_network_security_group" "main" {
name = "${var.linux_virtual_machine_name}-nsg"
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
tags = {
environment = var.environment
region = var.region
role = var.role
owner = var.owner
}
}
resource "azurerm_network_security_rule" "sg-inbound" {
name = "SG-inbound"
priority = 103
direction = "Inbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefixes = [
"x/32",
"x/32",
"x/32",
"x/32"
]
destination_address_prefix = "*"
resource_group_name = data.azurerm_resource_group.main.name
network_security_group_name = azurerm_network_security_group.main.name
}
resource "azurerm_network_security_rule" "sg-outbound" {
name = "SG-outbound"
priority = 104
direction = "Outbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefixes = [
"x/32",
"x/32",
"x/32",
"x/32"
]
resource_group_name = data.azurerm_resource_group.main.name
network_security_group_name = azurerm_network_security_group.main.name
}
resource "azurerm_network_security_rule" "mongorules" {
for_each = local.nsgrules
name = each.key
direction = each.value.direction
access = each.value.access
priority = each.value.priority
protocol = each.value.protocol
source_port_range = each.value.source_port_range
destination_port_range = each.value.destination_port_range
source_address_prefix = each.value.source_address_prefix
destination_address_prefix = each.value.destination_address_prefix
resource_group_name = data.azurerm_resource_group.main.name
network_security_group_name = azurerm_network_security_group.main.name
}
# Create a network interface for VMs and attach the PIP and the NSG
# Create public IPs
resource "azurerm_public_ip" "publicip" {
name = "${var.linux_virtual_machine_name}-publicip"
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
allocation_method = "Static"
sku = "Standard"
domain_name_label = var.linux_virtual_machine_name
tags = azurerm_network_security_group.main.tags
}
# create a network interface
resource "azurerm_network_interface" "nic" {
name = "${var.linux_virtual_machine_name}-nic"
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
tags = azurerm_network_security_group.main.tags
ip_configuration {
name = "${var.linux_virtual_machine_name}-publicip"
subnet_id = data.azurerm_subnet.vnet.id
private_ip_address_allocation = "dynamic"
public_ip_address_id = azurerm_public_ip.publicip.id
}
}
resource "azurerm_managed_disk" "dataDisk" {
name = "${var.linux_virtual_machine_name}-datadisk"
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
storage_account_type = "StandardSSD_LRS"
create_option = "Empty"
disk_size_gb = 250
tags = {
environment = var.environment
region = var.region
role = var.role
owner = var.owner
resource = "dataDisk"
}
}
# Create a new Virtual Machine based on the Golden Image
resource "azurerm_linux_virtual_machine" "vm" {
name = var.linux_virtual_machine_name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
network_interface_ids = ["${azurerm_network_interface.nic.id}"]
size = var.vm_size
admin_username = var.admin_username
computer_name = var.linux_virtual_machine_name
disable_password_authentication = true
source_image_id = data.azurerm_shared_image_version.asgi.id
tags = azurerm_network_security_group.main.tags
os_disk {
name = "${var.linux_virtual_machine_name}-osDisk"
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
admin_ssh_key {
username = "x"
public_key = data.azurerm_ssh_public_key.publickey.public_key
}
}
resource "azurerm_virtual_machine_data_disk_attachment" "attachDisk" {
managed_disk_id = azurerm_managed_disk.dataDisk.id
virtual_machine_id = azurerm_linux_virtual_machine.vm.id
lun = 1
caching = "ReadWrite"
depends_on = [
azurerm_linux_virtual_machine.vm
]
}```
[1]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine
Please use below:
resource "azurerm_virtual_machine_data_disk_attachment" "attachDisk" {
managed_disk_id = azurerm_managed_disk.dataDisk.id
virtual_machine_id = azurerm_linux_virtual_machine.vm.id
lun = "1"
caching = "ReadWrite"
depends_on = [
azurerm_linux_virtual_machine.vm
]
}```
Instead of
resource "azurerm_virtual_machine_data_disk_attachment" "attachDisk" {
managed_disk_id = azurerm_managed_disk.dataDisk.id
virtual_machine_id = azurerm_linux_virtual_machine.vm.id
lun = 1
caching = "ReadWrite"
depends_on = [
azurerm_linux_virtual_machine.vm
]
}```
OR
Please check if lun 1 is being used by any other data disk that you have created earlier.
Reference:
azurerm_virtual_machine_data_disk_attachment | Resources | hashicorp/azurerm | Terraform Registry

Provisioning a Windows VM in Azure with WinRM port (5986) open

I'm trying to provision a windows vm on Azure with Terraform with the port 5986 open to allow winrm access. The provisioning of the VM works.
I'm stuck on opening the port with terraform during provisioning. Any ideas?
You can follow the terraform script to create a windows server 2016 datacenter and open the default RDP port 3389 and port 5986 in NSG. It works for me.
Terraform v0.11.8
+ provider.azurerm v1.14.0
+ provider.random v2.0.0
The full sample
variable "resourcename" {
default = "myResourceGroup"
}
# Configure the Microsoft Azure Provider
provider "azurerm" {
subscription_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_secret = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
tenant_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
# Create a resource group if it doesn’t exist
resource "azurerm_resource_group" "myterraformgroup" {
name = "myResourceGroup"
location = "eastus"
tags {
environment = "Terraform Demo"
}
}
# Create virtual network
resource "azurerm_virtual_network" "myterraformnetwork" {
name = "myVnet"
address_space = ["10.0.0.0/16"]
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
tags {
environment = "Terraform Demo"
}
}
# Create subnet
resource "azurerm_subnet" "myterraformsubnet" {
name = "mySubnet"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
virtual_network_name = "${azurerm_virtual_network.myterraformnetwork.name}"
address_prefix = "10.0.1.0/24"
}
# Create public IPs
resource "azurerm_public_ip" "myterraformpublicip" {
name = "myPublicIP"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
public_ip_address_allocation = "dynamic"
tags {
environment = "Terraform Demo"
}
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "myterraformnsg" {
name = "myNetworkSecurityGroup"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
security_rule {
name = "RDP"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "WinRM"
priority = 998
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5986"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags {
environment = "Terraform Demo"
}
}
# Create network interface
resource "azurerm_network_interface" "myterraformnic" {
name = "myNIC"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}"
ip_configuration {
name = "myNicConfiguration"
subnet_id = "${azurerm_subnet.myterraformsubnet.id}"
private_ip_address_allocation = "dynamic"
public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}"
}
tags {
environment = "Terraform Demo"
}
}
# Generate random text for a unique storage account name
resource "random_id" "randomId" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group = "${azurerm_resource_group.myterraformgroup.name}"
}
byte_length = 8
}
# Create storage account for boot diagnostics
resource "azurerm_storage_account" "mystorageaccount" {
name = "diag${random_id.randomId.hex}"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
location = "eastus"
account_tier = "Standard"
account_replication_type = "LRS"
tags {
environment = "Terraform Demo"
}
}
# Create virtual machine
resource "azurerm_virtual_machine" "myterraformvm" {
name = "myVM"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_interface_ids = ["${azurerm_network_interface.myterraformnic.id}"]
vm_size = "Standard_DS1_v2"
storage_os_disk {
name = "myOsDisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
storage_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
os_profile {
computer_name = "myvm"
admin_username = "azureuser"
admin_password = "Password1234!"
}
os_profile_windows_config {
enable_automatic_upgrades = false
}
boot_diagnostics {
enabled = "true"
storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}"
}
tags {
environment = "Terraform Demo"
}
}

Resources