Terraform - Azure - Virtual Network - Subnets output shuffle - azure

We are using Terraform CLI on Azure, We have code for each subscription which create default Storage accounts, keyvault, VNet with subnet etc. Then we get the output of these services. In the output we also have info related to the VNET Subnets. We had less than 10 subnets before and we created VMs by giving reference of that output of the subnet. After adding more subnets in the same code we observed that after creating more subnets the output of the VNet->subnets has been readjusted/shuffled as shown below:
Changes to Outputs:
~ msdn_eastus_aks01 = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_aks01" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_webapp"
~ msdn_eastus_apimgt = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_apimgt" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_utility"
~ msdn_eastus_app = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_app" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_int_web"
~ msdn_eastus_appgw = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_appgw" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_apimgt"
~ msdn_eastus_db = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_db" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_app"
~ msdn_eastus_int_web = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_int_web" -> (known after apply)
~ msdn_eastus_utility = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_utility" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_db"
~ msdn_eastus_webapp = "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_webapp" -> "/subscriptions/xxxxxxxx-xxxxxxxx-xxx-xxxxxxxxxxxf/resourceGroups/msdn-eastus-test-subdefault/providers/Microsoft.Network/virtualNetworks/vnet-eastus-test-msdn/subnets/msdn_eastus_appgw"
So if we rerun the code of same VMs the referred subnet got changed so the SAME VM is getting the new ip from the different subnet as shown above

Related

Terraform thinks Azure CDN Front Door route has been modified every time I run a plan

I'm setting up an Azure CDN Front Door Profile using Terraform.
I'm having a problem with Terraform thinking that my routes have been changed every time I run a plan, even though they haven't been modified:
# azurerm_cdn_frontdoor_route.main-fe-resources will be updated in-place
~ resource "azurerm_cdn_frontdoor_route" "main-fe-resources" {
~ cdn_frontdoor_origin_group_id = "/subscriptions/e68adbb2-af8e-4b01-a7e8-2bf599d6d818/resourcegroups/ci-redacted-frontdoor/providers/Microsoft.Cdn/profiles/ci-redacted-frontdoor/origingroups/main-fe" -> "/subscriptions/e68adbb2-af8e-4b01-a7e8-2bf599d6d818/resourceGroups/ci-redacted-frontdoor/providers/Microsoft.Cdn/profiles/ci-redacted-frontdoor/originGroups/main-fe"
id = "/subscriptions/e68adbb2-af8e-4b01-a7e8-2bf599d6d818/resourceGroups/ci-redacted-frontdoor/providers/Microsoft.Cdn/profiles/ci-redacted-frontdoor/afdEndpoints/ci-main/routes/main-fe-resources"
name = "main-fe-resources"
# (8 unchanged attributes hidden)
# (2 unchanged blocks hidden)
}
The problems seems to be related to casing discrepancies between "resourceGroups" / "resourcegroups" and "originGroups" / "origingroups".
I've tried lowercasing the origin group ID in the Terraform script, but Terraform then complains that the ID doesn't contain the required string "originGroups".
I'm creating the routes like so:
resource "azurerm_cdn_frontdoor_route" "main-fe-resources" {
name = "main-fe-resources"
cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.main.id
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.main-fe.id
cdn_frontdoor_origin_ids = []
cdn_frontdoor_rule_set_ids = []
enabled = true
forwarding_protocol = "MatchRequest"
https_redirect_enabled = true
patterns_to_match = ["/assets-2022/*", "/_next/*"]
supported_protocols = ["Http", "Https"]
}
Any ideas?
So it does appear to be a bug in the provider. I originally created the routes manually, then added them to the Terraform state. I found that if I delete the routes and let Terraform recreate them then the problem goes away.
It's not an ideal solution, but at least the Terraform plans no longer detect changes when there aren't any.

how to pass list input to aws vpc elb in terraform

