Without a doubt the topic that seems to confuse people the most when using Ansible Tower is working with Credentials. Especially how to pass multiple credentials from either an external Secret Management source (which we’ve looked at a few times here) or just defining some arbitrary set of credentials and using them in a template.
I get emails about this topic from readers on a fairly regular basis and professionally I’ve run in to plenty of people that haven’t found the system very intuitive, none of this is exactly aided by the Tower documentation on the topic being a little brief and unclear to the uninitiated. In this post we’ll be looking at how to create Custom Credentials in Tower and how to employ them within Playbooks.
What Do We Want?
Let’s look at a straight forward scenario, let’s say we want to pass a REST API token to Ansible Task. Tower probably has a Credential Type for something like this already right? After all there’s Modules that allow you to use simple token authentication as an input parameter, but a look at the Tower Credential Type documentation doesn’t show us any such thing. In fact there’s little over a dozen Credential Types full stop, that won’t go too far. This is where Custom Credential Types come in to play.
Creating Custom Credentials
Custom Credentials allow us to create a custom set of inputs, optionally obscured at input and then remap them for use in a Task, this allows our same Credential Type to be re-used for any number of Credentials. Think of Credential Types as a template for Credentials that Tower knows nothing about yet.
Within Tower, we will browse to Credential Types and create a new Credential:
The structures are broken down in detail below:
--# INPUT CONFIGURATION --# "fields" defines the GUI fields which will be presented, only one is provided --# and it is mandatory, a string named token which will hold the Secret data initially. --# It's type is "secret" meaning it will be obscured on input, we have also defined --# it as "required" meaning it has to be entered. The label "API Tokd en" will be presented --# in the GUI when entering the secret data. fields: - id: token type: string label: API Token secret: true required: - token --# INJECTOR CONFIGURATION --# Here the "token" value is converted to a new variable named rest_api_token. --# The data defined in the Injector Configuration is available in any Playbook --# that our Secret is connected to by a Tower Template extra_vars: rest_api_token: '{{ token }}'
Creating and Using A Simple Credential
Now that we have a Credential Type defined, let’s create a Credential to leverage it. In Tower we can browse to Credentials and create a new Credential (in this example I’m going to create an API Token to communicate with my Netbox deployment):
Now that our Credential has been created we can create a simple Playbook to test that it works:
--- - name: "Netbox Demo" connection: local hosts: localhost gather_facts: False tasks: - name: Create Netbox Device netbox_device: netbox_url: https://netbox.madcaplaughs.co.uk netbox_token: "{{ rest_api_token }}" data: name: Test Firewall device_type: SRX 100B device_role: Firewalls site: madcaplaughs state: present ...
…and call the Playbook from a Template in Tower. Provided that we attach our new Netbox-API-Token Credential to the Template, we can implicitly call the new “{{ rest_api_token }}” variable from within our Task:
What About Multiple Secrets?
OK, so this is all fine if we only have a single secret value we ever want to pass, but eventually we’ll need to go beyond that. Let’s consider another scenario, say we want to pass a username and password for Basic HTTP authentication to an Ansible Task. Hopefully we aren’t forced to do that too much but this is the real world and there’s plenty of Module support out there. So let’s take a look at how we can accommodate that by extending our Custom Credential configuration:
--# INPUT CONFIGURATION --# This time our "fields" will present two input fields showing as "Username" and "Password". --# Both of these will obscure input for security and both will be mandatory. fields: - id: username type: string label: Username secret: true - id: password type: string label: Password secret: true required: - username - password --# INJECTOR CONFIGURATION --# Here the Injector Configuration will remap our values to two new strings, allowing --# them to be looked up at runtime as "{{ http_basic_username }}" and "{{ http_basic_password }}" extra_vars: http_basic_username: '{{ username }}' http_basic_password: '{{ password }}'
…and now when we try to create a new Credential using this Credential Type, we will be required to enter two secret values which will be implicitly available in our Playbooks as “{{ http_basic_username }}” and “{{ http_basic_password }}”.
A final point that is useful to know. You can add as many fields to you Credential Types as you like and provided that they aren’t set as Required, you can just leave them blank when creating a Credential without running in to any issues with you Plays. This can come in useful when trying to develop your credential management strategy as the limitations of Custom Credentials quickly show themselves and proper planning is essential to avoiding such problems.
Hopefully that clears up some confusion!