Always fun to strike problems in what should be the simplest things. I wanted to add Ansible Tower as a service into ManageIQ. Cloudforms would have a similar result.
So, what is a person to do? Hit the google. Eventually I came across this bugzilla item https://bugzilla.redhat.com/show_bug.cgi?id=1740860 and it gave a hint as to just specifying the /api/v2 in the URL I gave to ManageIQ rather than just the base hostname. eg. https://blah…./api/v2
Tried it, it worked! My credential validated and a provider refresh was automatically initiated and all my Ansible Tower templates and inventories were discovered correctly.
The section ‘Authenticating with Azure‘ sounds like the right place, but you can’t use your AD username / password from Ansible because you turned on 2FA – You turned it on RIGHT? So the option left to you is to create a Service Principal (SP).
Note: having 2FA on your account is what you should be doing, so don’t turn it off.
It’s quite simple to create a credential for Ansible to use when connecting to Azure. Simply, fire up the Cloud Shell (awesome feature BTW Microsoft) and create a Service Principal (SP).
But Hang On, what is a Service Principal? The Ansible guide refers you to the Azure documentation over at https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal which you will read, and if you’re like me, you’ll wonder what you actually just read. Have no fear. As I mentioned above you can use a simple Azure CLI command (via the Cloud Shell you just started) and create the Service Principal. Think of the Service Principal as a credential an application (in this case Ansible) can use to access the Azure service(s).
geoff@Azure:~$ az ad sp create-for-rbac --name svc-ansible-azure # (optional if not specified one will be generated) --password 'ALovelyComplexPasswor@'
Changing "svc-ansible-azure" to a valid URI of "http://svc-ansible-azure", which is the required format used for service principal names
Creating a role assignment under the scope of "/subscriptions/88888888-4444-4444-4444-cccccccccccc"
Retrying role assignment creation: 1/36
Retrying role assignment creation: 2/36
{
"appId": "appid888-4444-4444-4444-cccccccccccc",
"displayName": "svc-ansible-azure",
"name": "http://svc-ansible-azure",
"password": "password-4444-4444-4444-cccccccccccc",
"tenant": "tenant88-4444-4444-4444-cccccccccccc"
}
geoff@Azure:~$
If you want to see what that command just did in the Azure portal, head over to the Azure Active Directory -> App registrations blade.
and then you can see the Service Principal you just created.
So what do you do with the new credential.
The Ansible Azure scenario guide has a section on what to do, however, it’s a bit too vague for me.
Using Environment Variables
To pass service principal credentials via the environment, define the following variables:
For your sanity, AZURE_CLIENT_ID ==> appId AZURE_SECRET ==> password AZURE_TENANT ==> tenant
The remaining item, AZURE_SUBSCRIPTION_ID is exactly that, you can also get from the Cloud Shell as follows
geoff@Azure:~$ az account list
[
{
"cloudName": "AzureCloud",
"id": "subscrip-4444-4444-4444-cccccccccccc
"isDefault": true,
.
.
.
In this case AZURE_SUBSCRIPTION_ID ==> id , whichever id in your account that is valid for your use case.
If you want to add these credentials into Ansible Tower, simply create a Credential of type Microsoft Azure Resource Manager and use the values you’ve deduced above. Ansible Tower will automatically translate them into Environment Variables for your Tower template execution.
It’s been one of those weeks and I needed to get some more experience with the ansible ServiceNOW modules, specifically within Ansible Tower. It looked pretty simple and in fact it really was quite simple.
Ansible Tower neatly stores credentials within it – or externally if that fills you with joy. There isn’t a ServiceNow credential type in Ansible Tower. Undeterred, I thought I would use machine credentials, but tower has an annoying behavior of only allowing 1 instance of each credential type attached to a tower template and I am already using machine credentials in my template.
Fortunately on the left hand side of the tower ui there’s an entry labelled credential types
When creating the credential type you need to supply two (2) pieces of information. The first piece is called the Input configuration – or what the fields look like on the web ui when you create a credential of this type and secondly, the Injector configuration which details what do do with thew credentials.
In my case, the new credential type is called SNOW and i’m providing the instance name, username and password as part of the structure for this credential – via the Input configuration and then I detail that I want to store this data in environment variables that will be accessible from my playbook when run in tower.
There are many times when you run an Ansible playbook through Ansible Tower and you have to become a privileged user on the target system. This is business as usual for Ansible and Ansible Tower.
This is normally achieved by specifying become as part of your playbook, such as this snippet.
---
- name: Patch Linux
hosts: all
gather_facts: true
become: true
Typically, as part of a patching playbook, you would reboot the system and wait for the reboot to finish using a code fragment like this :
- name: Wait for server to restart
local_action:
module: wait_for
host={{ ansible_ssh_host }}
port=22
delay=60
timeout=300
This local_action inherits the become: true from the parent definition and this is where Tower starts to complain. Remember, with Ansible Tower, it’s the tower server itself where the local_action will run. You can expect to see something like this :
"module_stderr": "sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?\n",
No, you SHOULD NOT enable the awx user to use sudo on the Tower system as the AWX service user is intentionally restricted from sudo operations. The best approach is to de-privilege the local_action. Fortunately, local_action has it’s own become capability so you can turn off the request for privileged access as you don’t need it.
The above code block is now :
- name: Wait for server to restart
become: false
local_action:
module: wait_for
host={{ ansible_ssh_host }}
port=22
delay=60
timeout=300
and the tower job template will execute without any errors.