Orchestrating Azure Resources with Ansible

Introduction

Now firstly, you may ask, why did I choose Ansible for orchestrating Azure Resources, why didn’t I use ARM or Terraform? Well the answer is quite simply, I wanted to try it out and see what it had to offer.

My goal here was to be able to automate Idempotent Azure Infrastructure and Configuration in one Playbook for future tutorials on mostly AKS and K8s addons.

Infrastructure and Configuration Architecture

Let’s quickly look at what we will create with ansible

We’ll create the following Infrastructure:

  • Resource Group
  • VNet
  • 2 Subnets
  • AKS cluster
  • Private DNS

We’ll also perform the following configurations

  • Create a User Managed Identity and assign it Contributor Access over the Subscription
  • Link the Private DNS to the VNet
  • Give the Cluster System Managed Identity Contributor Access over the Subscription
  • Add the User Managed Identity to the VMScaleSet

Steps

We’re going to open Cloudshell in our Azure Subscription, which has Ansible pre installed.

Copy the ansible playbook from here: https://github.com/aido123/ansible/blob/main/azure_ansible.yaml into a file with the same name in your cloud shell

Next run the playbook, overriding the static variables I’ve set in the playbook with your own.

ansible-playbook azure_ansible.yaml --extra-vars "resource_group_name=myrsg subscription_id=ABC123 tenant_id=DEF456 contributor_roleid=b24988ac-6180-42a0-ab88-20f7382dd24c msi_name=mymsi vnet_name=myvnet subnet1_name=mysbt1 subnet2_name=mysbt2 dns_name=hynes.pri cluster_name=mycluster location=westeurope vm_username=myuser vm_password=MyPass98+332711"

After a number of minutes, the above infra and config will be setup.

An extensive list of the azure ansible modules available are outlined here: https://docs.ansible.com/ansible/latest/collections/azure/azcollection/

Snippets of note

Simple sleep task to wait for resources to be created

- name: Sleep for 30 seconds to make sure Msi created
wait_for:
timeout: 30
delegate_to: localhost

Configuring a Sub Resource using a combination of the Generic Azure Resource with a Sub Resource using properties in the body section

- name: Link private dns to vnet
azure_rm_resource:
api_version: '2018-09-01'
resource_group: "{{ resource_group_name }}"
provider: network
resource_type: privatednszones
resource_name: "{{ dns_name}}"
subresource:
- type: virtualnetworklinks
name: link1
body:
location: Global
properties:
virtualNetwork:
id: "/subscriptions/{{ subscription_id }}/resourceGroups/{{ resource_group_name }}/providers/Microsoft.Network/virtualNetworks/{{ vnet_name }}"
registrationEnabled: false

Waiting on a resource to become available using the “is defined” syntax

- name: Get VMScaleSet info
azure_rm_resource_info:
resource_group: "{{ nodersggroup.response[0].properties.nodeResourceGroup }}"
provider: compute
resource_type: virtualmachinescalesets
api_version: "2017-12-01"
register: vmssresources
until: vmssresources.response[0].name is defined
retries: 20
delay: 60

Conclusion

This is not an in depth review of Ansible and Azure Ansible Modules, but some notes from my brief tinkering…

Ansible itself is feature rich, looping, waiting on conditions, all that good stuff is there. If and when I found an issue or a limitation with an azure module, I was quickly able to come up with a workaround.

Ansible for the Azure Resources that I was using i.e. AKS, were not up to date. I could not use the azure aks ansible module for creating managed identity clusters, so I had to revert to using the generic azure rm module. Thankfully you can just use a generic azure module and plug in raw json into the body section.

Some Azure Modules for Ansible for Azure Configuration purposes i.e. assigning a managed identity to a VMScaleSet are not available, so I had to revert to basic scripting.

Not all azure modules are idempotent. For instance, if we were to run the above script again, it would fail on the initial role assignment task as it has already been done.

In the Playbook, we wait for resources to become available in the MC_* resource group, so we can determine the name of the VMScaleSet. The command we use seems to pull from an Azure cache, so even though the resources can be viewed via the UI, they do not appear via the az cli resource group list command. Query raised here: https://github.com/Azure/AKS/issues/1964

Resources

https://docs.ansible.com/ansible/latest/collections/azure/azcollection/

https://github.com/aido123/ansible

Cloud Platform Architect. Opinions and articles on medium are my own.