terraform on azure - create keyvault with private connection - azure

Would like to get some pointers on setting up a key vault with a private connection. Looking at the examples on the TF site and other sites I put this together but it crashes.
In short, it creates the KV, assigns some policies, and then creates the private link which is in turn associated with the service endpoint. Any help would be greatly appreciated.
locals {
prefix = "kv01am"
}
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault" "sandbox" {
name = "${local.prefix}-KV"
location = "eastus2"
resource_group_name = "rg-hsc-uscodappname01-137941ad"
enabled_for_disk_encryption = true
tenant_id = data.azurerm_client_config.current.tenant_id
# soft_delete_enabled = true
# 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 = [
"get",
]
secret_permissions = [
"get",
]
storage_permissions = [
"get",
]
}
network_acls {
default_action = "Deny"
bypass = "AzureServices"
}
}
resource "azurerm_private_link_service" "example" {
name = "kv-privatelink"
location = "eastus2"
resource_group_name = "rg-hsc-uscodappname01-137941ad"
nat_ip_configuration {
name = azurerm_public_ip.example.name
primary = true
subnet_id = "zzzzzzzzzzzzzzzzzzzzzzzz"
}
}
resource "azurerm_private_endpoint" "sandbox_kv" {
name = azurerm_key_vault.sandbox.name
location = "eastus2"
resource_group_name = "rg-hsc-uscodappname01-137941ad"
#subnet_id = azurerm_subnet.sandbox["PrivateLink"].id
subnet_id = "zzzzzzzzzzzzzzzz"
private_service_connection {
name = azurerm_key_vault.sandbox.name
private_connection_resource_id = azurerm_key_vault.sandbox.id
is_manual_connection = false
subresource_names = ["Vault"]
}
}

Instead of creating dns record "manually" you could have a private_dns_zone_group declared.
# ============PrivateLink==========================
resource "azurerm_private_endpoint" "pe_kv" {
name = format("pe-2%s", var.name)
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
subnet_id = data.azurerm_subnet.main.id
private_dns_zone_group {
name = "privatednszonegroup"
private_dns_zone_ids = [azurerm_private_dns_zone.main.id]
}
private_service_connection {
name = format("pse-2%s", var.name)
private_connection_resource_id = azurerm_key_vault.main.id
is_manual_connection = false
subresource_names = ["Vault"]
}
}
resource "azurerm_private_dns_zone" "main" {
name = "privatelink.vaultcore.azure.net"
resource_group_name = data.azurerm_resource_group.main.name
}