here i'm trying to provision a aws classic ELB in a VPC where i have 2 public subnets. These subnets are also provisioned by terraform and i'm trying to pass both the subnets ids to elb module.SO the problem is i'm not able to give list input to elb subnets field
public_subnet variable works fine as i have used it for route table association it's just that i'm not able to handle the list and give it as input to vpc.
it works if i use subnets = [var.public_subnet.0,var.public_subnet.1]
here's my code
resource "aws_elb" "webelb" {
name = "foobar-terraform-elb"
#availability_zones = [var.public_subnet]
subnets = [var.public_subnet]
#
#
#
}
variable "public_subnet" {
type = list
}
subnet.tf
output "public_subnet" {
value = aws_subnet.public.*.id
}```
Error:
```Error: Incorrect attribute value type
on elb/elb.tf line 4, in resource "aws_elb" "webelb":
4: availability_zones = [var.public_subnet]
Inappropriate value for attribute "availability_zones": element 0: string
required.```
Since var.public_subnet is already a list. [var.public_subnet] is equivalent to [["192.168.0.0/32"]] instead of the expected, un-nested input ["102.168.0.0/32"]
ie...just use var.public_subnet

How can I programmatically find VMs with unrestricted SSH connection?

I need to get a list of VMs that have unrestricted SSH.
I've been browsing the Azure SDK for Python documentation. There is an SshConfiguration class in the compute module, but it only has info about the public keys. There is a different SshConfiguration class in the batch AI module that can be used to get a list of public IPs that are allowed to connect, which is what I want. But I'm not using batch AI.
How can I get the information I want programmatically?
You'll have to take a detour for this as there is no direct method in the Compute module that gives this information directly.
Using methods from both the Compute and Network modules, I coded up the following script to list all VMs in the Subscription with unrestricted SSH access, i.e., list all the Inbound rules allowing access to the VM over port 22 from the Internet.
# Imports
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.compute import ComputeManagementClient
# Set subscription ID
SUBSCRIPTION_ID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
def get_credentials():
credentials = ServicePrincipalCredentials(
client_id='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
secret='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
tenant='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
)
return credentials
# Get credentials
credentials = get_credentials()
# Initialize management client
network_client = NetworkManagementClient(
credentials,
SUBSCRIPTION_ID
)
# Initialize management client
compute_client = ComputeManagementClient(
credentials,
SUBSCRIPTION_ID
)
def get_unrestricted_ssh_rules():
print('\nListing all VMs in Subscription with unrestricted SSH access:')
for vm in compute_client.virtual_machines.list_all():
# Get the VM Resource Group name
vm_rg_name = vm.id.split('/')[4]
# Loop through NICs
for nic in vm.network_profile.network_interfaces:
# Get the NIC name and Resource Group
nic_name = nic.id.split('/')[-1]
nic_rg_name = nic.id.split('/')[4]
# Get the associated NSG and its Resource Group
nsg = network_client.network_interfaces.get(
nic_rg_name, nic_name).network_security_group
nsg_name = nsg.id.split('/')[-1]
nsg_rg_name = nsg.id.split('/')[4]
# Get the associated Security Rules
for rule in network_client.security_rules.list(nsg_rg_name, nsg_name):
# Conditions:
# Rule direction: Inbound
# Rule Access: Allow
# Port: 22
# Source Address Prefix: 'Internet' or '*'
unrestricted = (rule.direction == 'Inbound' and rule.access == 'Allow' and ('22' in (rule.destination_port_ranges, rule.destination_port_range)
or rule.destination_port_range == '*') and (rule.source_address_prefix == '*' or rule.source_address_prefix == 'Internet'))
# Print all the Inbound rules allowing access to the VM over port 22 from the Internet
if unrestricted:
print "\nVM Name: ", vm.name, "\nResource Group Name: ", vm_rg_name, "\nRule Name: ", rule.name
# List all VMs in the Subscription with unrestricted SSH access
get_unrestricted_ssh_rules()
You may repeat the same with Subnets as well if the NSG is associated with a Subnet instead of a NIC.
References:
azure-mgmt-compute
VirtualMachinesOperations class
azure-mgmt-network
SecurityRulesOperations class
NetworkInterfacesOperations class
Hope this helps!

How to create multiple VM's in Azure with different specifications

I am looking to create approx. 15 virtual machines with Terraform, of which all have their own Size in Azure such as B2S, B2MS etc. They also have different sized disks. I understand that you can use Copy Index to loop through arrays, however I'm not sure of the best way to do this with VM's that have lots of properties that are different.
Is there a way to create a map object for each VM specification and then just loop through it with a Virtual Machine creation in the TF file? At the moment the only way I can see of doing it is creating a separate virtual machine resource in the main file and referencing each individual map file..
Create a map as you mention with the vm prefix as the key and size as the value:
variable "vms" {
type = "map"
default = {
vm1 = "Standard_DS1_v2"
vm2 = "Standard_ES2_v2"
}
}
Create your VMS:
# Network Interfaces for each one of the VMs
resource "azurerm_network_interface" "main" {
# looping to create a resource for each entry in the map
for_each = var.vms
# Accessing keys in the map by each.key
name = "${each.key}-nic"
...
}
resource "azurerm_virtual_machine" "main" {
# Looping to create a VM per entry in the map
for_each = var.vms
# Accessing names of map entries
name = "vm-${each.key}-we"
# Here we make sure we access the corrrect
network_interface_ids = [azurerm_network_interface.main[each.key]]
vm_size = each.value
...
os_profile {
# Accessing names of map entries again
computer_name = "vm-${each.key}-we"
...
}
...
}
For brevity I didn't write down the whole example of creating azure vms.
There's many attributes you'll have to fill in as you need them.
Docs about how to create Azure VMS: https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html
Docs about resources and "looping" them: https://www.terraform.io/docs/configuration/resources.html
Terraform has seriously the best docs out there IMO.

How do I get instance id/name from public ip address of VM in azure via python sdk

def get_instance_id_from_pip(self, pip):
subscription_id="69ff3a41-a66a-4d31-8c7d-9a1ef44595c3"
compute_client = ComputeManagementClient(self.credentials, subscription_id)
network_client = NetworkManagementClient(self.credentials, subscription_id)
print("Get all public IP")
for public_ip in network_client.public_ip_addresses.list_all():
if public_ip.ip_address == pip:
print(public_ip)
# Get id
pip_id= public_ip.id.split('/')
print("pip id : {}".format(pip_id))
rg_from_pip = pip_id[4].lower()
print("RG : {}".format(rg_from_pip))
pip_name = pip_id[-1]
print("pip name : {}".format(pip_name))
for vm in compute_client.virtual_machines.list_all():
vm_id = vm.id.split('/')
#print("vm ref id: {}".format(vm_id))
rg_from_vm = vm_id[4].lower()
if rg_from_pip == rg_from_vm:
## this is the VM in the same rg as pip
for ni_reference in vm.network_profile.network_interfaces:
ni_reference = ni_reference.id.split('/')
ni_name = ni_reference[8]
print("ni reference: {}".format(ni_reference))
net_interface = network_client.network_interfaces.get(rg_from_pip, ni_name)
print("net interface ref {}".format(net_interface))
public_ip_reference = net_interface.ip_configurations[0].public_ip_address
if public_ip_reference:
public_ip_reference = public_ip_reference.id.split('/')
ip_group = public_ip_reference[4]
ip_name = public_ip_reference[8]
print("IP group {}, IP name {}".format(ip_group, ip_name))
if ip_name == pip_name:
print("Thank god. Finallly !!!!")
print("VM ID :-> {}".format(vm.id))
return vm.id
I have above code to get the VM instance ID from Public ip but its not working. What is real surprising is that for all instances, I am getting x.public_ip_address.ip_address as None value.
I had multiple readthedocs references for python SDK of Azure. but, some how all links not working. Good job Azure :)
Some of them:
https://azure-sdk-for-python.readthedocs.io/en/v1.0.3/resourcemanagementcomputenetwork.html
https://azure-storage.readthedocs.io/en/latest/ref/azure.storage.file.fileservice.html
Second edit:
I got the answer to this and above code will return vm id given the public ip address. Though, you can see it is not absolutely optimized answer. Hence, better answers are welcome. Thanks!
Docs have moved here:
https://learn.microsoft.com/python/azure/
We made some redirection, but unfortunately it's not possible to go global redirection on RTD, so some pages are 404 :/
About your trouble, I would try to use the publicip operation group directly:
https://learn.microsoft.com/en-us/python/api/azure.mgmt.network.v2017_11_01.operations.publicipaddressesoperations?view=azure-python
You get this one in the Network client, as client.public_ip_addresses

Resources