Introduction
Learn how to connect an Ansible to Azure using an Azure Service Principal account.
Prerequisites
- Azure subscription - Create a free account!
- Ansible for Azure Install dependencies
- Azure PowerShell - Learn how to Install
1. Create an Azure Service Principal
Use the PowerShell cmdlet New-AzADServicePrincipal
to create an Azure Service Principal account.
$credentials = New-Object Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential `
-Property @{ StartDate=Get-Date; EndDate=Get-Date -Year 2024; Password='<PASSWORD>'};
$spSplat = @{
DisplayName = 'sp-cs-ansible'
PasswordCredential = $credentials
}
$sp = New-AzAdServicePrincipal @spSplat
```
Replace `<PASSWORD>` with your password.
## 2. Assign a Role to the Service Principal
By default, service principals are created without any permissions. And without permissions, your service principal will not be authorized to connect to Azure.
Use the `New-AzRoleAssignment` cmdlet to assign the _Contributor_ role to your service principal.
```powershell
$subId = (Get-AzSubscription -SubscriptionName 'NameOfSubscriptionHere').id
$roleAssignmentSplat = @{
ObjectId = $sp.id
RoleDefinitionName = 'Contributor'
Scope = "/subscriptions/$subId"
}
New-AzRoleAssignment @roleAssignmentSplat
```
> NOTE: _To improve security, change the scope of the role assignment to a resource group instead of a subscription._
## 3. Authenticating with Azure
You will need the following information to connect to Azure.
* `SubscriptionId`
* `ApplicationId`
* `Service Principal Password`
* `TenantId`
(Optional) Use PowerShell to get the required information.
```powershell
@{
subscriptionId = (Get-AzContext).Subscription.Id
clientid = (Get-AzADServicePrincipal -DisplayName 'sp-cs-ansible').ApplicationId.Guid
tenantid = (Get-AzContext).Tenant.Id
}
```
### 3.1 Authenticate using a Credentials File
The Ansible uses the path `~/.azure/credentials` to look for credentials to autoload.
Placing a file in this location with the proper values will result in Ansible being able to connect to Azure.
**Create a credentials file**
```bash
mkdir ~/.azure
vi ~/.azure/credentials
```
**Populate the required Ansible variables**
```bash
[default]
subscription_id=<subscription_id>
client_id=<security-principal-appid>
secret=<security-principal-password>
tenant=<security-principal-tenant>
```
Replace values within `< >` with your Azure information.
> _Important: Credential files are for development usage ONLY._
### 3.2 Authenticate using Environment Variables
An alternate method of authentication is the usage of environment variables.
Use the bash command `export` to define the required Ansible environment variables.
```bash
export AZURE_SUBSCRIPTION_ID=<subscription_id>
export AZURE_CLIENT_ID=<security-principal-appid>
export AZURE_SECRET=<security-principal-password>
export AZURE_TENANT=<security-principal-tenant>
```
Replace values within `< >` with your Azure information.
> NOTE: _Read more about [Providing Credentials to Azure Modules](https://docs.ansible.com/ansible/latest/scenario_guides/guide_azure.html#providing-credentials-to-azure-modules)._
## 4. Run an Ansible Playbook
Write and execute an Ansible playbook to confirm Ansible can connect to Azure.
**Create** a file named `playbook.yml`
```bash
vi playbook.yml
```
**Copy and paste** the contents below to into the playbook.
```yaml
---
- hosts: localhost
connection: local
tasks:
- name: Create resource group
azure_rm_resourcegroup:
name: rg-cs-ansible
location: eastus
register: rg
- debug:
var: rg
```
The Ansible playbook will create an Azure resource group named `rg-cs-ansible` in the `eastus` region.
It registers the output to an Ansible variable that is will be displayed in the terminal using the `debug` module.
### Run the playbook using ansible-playbook
To execute the playbook use the ansible command `ansible-playbook playbook.yml`
```bash
ansible-playbook playbook.yaml
```
You now have a newly created resource group called `rg-cs-ansible` in Azure!
![Create Resource Group Ansible Playbook Output](https://thepracticaldev.s3.amazonaws.com/i/ug3q82y4ori976h29lcp.png)
### Sources <a name="Sources"></a>
- [Using Ansible with Azure](https://docs.microsoft.com/en-us/azure/ansible/ansible-overview)
- [Quickstart: Install Ansible on Linux virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/ansible-install-configure?toc=%2Fazure%2Fansible%2Ftoc.json&bc=%2Fazure%2Fbread%2Ftoc.json#install-ansible-on-an-azure-linux-virtual-machine)
- [Create an Azure service principal with Azure PowerShell](https://docs.microsoft.com/en-us/powershell/azure/create-azure-service-principal-azureps?view=azps-3.1.0)
- [New-AzRoleAssignment](https://docs.microsoft.com/en-us/powershell/module/az.resources/new-azroleassignment?view=azps-3.1.0)
_Originally posted on [CloudSkills.io](https://cloudskills.io/blog/connect-to-azure-with-ansible)_
Top comments (15)
Hi Josh,
quick question, can we use ansible in azure cloud shell, and specify custom location for host file using -i /home/user/hosts? something like that?
the idea is not to setup a VM in azure and configure ansible, rather use the native ansible from azure cloud shell. Your thoughts?
Note: I am aware that we can definitely use Dynamic inventory file but i still want to manually enter target severs under host file and use while running playbook.
Hi Sandeep,
That's an excellent question and idea. I actually have a blog post on using Ansible with cloud shell queued up. I love the idea of using cloud shell because it removes the need to stand up additional infrastructure.
As long as the host files and playbooks are stored in the Azure storage account you'll have access to them and can run them. You could also use a git repo and just pull them down when you need them.
Instead of host files you could use a host_list as well. For example ansible playbook.yaml -i web01, the comma at the end will prevent Ansible from attempting to parse the input.
If you start using it more please DM me and let me know how you like it and if there are any limitations.
I hope my reply helps and thank you for the comment! Have a great day!
Thanks Josh for prompt reply, i tried the same however it does not work. i am sure i am doing something wrong here (Refer the screen shot). this is what i do.
So you've run into the fun part of using Ansible with Windows. Ansible was developed for Linux first and its default connection will be SSH to Linux targets to override this you need to specify several Ansible variables to modify the connection options.
The settings and values you need to change greatly depend on your configuration, but here are some basic ones for WinRM over HTTP using NTLM authentication.
You can place these values anywhere but here are a few examples. One using the Ansible cmd and another using a playbook.
or a playbook
You can also put these vars in the group_vars folder or in the hosts file as vars. Which ever you prefer. I also wrote about remote management with Ansible and Windows see the below post. I hope this helps!
NOTE: If you're using WinRM over HTTP on 5985 you will have to open a firewall port on the vm or disable windows firewall.
dev.to/cloudskills/provisioning-az...
You are right Josh, i have been using group_vars and exactly same method you mentioned on my centOs ansible controller host. However when it comes to Azure Shell it does not work. Sharing my screen output..
➜ clouddrive ansible path -i hosts -m win_ping
[WARNING]: Could not match supplied host pattern, ignoring: path
[WARNING]: No hosts matched, nothing to do
➜ clouddrive ansible patch -i hosts -m win_ping
10.0.0.222 | UNREACHABLE! => {
"changed": false,
"msg": "kerberos: the python kerberos library is not installed",
"unreachable": true
}
➜ clouddrive ls group_vars
patch
➜ clouddrive more group_vars/patch
ansible_user: myUser@Domain.com
ansible_password: Welcome@123
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
ansible_winrm_transport: kerberos
ansible_winrm_kerberos_delegation: true
➜ clouddrive
I see you're using Kerberos auth. In that case, you'll have to install the Kerberos python libraries. I'm not sure how those will preserved probably stored in the storage account? Humm, very interesting.
Azure Cloud Shell wont allow you to install anything. So there has to be another way or Ansible on Cloud Shell does not serve the purpose.
Good point, I'll do some digging. Something tells me there is a way to mount external modules to cloud shell without installing them directly. In the time being NTLM seems to be the best alternative.
Again, NTLM is not an option for most of enterprise customers. either SSP or Kerberos. Will check too about External Modules on azure.
Thank you Josh for such a good series about ansible with Azure!
Followed along, found a small mistake, I believe you meant the below assignment in the 'roleAssignmentSplat' hashtable instead of '$spId'
Scope = "/subscriptions/$subId"
Hey Shan,
You're very welcome and thank you for taking the time to read and walk through the tutorials! You're correct with the mistake you identified. I've updated the code for the roleAssignmentSplat hashtable. I really appreciate you taking the time to point this out. Thank you!
For some reason, the error still exists in the code :|
Not sure if it just didn't save or got reverted but it's been fixed! Thanks for the comment.
Hi Josh,
Nice article. Thanks for sharing.
I am trying to create the service Principal using ansible module (azure.azcollection.azure_rm_adserviceprincipal) but getting some strange errors ("Error creating service principle, app id 123456 - Access Token missing or malformed.).
Just wanted to check if you did anything similar to this.
Thanks
Aniket
Some comments may only be visible to logged-in visitors. Sign in to view all comments.