This is Part 2 of the Ansible on Azure series. In this blog you’ll discover how Terraform IaC can automate your Ansible control host deployment to Azure.
I’ll showcase the custom module terraform-azurerm-ansible-linux-vm and highlight some noteworthy items. Each new heading will cover a different resource type for easy reader consumption.
- Part 1 covers the birds-eye solution overview and introduces you to key components.
- Part 2 showcases the Terraform module used to automate deployment of an Ansible control host into Azure.
- Part 3 dives into using the Molecule-Azure driver to rapidly develop Ansible playbook tasks on Azure instances.
Finally, I’ll also provide a step-by-step example of using the module to deploy an Ansible control host into Azure.
Development Ecosystem Mapping
In terms of our development ecosystem described in Part 1, and shown below, this blog covers stages 1-3.
1 - Resource Group (RG)
- This new Resource Group will help isolate our new Ansible development environment and support a quick destroy later.
- I recommend appending your initials to new RG’s name e.g. rgName = "ansbledev-yourinitials" to allow for easy identification later.
- Here I’m also outputting the new RG’s name to the Terraform console. We’ll need to reference this value within our Molecule create.yml file later in Part 3 of this series.
2 - Virtual Network (VNET)
- This new VNET will be an isolated space and subnet for the Ansible control host and Molecule test instances to directly communicate over.
- I recommend appending your initials to new VNET’s name e.g. vnetName = "ansibledev-yourinitials".
- Remember to avoid configuring any VNET peering or gateway devices on this new VNET to ensure it remains isolated from the rest of your environments.
- Here I’m also outputting the new VNET’s name to the Terraform console as we’ll need to reference this value within our Molecule create.yml file later in Part 3 of this series.
3 - Network Security Group/Rule (NSG)
- To secure our new VNET we need a NSG with a single inbound rule to allow SSH from a single Public IP source_address_prefix to the Private IP of the Ansible control host.
- You’ll need to update source_address_prefix with your own Public IP https://www.whatismyip.com/
- I recommend appending your initials to new NSG’s name e.g. nsgName = "ansibledev-yourinitials".
4 - Public IP and Network Interface(PIP/NIC)
- We need to create a new dynamic PIP and setup a static private IP on the NIC associated to our new Ansible control host.
- I recommend appending your initials to new PIP’s name e.g. vmPublicIPDNS = "ansibledev-yourinitials".
- A data lookup data.azurerm_subnet.default.id will grab the subnet id from our new VNET.
- Here I’m also outputting the new PIP’s FQDN to the Terraform console as we’ll need to use this value to connect to the Ansible control host over SSH.
5 - Transport Layer Security Key (TLS)
- This section generates a new TLS key for our use in connecting to the Ansible control host. Warning: This key is intended for throwaway development environments and will be stored unencrypted within your Terraform state file.
- I recommend excluding your Terraform state files used by this module from syncing to source control by adding the following to your .gitignore file:
- Here I’m also outputting the new private key’s PEM value to the Terraform console as later on we’ll need to save this locally in a .PEM file.
6 - Virtual Machine (VM)
- This new VM is an Ubuntu 18.04 LTS server and will act as our Ansible control host in Azure. We’ll be connecting to this host over SSH from VSCode and using it to develop and test Ansible playbooks on Azure instances.
- I recommend appending your initials to new VM’s name e.g. vmName = "ansibledev-yourinitials".
- The default VM size is also Standard_B2s, a 2CPU/8GB low-cost option ideal for testing and development. Because we’re using the Molecule Azure driver to create/converge/destroy Azure instances there isn’t a requirement for a beefy Ansible control host.
- Our new VM also references the OpenSSH public key value using public_key = "tls_private_key.vm1key.public_key_openssh".
7 - Shutdown Schedule
- This section creates a daily VM shutdown schedule associated to the new Ansible control host.
- A daily shutdown ensures our costs are further minimized and we’re not going to pay for running costs when the VM is unused.
- Time of shutdown can be modified using vmShutdownTime = "1900".
- The timezone used for the shutdown can be modified using vmShutdownTimeZone = "AUS Eastern Standard Time".
8 - VM Extension and Shell Script
- This section creates a CustomScript type VM extension associated to the new Ansible control host.
- A shell script ubuntu-setup-ansible.sh stored in the repo is called with the source command . ./ubuntu-setup-ansible.sh.
- The shell script below runs at the time of VM creation via Terraform and automates the installation of multiple software packages we need to develop Ansible playbooks with Molecule and Azure.
- Note: I’m a novice with shell scripting so if there’s any glaring issues please do reach out to me!
- Requirements-ansible.txt contains packages/plugins related to Ansible/Molecule development.
- If any new versions are released for the below requirements a new Ansible control host should be deployed using the updated requirements-ansible.txt file.
- Requirements-azure.txt contains packages/plugins related to Azure development.
- If any new versions are released for the below requirements a new Ansible control host should be deployed using the updated requirements-azure.txt file.
- This list is very similar to the requirements file maintained in the ansible-collections/azure repo.
TF Module Example Usage (Windows users)
- 1 - Clone the repo
git clone https://github.com/globalbao/terraform-azurerm-ansible-linux-vm cd terraform-azurerm-ansible-linux-vm
- 2 - Initialize the module
- 3 - Set the value of module.linux_vm.nsgRule1.source_address_prefix to your own Public IP address.
- 4 - Authenticate to Azure via AzCLI
az login az account set -s subscriptionID
- 5 - Run Terraform to create the module resources.
terraform apply -auto-approve
Note: the TF apply can take ~15mins due to the shell script tasks via VM Extension.
At this stage your Ansible control host has been deployed to Azure and is ready for your SSH connection using VSCode.
Remember to take note of the following outputs.
- module.linux_vm.pip1 - the PIP DNS name of your Ansible control host
- module.linux_vm.tls_private_key - the SSH private key needed to connect to your Ansible control host
- module.linux_vm.azurerm_resource_group_name - the RG of your Ansible dev environment (you should use this value in the create.yml files for your Molecule scenarios)
- module.linux_vm.azurerm_virtual_network_name - the VNET name of the Ansible dev environment (you should use this value in the create.yml files for your Molecule scenarios)
Setup/test the SSH authentication.
- 6 - Create a new local file for the private key e.g. C:\Local\vm1key.pem
- 7 - Modify the C:\Local\vm1key.pem file’s permissions so only your Windows account has read/write access.
- 8 - Remove all other inherited permissions (e.g. System/Administrator Group) from C:\Local\vm1key.pem.
- 9 - Copy & paste the Terraform output of tls_private_key into this new file.
- 10 - Open VSCode > Remote Explorer > SSH Targets > Add New
- 11 - Copy & paste the Terraform output of pip1 as the SSH target.
- 12 - Select the SSH config file to update e.g. C:\Users\Username\.ssh\config
- 13 - Add the following to SSH config file:User ansibleadmin and IdentityFile C:/Local/vm1key.pem
- 14 - Verify the SSH connection works via VSCode > Remote Explorer > SSH Target > Connect to Host
Note: The above steps 6-14 work on my Win10 machine but if you encounter issues I recommend reviewing the official doco here: https://code.visualstudio.com/docs/remote/ssh
- 15 - Work on your Ansible development (see Part 3).
- 16 - Remove the environment.
terraform destroy -auto-approve
In this blog we looked at deploying an Ansible control host into Azure using the TF module terraform-azurerm-ansible-linux-vm with examples of the following resource types: