Creating custom credentials in Ansible Tower
As we go further in our efforts to automate all the things with ansible, you will likely come across a need to manage some cusom credentials that do not come with a predefined type in Ansible Tower. You might be currently setting these in an environment variable, in group_vars or host_vars, or perhaps hardcoded into a playbook itself. What if we need to extract these from the eyes of others, or make them easily reused across the organization? Can I use Ansible Tower to manage and abstract custom credentials like it does for machine, github, or cloud account types? The answer is yes.
So let’s look at moving a custom credential into Tower. I’m going to use Red Hat Subscription Manager credentials as an example, this is the Customer Portal account username and password that’s used to register a RHEL system. This credential is obviously private and sensitive in nature and I’d like to make this easily usable across my organization, but I don’t want it to be stored in plain-text or easily accessible by the wrong eyes.
I have an example playbook that registers a host using the subscription-manager utility. Currently I store my username and password in an environment variable that’s private to my workstation and user login session:
# export SMUSERNAME=andrew.ludwar # export SMPASSWORD=secretpassword # cat playbook.yml --- - name: Deploy a VM hosts: all become: true vars: # Fetch subscription-manager credentials subs_mgr_username: "{{ lookup('env', 'SMUSERNAME') }}" subs_mgr_password: "{{ lookup('env', 'SMPASSWORD') }}" tasks: - name: Register host with subscription-manager redhat_subscription: state: present username: "{{ subs_mgr_username }}" password: "{{ subs_mgr_password }}" auto_attach: true
Now this works great, but it’s limited to my specific workstation and login session. What if I wanted others to be able to register systems using these credentials? Or, what if I wanted these to be easily passed into playbooks run via Tower in a workflow? Enter custom credentials.
In Ansible Tower, we have a concept of Credential Types. We can define a credential type that’s different from the pre-packaged credentials, and then create a new credential using that framework. In the Ansible Tower GUI, under Administration at the left hand side, click on “Credential Types”. You should see a listing similar to this, although yours may be blank:
Let’s define a new credential type, which Ansible Tower will abstract away from those who we don’t want to see it but will still allow us to use it easily in our playbooks.
I’ve named this credential for the Red Hat Customer Portal, and I’ve given it some input configuration and injector configuration to define what this credential is and how we will reference it. We define the credential ID, its data type (string), label, and for the password I’ve included the secret flag to keep this hidden wherever it gets referenced.
Input Configuration:
fields: - id: rhnusername type: string label: rhnusername - id: rhnpassword type: string label: rhnpassword secret: true required: rhn-username rhn-password
The injector configuration is basically taking over for the environmental variable structure, in that we’ll be using these as extra vars passed into playbooks, and I’m assigning these a name and a value to be referenced
Injector Configuration:
extra_vars: rhnpassword: '{{rhnpassword}}' rhnusername: '{{rhnusername}}'
Here’s what it looks like as I’ve now saved it:
Now that the credential framework is there, we can use this to create a new credential for the Red Hat Customer Portal. Let’s create a new credential. When clicking on add credential, we should now see a new option for credential type named “Red Hat Customer Portal”:
So we select our new credential type. Now we should see the two fields that we’ve defined previously in RHNUSERNAME and RHNPASSWORD, and also that the password field should hide our data once entered:
After entering our username and password details here and saving, this is ready to be used in playbooks called with Tower.
Remember the playbook we just used that had environment variable look ups? We’ll change that slightly to use the names defined in the injector configuration. Then we’ll add this new credential in the Job Template and Tower will pass the credential details to be used in the playbook, and the playbook will capture them by their variable names, just like if we were passing extra variables at runtime. Here’s the new playbook we’ll use:
--- - name: Deploy a VM hosts: all become: yes vars: # Fetch subscription-manager credentials subs_mgr_username: "{{ rhnusername }}" subs_mgr_password: "{{ rhnpassword }}" tasks: - name: Register host with subscription-manager redhat_subscription: state: present username: "{{ subs_mgr_username }}" password: "{{ subs_mgr_password }}" auto_attach: true
And in the Job Template, we’ll simply add another credential which will get passed to and captured by the playbook to be used to register the system:
Which gets captured and used in our playbook results:
References:
1 https://access.redhat.com/solutions/3331011
2 https://docs.ansible.com/ansible-tower/latest/html/userguide/credential_types.html