Azure DevOps Ansible Pipeline
I thought it was about time that I started to have a play with Azure DevOps a little more than I have been doing. One of the things I have always meant to look at in the past is using DevOps to run Ansible playbooks.
However the Ansible Task recommended by Microsoft has always put me off, the reason for this is that this task requires a Virtual Machine to run Ansible – this to me always seemed a little overkill.
As I had some time I thought I would sit down and have a look at coming up with a pipeline which executes an Ansible playbook which doesn’t use the Ansible Task. As I had already done some work with Python based command line tools on Azure DevOps I thought it best to take the same approach as I took with those to my Ansible pipeline.
As you can see, the start of the pipeline is pretty straight foward, I am triggering whenever master
is pushed to, and using, the latest Ububtu VM image:
The next step is to make sure that Python is installed, here I am using Python 3.6:
So far so good, but the next step had me scratching my head for a little while.
I knew that I was going to connect the Azure DevOps project to my Azure subscription using a service connection which would grant contributor access, I also knew that I didn’t want to hard code any values in my azure-pipelines.yml
file, so how could I make sure that the credentials for the Azure DevOps managed service principle could be securely used by Ansible?
After a little trial and error, I settled on the task below:
As you can see, I am using the AzureCLI Task – this takes a few inputs:
-
azureSubscription: This will be the name of the service connection, as I don’t want to hardcode any values here I am using the variable
$(SUBSCRIPTION_NAME)
-
addSpnToEnvironment: When set to
true
this will add service principal id and key of the service endpoint as variables - scriptType: As I am using Ubuntu, I set this to ‘bash’
- scriptLocation: Finally, setting ‘inlineScript’ means that I can define the script within the task
The inline script uses logging commands to take the SPN variables and set them as variables we can use in later tasks:
You may have noticed that ARM_CLIENT_ID, ARM_CLIENT_SECRET and ARM_TENANT_ID are using the variables from the task which is why they are using the ${variable}
format.
To populate ARM_SUBSCRIPTION_ID we are using the output of running az account show --query="id" -o tsv
which returns the subscription ID, so as we are using Bash the format is $(command here)
.
The great thing about this approach is that because the variables which are outputted by the AzureCLI task are secrets they will always be treated as such so if we were to ever output them they will simply appear as *** though it is important that you are still careful when using them as you do not want the values appearing in any output.
The next step installs Ansible along with the Azure Modules:
Now that we have our SPN credentials defined as variables within the pipeline and Ansible installed we can finally run the playbook using the final task:
As the Azure Ansible modules expect the Azure credentials, tenant and subscription IDs as environment variables we are passing this at run time in the format which Ansible expects, AZURE_CLIENT_ID, AZURE_SECRET, AZURE_TENANT and AZURE_SUBSCRIPTION_ID – all of which are populated using the pipeline variables which were set in the Azure CLI task.
Running the pipeline gave me the following output:
Step – Install Python
Step – Azure CLI
Step – Install Ansible and the Azure modules
Step – Run Ansible Playbook
As you can see from the pipeline output above, the whole pipeline took just over a minute to run, and 50 seconds of that was installing Ansible itself.
Admittedly the playbook didn’t do much other than create a resource group called “azuredevops-rg” – however it wasn’t the playbook I was concerned about in this post – I just want a good boilerplate azure-pipelines.yml
file for future projects.
If you follow along with this post, make sure that when creating the pipeline in Azure DevOps you create a variable called SUBSCRIPTION_NAME
and populate with the name of the Azure Resource Manager service connection your project uses.
You can find the repository used in this post on GitHub.
Further Insights
Got 2 minutes to spare to watch our Managed DevOps offering?
Have a watch of our short 2-minute video on our Managed DevOps offering – a modern approach for modern applications.
Do you require a DevOps Managed Service?
Our DevOps Managed Services are designed for customers who require a modern operational model for cloud native applications.
How Not to Screw Up Your Move to Azure
A deep dive into our experience of delivering hundreds of cloud migration projects, including lessons learned and must-do activities.
Russ McKendrick
Practice Manager (SRE & DevOps)
Russ heads up the SRE & DevOps team here at N4Stack.
He's spent almost 25 years working in IT and related industries and currently works exclusively with Linux.
When he's not out buying way too many records, Russ loves to write and has now published six books.
To find out more about Russ click here!