This is what I ended up doing. Could not find a good way to derive the ip address for the private link endpoint so I just hard coded it, if someone has a better way to handle this that would be great, not too much literature on that subject. Also, added a section to register the A record in private DNS but beware this creates a DNS Private zone in the same subnet as the kv.
data "azurerm_resource_group" "main" {
name = var.resource_group_name
}
data "azurerm_subnet" "main" {
name = var.virtual_network_subnet_name
virtual_network_name = var.virtual_network_name
resource_group_name = var.vnet_resource_group_name
}
data "azurerm_client_config" "main" {}
resource "azurerm_key_vault" "main" {
name = var.name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
tenant_id = data.azurerm_client_config.main.tenant_id
enabled_for_deployment = var.enabled_for_deployment
enabled_for_disk_encryption = var.enabled_for_disk_encryption
enabled_for_template_deployment = var.enabled_for_template_deployment
# soft_delete_enabled = false
# purge_protection_enabled = false
sku_name = var.sku
network_acls {
default_action = "Deny"
bypass = "AzureServices"
# ip_rules = var.ip_rules
}
# ============PrivateLink==========================
resource "azurerm_private_endpoint" "pe_kv" {
name = format("pe-2%s", var.name)
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
subnet_id = data.azurerm_subnet.main.id
private_service_connection {
name = format("pse-2%s", var.name)
private_connection_resource_id = azurerm_key_vault.main.id
is_manual_connection = false
subresource_names = ["Vault"]
}
}
resource "azurerm_private_dns_zone" "main" {
name = "privatelink.vaultcore.azure.net"
resource_group_name = data.azurerm_resource_group.main.name
}
resource "azurerm_private_dns_a_record" "pe_kv" {
name = var.name
zone_name = azurerm_private_dns_zone.main.name
resource_group_name = data.azurerm_resource_group.main.name
ttl = 300
records = ["1.2.3.4"]
}
output kv_private_ip {
value = ["1.2.3.4"]
}

This is how I get fqdn and private IP:
resource "azurerm_private_endpoint" "private_endpoint" {
count = var.private_link_subnet != null ? 1 : 0
name = "${var.private_link_subnet.virtual_network_name}-${var.name}"
location = var.location
resource_group_name = var.resource_group
subnet_id = var.private_link_subnet.id
private_service_connection {
is_manual_connection = false
name = "${var.private_link_subnet.virtual_network_name}-${var.name}"
private_connection_resource_id = azurerm_key_vault.vault.id
subresource_names = ["vault"]
}
lifecycle { ignore_changes = [tags] }
}
resource "null_resource" "dns_update" {
triggers = {
priv_fqdn = "${azurerm_private_endpoint.private_endpoint[0].custom_dns_configs[0].fqdn}"
priv_ip = "${azurerm_private_endpoint.private_endpoint[0].custom_dns_configs[0].ip_addresses[0]}"
}
provisioner "local-exec" {
when = destroy
command = <<EOF
echo ${self.triggers.priv_fqdn}
bash ${path.module}/dns_update.sh destroy ${self.triggers.priv_fqdn}
EOF
}
provisioner "local-exec" {
command = <<EOF
echo ${self.triggers.priv_fqdn}
echo ${self.triggers.priv_ip}
bash ${path.module}/dns_update.sh apply ${self.triggers.priv_fqdn} ${self.triggers.priv_ip}
bash ${path.module}/dns_update.sh get ${self.triggers.priv_fqdn}
EOF
}
}
then I have:
self.triggers.priv_fqdn >> szp.vaultcore.azure.net
self.triggers.priv_ip >> 10.10.8.205

Related

Azure VM: AzureADJoined is "No" even after enabling the AADLoginForWindows extension

I have created a VM in Azure as mentioned below
resource "azurerm_windows_virtual_machine" "virtual_machine_hub" {
name = "vm-hub"
resource_group_name = azurerm_resource_group.ipz12-dat-np-connection-rg.name
location = azurerm_resource_group.ipz12-dat-np-connection-rg.location
size = "Standard_B8ms"
admin_username = "xxxxx"
admin_password = "xxxxx"
network_interface_ids = [
azurerm_network_interface.virtual_machine_hub_nic.id
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsDesktop"
offer = "Windows-10"
sku = "21h1-pro"
version = "latest"
}
depends_on = [
azurerm_network_interface.virtual_machine_hub_nic
]
}
and enabled the AADLoginForWindows extension
resource "azurerm_virtual_machine_extension" "virtual_machine_hub_ext" {
name = "AADLoginForWindows"
virtual_machine_id = azurerm_windows_virtual_machine.virtual_machine_hub.id
type = "AADLoginForWindows"
type_handler_version = "1.0"
auto_upgrade_minor_version = true
publisher = "Microsoft.Azure.ActiveDirectory"
depends_on = [
azurerm_windows_virtual_machine.virtual_machine_hub
] }
however "dsregcmd /status" command shows that it is not connected with Azure AD domain like AzureADJoined is "No"
In order to register the VM in Azure AD, I don't feel that I have the appropriate permissions. If that's the case, what level of permission is required? and what am I missing?
Note: I have manually joined Azure AD like mentioned below
As discussed here, it is described that aadj private extension also to be created for a virtual machine under path:
HKLM\SOFTWARE\Microsoft\RDInfraAgent\AADJPrivate
So, another Custom script extension was added to add the key AADJPRIVATE for the VM.
Followed this template given by #Ansuman Bal in SO thread for Azure AD VM join and made a few changes to achieve the expected results as per your requirements.
vi main.tf:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.37.0"
}
}
}
provider "azurerm" {
features {}
}
provider "azuread" {}
data "azuread_group" "aad_group" {
display_name = "<ADGroup>"
security_enabled = true
}
data "azurerm_role_definition" "vm_user_login" {
name = "<VM User Login>"
}
resource "azurerm_role_assignment" "vm_user_role" {
scope = azurerm_resource_group.rg-xxx.id
role_definition_id = data.azurerm_role_definition.vm_user_login.id
principal_id = data.azuread_group.aad_group.id
}
data "azurerm_role_definition" "desktop_user" {
name = "xxxxxx User"
}
resource "azurerm_role_assignment" "desktop_role" {
scope = azurerm_virtual_desktop_application_group.desktopapp.id
role_definition_id = data.azurerm_role_definition.desktop_user.id
principal_id = data.azuread_group.aad_group.id
}
resource "azurerm_resource_group" "eg-RG" {
name = "xxxxxtest"
location = "West Europe"
}
resource "azurerm_virtual_network" "vnet" {
name = "xxxx-vnet"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
address_space = ["10.0.0.0/16"]
}
resource "azurerm_subnet" "xxxxdefaultSubnet" {
name = "xxxxxsubnet"
resource_group_name = azurerm_resource_group.eg-RG.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.0.0/24"]
}
resource "azurerm_network_security_group" "nsg" {
name = "xxxx-nsg"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
security_rule {
name = "allow-rdp"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = 3389
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "nsg_association" {
subnet_id = azurerm_subnet.xxxxdefaultSubnet.id
network_security_group_ID = azurerm_network_security_group.<nsg>.id
}
resource "time_rotating" Gen_token" {
rotation_days = 30
}
resource "azurerm_virtual_desktop_host_pool" "new-hp" {
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
name = "xxxxxhostpool"
friendly_name = "samplepool"
validate_environment = true
start_vm_on_connect = true
custom_rdp_properties = "audiocapturemode:i:1;audiomode:i:0;targetisaadjoined:i:1;"
description = "host-poool demo"
type = "Pooled"
maximum_sessions_allowed = 10
load_balancer_type = "DepthFirst"
}
resource "azurerm_virtual_desktop_host_pool_registration_info" "reginfo" {
hostpool_id = azurerm_virtual_desktop_host_pool.new-hp.id
expiration_date = time_rotating.avd_token.rotation_rfc3339
}
resource "azurerm_virtual_desktop_application_group" "desktopapp" {
name = "xxxx-Desktop"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
type = "Desktop"
host_pool_id = azurerm_virtual_desktop_host_pool.new-hp.id
friendly_name = "xxxxx"
description = "xxxxapplications"
}
resource "azurerm_virtual_desktop_workspace" "workspace" {
name = "xxxxxx-WORKSPACE"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
friendly_name = "xxxxxxx"
description = "Purporse"
}
resource "azurerm_virtual_desktop_workspace_application_group_association" "sampleworkspaceremoteapp" {
workspace_id = azurerm_virtual_desktop_workspace.workspace.id
application_group_id = azurerm_virtual_desktop_application_group.desktopapp.id
}
resource "azurerm_network_interface" "xxxx_nic" {
count=2
name = "xxxx-${count.index}"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.xxxxxdefaultSubnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_windows_virtual_machine" "sessionhost" {
depends_on = [
azurerm_network_interface.sessionhost_nic
]
count=2
name = "xxxvm-${count.index}"
resource_group_name = azurerm_resource_group.eg-RG.name
location = azurerm_resource_group.eg-RG.location
size = "Standard_B2MS"
admin_username = "useradmin"
admin_password = "<Password>"
provision_vm_agent = true
network_interface_ids = [azurerm_network_interface.sessionhost_nic.*.id[count.index]]
identity {
type = "SystemAssigned"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsDesktop"
offer = "Windows-10"
sku = "20h2-evd"
version = "latest"
}
}
locals {
registration_token = "${azurerm_virtual_desktop_host_pool_registration_info.reginfo.token}"
shutdown_command = "shutdown -r -t 10"
exit_code_hack = "exit 0"
commandtorun = "New-Item -Path HKLM:/SOFTWARE/Microsoft/RDInfraAgent/AADJPrivate"
powershell_command = "${local.commandtorun}; ${local.shutdown_command}; ${local.exit_code_hack}"
}
resource "azurerm_virtual_machine_extension" "xxxAVDModule" {
depends_on = [
azurerm_windows_virtual_machine.xxx_sessionhost
]
count = 2
name = "Microsoft.PowerShell.DSC"
virtual_machine_id = azurerm_windows_virtual_machine.avd_sessionhost.*.id[count.index]
publisher = "Microsoft.Powershell"
type = "DSC"
type_handler_version = "2.73"
settings = <<-SETTINGS
{
"modulesUrl": "https://wvdportalstorageblob.blob.core.windows.net/galleryartifacts/Configuration_11-22-2021.zip",
"ConfigurationFunction": "Configuration.ps1\\AddSessionHost",
"Properties" : {
"hostPoolName" : "${azurerm_virtual_desktop_host_pool.new-hp.name}",
"aadJoin": true
}
}
SETTINGS
protected_settings = <<PROTECTED_SETTINGS
{
"properties": {
"registrationInfoToken": "${azurerm_virtual_desktop_host_pool_registration_info.reginfo.token}"
}
}
PROTECTED_SETTINGS
}
resource "azurerm_virtual_machine_extension" "AADLoginForWindows" {
depends_on = [
azurerm_windows_virtual_machine.xxxx_sessionhost,
azurerm_virtual_machine_extension.AVDModule
]
count = 2
name = "AADLoginForWindows"
virtual_machine_id = azurerm_windows_virtual_machine.avd_sessionhost.*.id[count.index]
publisher = "Microsoft.Azure.ActiveDirectory"
type = "AADLoginForWindows"
type_handler_version = "1.0"
auto_upgrade_minor_version = true
}
resource "azurerm_virtual_machine_extension" "xxxxaadjprivate" {
depends_on = [
azurerm_virtual_machine_extension.AADLoginForWindows
]
count = 2
name = "AADJPRIVATE"
virtual_machine_id = azurerm_windows_virtual_machine.avd_sessionhost.*.id[count.index]
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
settings = <<SETTINGS
{
"commandToExecute": "powershell.exe -Command \"${local.powershell_command}\""
}
SETTINGS
}
terraform plan:
terraform apply:
VM Joined in AD after deployment:
Virtual Machine Overview:

How to implement in terraform azure for redis with private endpoint?

I need help with terraform. I need deploy azure for redis cache using private endpoint. My code:
resource "azurerm_redis_cache" "redis_cache_example" {
name = "redis-cache-ex"
location = var.location
resource_group_name = var.resource_group_name
capacity = var.redis_plan_capacity
family = var.redis_plan_family
sku_name = var.redis_plan_sku_name
enable_non_ssl_port = false
minimum_tls_version = "1.2"
public_network_access_enabled = false
}
resource "azurerm_private_dns_zone" "private_dns_zone_example" {
name = "example.redis-ex.azure.com"
resource_group_name = var.resource_group_name
}
resource "azurerm_private_dns_zone_virtual_network_link" "virtual_network_link_example" {
name = "exampleVnet.com"
private_dns_zone_name = azurerm_private_dns_zone.private_dns_zone_example.name
virtual_network_id = var.vnet_id
resource_group_name = var.resource_group_name
}
resource "azurerm_private_endpoint" "redis_pe_example" {
name = "redis-private-endpoint-ex"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = var.subnet_id
private_dns_zone_group {
name = "privatednsrediszonegroup"
private_dns_zone_ids = [azurerm_private_dns_zone.private_dns_zone_example.id]
}
private_service_connection {
name = "peconnection-example"
private_connection_resource_id = azurerm_redis_cache.redis_cache_example.id
is_manual_connection = false
subresource_names = ["redisCache"]
}
}
After deploying my redis doesn't ping within vnet. What's wrong with my terraform?
You can also add an azurerm_private_endpoint resource and link it to azurerm_redis_cache (or i guess other resource as well).
resource "azurerm_redis_cache" "default" {
...
}
resource "azurerm_private_endpoint" "default" {
count = 1
name = format("%s-redis%d", var.env, count.index + 1)
resource_group_name = data.azurerm_resource_group.default.name
location = data.azurerm_resource_group.default.location
subnet_id = data.azurerm_subnet.default.id
private_service_connection {
name = format("%s-redis%d-pe", var.env, count.index + 1)
private_connection_resource_id = azurerm_redis_cache.default[count.index].id
is_manual_connection = false
subresource_names = ["redisCache"]
}
}
You can find list of other private resources on AZ docs.

Terraform - Creating Private link for Postgresql

I want to create a private link for postgres database. The config shown in the screenshot is exactly I want to configure suing TERRAFORM but could not find any solution.
DNS CONFIG
I tried using following TERRAFORM code
resource "azurerm_private_dns_zone" "priv-dns" {
name = var.azurerm_private_dns_zone_name
resource_group_name = var.resource_group_name
}
resource "azurerm_private_dns_zone_virtual_network_link" "priv-dns-link" {
name = "priv-dns-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.priv-dns.name
virtual_network_id = var.virtual_network_id
registration_enabled = true
}
resource "azurerm_private_endpoint" "sql_postgres" {
name = var.postgresql_private_endpoint
location = var.location
resource_group_name = var.resource_group_name
subnet_id = var.data_subnet_id
private_service_connection {
name = var.postgresql_private_link
private_connection_resource_id = azurerm_postgresql_server.postgresql.id
subresource_names = ["postgresqlServer"]
is_manual_connection = false
}
private_dns_zone_group {
name = "dns-group"
private_dns_zone_ids = [ azurerm_private_dns_zone.priv-dns.id ]
}
}
I end up getting below DNS config which doesn't work
wrong DNS config
Use this full example to modify to your own needs. Important is to not change the DNS zone name.
resource "azurerm_private_dns_zone" "pgdb" {
name = "privatelink.postgres.database.azure.com"
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_private_dns_zone_virtual_network_link" "pgdb" {
name = "${local.prefix}-pg-pl"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.pgdb.name
virtual_network_id = azurerm_virtual_network.vnet.id
}
resource "azurerm_private_endpoint" "pgdb_primary" {
name = "${local.prefix}-pg-pe"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
subnet_id = azurerm_subnet.snet_datastores.id
private_dns_zone_group {
name = "privatepgdb"
private_dns_zone_ids = [azurerm_private_dns_zone.pgdb.id]
}
private_service_connection {
name = "pg-psconn"
private_connection_resource_id = azurerm_postgresql_server.pgprimary.id
subresource_names = ["postgresqlServer"]
is_manual_connection = false
}
}

Terraform Azure Application Gateway does not have secrets get permission on key vault

I am trying to terraform the provision of azure application gateway with trusted_root_certificates certificates in a key vault. But I am getting the following error:
"message":"The user, group or application 'name=Microsoft.Network/applicationGateways;appid=some-id;iss=https://sts.windows.net/xxx-xxx/' does not have secrets get permission on key vault 'jana-kv-ssi-test;location=australiaeast'.
And here's my terrafom code:
module "cert-kv" {
source = "./modules/kv"
resource_group_name = var.resource_group_name
project = var.project
location = var.location
environment = var.environment
default_tags = var.default_tags
kv_sku = var.kv_sku
kv_name = var.kv_name
kv_key_permissions = var.kv_key_permissions
kv_secret_permissions = var.kv_secret_permissions
kv_storage_permissions = var.kv_storage_permissions
certificate_permissions = var.certificate_permissions
cert_name = var.cert_name
local_cert_path = var.local_cert_path
local_cert_password = var.local_cert_password
root_cert_name = var.root_cert_name
root_cert_local_cert_path = var.root_cert_local_cert_path
root_cert_local_cert_password = var.root_cert_local_cert_password
}
module "app-gateway" {
source = "./modules/app_gateway"
resource_group_name = var.resource_group_name
environment = var.environment
default_tags = var.default_tags
project = var.project
location = var.location
gw_sku_name = var.gw_sku_name
gw_tier = var.gw_tier
frontend_port_settings = var.frontend_port_settings
autoscale_configuration_max_capacity = var.autoscale_configuration_max_capacity
appgw_zones = var.appgw_zones
appgw_private_ip = var.appgw_private_ip
appgw_subnet_id = module.application-subnets.app_subnet_id
cipher_suites = var.cipher_suites
tls_version = var.tls_version
appgw_backend_pools = var.appgw_backend_pools
appgw_backend_http_settings = var.appgw_backend_http_settings
appgw_http_listeners = var.appgw_http_listeners
ssl_certificates_configs = var.ssl_certificates_configs
appgw_routings = var.appgw_routings
appgw_redirect_configuration = var.appgw_redirect_configuration
gw_key_vault_id = module.cert-kv.keyvault_id # var.gw_key_vault_id
health_probe_config = var.health_probe_config
kv_secret_id_for_root_cert = module.cert-kv.root_secret_id
kv_secret_name_for_root_cert = var.root_cert_name
depends_on = [module.application-subnets, module.cert-kv]
}
And here are the resource files for above modules.
# key-vault
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault" "cert_kv" {
name = join("-", [var.project, var.environment, var.kv_name])
location = var.location
resource_group_name = var.resource_group_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 = var.kv_sku
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
key_permissions = var.kv_key_permissions
secret_permissions = var.kv_secret_permissions
storage_permissions = var.kv_storage_permissions
certificate_permissions = var.certificate_permissions
}
tags = var.default_tags
}
resource "azurerm_key_vault_certificate" "certs" {
name = var.cert_name
key_vault_id = azurerm_key_vault.cert_kv.id
certificate {
contents = filebase64(var.local_cert_path)
password = var.local_cert_password
}
}
resource "azurerm_key_vault_certificate" "root_cert" {
name = var.root_cert_name
key_vault_id = azurerm_key_vault.cert_kv.id
certificate {
contents = filebase64(var.root_cert_local_cert_path)
password = var.root_cert_local_cert_password
}
}
resource "azurerm_user_assigned_identity" "key_vault_read" {
resource_group_name = var.resource_group_name
location = var.location
name = join("-", [var.project, var.environment, "key_vault_read_permission"])
}
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault_access_policy" "key_vault_role_policy" {
key_vault_id = var.gw_key_vault_id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = azurerm_user_assigned_identity.key_vault_read.principal_id
key_permissions = [
"Get","List",
]
secret_permissions = [
"Get","List",
]
}
# app-gw
resource "azurerm_application_gateway" "application-gateway" {
name = join("-", [var.project, var.environment, "app-gateway"])
location = var.location
resource_group_name = var.resource_group_name
tags = var.default_tags
sku {
name = var.gw_sku_name
tier = var.gw_tier
}
. . .
trusted_root_certificate {
name = var.kv_secret_name_for_root_cert
key_vault_secret_id = var.kv_secret_id_for_root_cert
}
. . .
identity {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.key_vault_read.id]
}
lifecycle {
ignore_changes = [
url_path_map,
request_routing_rule
]
}
}
Can someone please help me?

how to deploy two vm to two different resource group

Does anyone could give a hint on how should i do. i want to deploy 4 Az linux VM but 2 in each different resource group.
eg: rg-one will have 2 linux and rg-two will the other two
the way i did it is too create two block with azure_linux_virtual_machine, it is working but i was wondering if it could not be simplify.
thank in advance for the head up
here a snipped what i have done.
# Fetch exisiting resource_group
data "azurerm_resource_group" "rg-dock001" {
name = var.resource_group01
}
# Fetch vm network
data "azurerm_virtual_network" "vm_network" {
name = var.vm_network
resource_group_name = var.rg_name_network
}
output "azurerm_virtual_network" {
value = data.azurerm_virtual_network.vm_network.id
}
# Fetch vm subnet
data "azurerm_subnet" "vm_subnet" {
name = var.vm_subnet
resource_group_name = var.rg_name_network
virtual_network_name = var.vm_network
}
output "subnet_id" {
value = data.azurerm_subnet.vm_subnet.id
}
resource "azurerm_network_interface" "ens124-01" {
name = var.vm_nic01[count.index]
count = length(var.vm_nic01)
location = var.rg_location
resource_group_name = var.resource_group01
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "10.241.25.${count.index + 10}"
}
tags = var.vm_tags
}
output "private_ip01" {
value = length(azurerm_network_interface.ens124-01.*.private_ip_address)
}
# Fetch existing image
data "azurerm_image" "custom_docker_image" {
name_regex = var.packer_image
sort_descending = true
resource_group_name = var.resource_group_image
}
output "image_id" {
value = data.azurerm_image.custom_docker_image.id
}
# create and display an SSH key
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = 4096
}
output "tls_private_key" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
}
resource "azurerm_linux_virtual_machine" "main01" {
name = var.vm_name01[count.index]
count = length(var.vm_name01)
resource_group_name = var.resource_group01
location = var.rg_location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.ens124-01.*.id, count.index)}"]
source_image_id = data.azurerm_image.custom_docker_image.id
computer_name = var.vm_name01[count.index]
admin_ssh_key {
username = var.ssh_username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-0${count.index + 1}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
tags = var.vm_tags
}
data "azurerm_resource_group" "rg-dock002" {
name = var.resource_group02
}
resource "azurerm_network_interface" "ens124-02" {
name = var.vm_nic02[count.index]
count = length(var.vm_nic02)
location = var.rg_location
resource_group_name = var.resource_group02
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "10.241.25.${count.index + 20}"
}
tags = var.vm_tags
}
output "private_ip02" {
value = length(azurerm_network_interface.ens124-02.*.private_ip_address)
}
resource "azurerm_linux_virtual_machine" "main02" {
name = var.vm_name02[count.index]
count = length(var.vm_name02)
resource_group_name = var.resource_group02
location = var.rg_location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.ens124-02.*.id, count.index)}"]
source_image_id = data.azurerm_image.custom_docker_image.id
computer_name = var.vm_name02[count.index]
admin_ssh_key {
username = var.ssh_username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-0${count.index + 1}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
tags = var.vm_tags
}````
As per your requirement you can use something like below :
provider "azurerm" {
features {}
}
variable "VM" {
default= {
vm1={
rg_name= "ajaytest",
vnet_name="ajay-vnet",
subnet_name="default",
nic_name = "ansumanVM-nic",
private_ip="10.0.0.10",
vm_name="ansumanVM"
},
vm2={
rg_name= "kartiktest",
vnet_name="kartik-vnet",
subnet_name="default",
nic_name="terraformVM-nic",
private_ip="10.0.0.20",
vm_name="terraformVM"
}
}
}
variable "username" {
default="ansuman"
}
variable "password" {
default="Password#1234!"
}
data "azurerm_shared_image_version" "example" {
name = "0.0.1"
image_name = "UbuntuwithNginxinstalled"
gallery_name = "ansumantestgallery"
resource_group_name = "ansumantest"
}
data "azurerm_resource_group" "rg-dock" {
for_each = var.VM
name = each.value["rg_name"]
}
# Fetch vm network
data "azurerm_virtual_network" "vm_network" {
for_each = var.VM
name = each.value["vnet_name"]
resource_group_name = each.value["rg_name"]
}
# Fetch vm subnet
data "azurerm_subnet" "vm_subnet" {
for_each = var.VM
name = each.value["subnet_name"]
resource_group_name = each.value["rg_name"]
virtual_network_name = each.value["vnet_name"]
}
resource "azurerm_network_interface" "ens124" {
for_each = var.VM
name = each.value["nic_name"]
location = data.azurerm_resource_group.rg-dock[each.key].location
resource_group_name = data.azurerm_resource_group.rg-dock[each.key].name
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet[each.key].id
private_ip_address_allocation = "Static"
private_ip_address = each.value["private_ip"]
}
}
# create and display an SSH key
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = 4096
}
output "tls_private_key" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
}
resource "azurerm_linux_virtual_machine" "main" {
for_each = var.VM
name = each.value["vm_name"]
resource_group_name = data.azurerm_resource_group.rg-dock[each.key].name
location = data.azurerm_resource_group.rg-dock[each.key].location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = [azurerm_network_interface.ens124[format("%s", each.key)].id]
source_image_id = data.azurerm_shared_image_version.example.id
computer_name = each.key
admin_ssh_key {
username = var.username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-${each.key}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
}
Note: The admin username and the ssh username must be the same due the below limitation :
And the location of the VM ,Vnet ,Image and other resources must be the same.
Output:

Resources