This is part of a series of posts about how Ansible and Ansible Tower enable you to manage your infrastructure simply, securely, and efficiently.
When we talk about Tower, we often talk in terms of control, knowledge, and delegation. But what does that mean? In previous posts in this series, we've talked about the concept of 'control', as it relates to both managing your infrastructure and managing your automation. Today we're going to explain delegation, and the security aspects that go into that.
DELEGATION - THE BASICSAnsible Playbooks, out of the box, are pretty simple - you run Ansible as a particular user, you pass it whatever inventory you want to manage, and it uses whatever credentials the executing user happens to have on hand. This is great for getting automating quickly, but what if you want to delegate automation to someone else to run as needed? You need to provide an inventory file for Ansible and Playbook to them (hopefully they don't edit them), and give them credentials (hopefully they won't use them for something else).
That's where the control, knowledge, and delegation features of Ansible Tower come into play.
STEP 1: CREDENTIALSAnsible Tower securely stores credentials for use by automation. This has multiple benefits:
No direct accessIf the user doesn't have direct access to the credential, they can't use it elsewhere for other means, and there's no need to change the credentials if they leave the organization.
Allows for additional securityWant to restrict access so only SSH from the Tower server is allowed? Easy to do with SSH authorized key restrictions. Want to ensure that no one can perform actions except through automation? Store the key in Tower and then throw it away.
Easy to rotate credentials
If the key or password is stored in a central location, then it becomes much simpler to rotate the key when needed, and can be done as part of an automation process.
Adding credentials for storage in Tower is easy. Here we'll add a SSH key for managing some set of machines, on Tower's Credential screen.
Note that as part of a credential like this, we can also specify how this key will be used with privelege escalation - with su, sudo, or other mechanisms. In the above example, we choose to use sudo, to root, with a particular password.
As with all parts of Tower, credentials can be created and edited via Tower's REST API. Here are examples, using the tower-cli commandline wrapper.
tower-cli credential create --name "SSH key" --description "SSH key" \ --organization "Default" --kind ssh --ssh-key-data ~/.ssh/test_key \ --ssh-key-unlock "setec astronomy" --username myuser --become-method sudo \ --become-username root --become-password "correct horse battery staple" tower-cli credential create --name "Amazon keys" --description "AWS keys" \ --organization "Default" --kind aws --username "AKIAFAKEACCOUNT12345" \ --password "seriously, this is not an actual AWS key"
Tower can store many types of credentials - username/password combos for machine access, credentials for network switches, and credentials for many cloud and infrastructure providers.
STEP 2: INVENTORY AND PLAYBOOKSAnsible's control of inventory and Playbooks also allows for easier delegation. In an earlier blog post in this series we described how to set up inventory for use in Tower. Both of these are key to delegation - ensuring that the proper Playbooks are run in the proper controlled way on the proper inventory. See our earlier series for more detail.
Delegation through role-based access controlThe key to properly delegating access is to control who has access to what. It does no good to delegate deployments to the QE team if they can with one click accidentally deploy to the production environment.
Tower solves this problem via a comprehensive role-based access control (RBAC) engine. With Tower, you can always ensure your automation is run properly across your organization.
Starting Simple: RBAC on job templates
Say you want to be very restrictive in what you delegate - certain people should only be able to run certain pieces of automation, exactly in the way that it's written.
You can do this by assigning roles and permissions on Tower job templates. A user with permission to run a job template will be able to run that Playbook as defined, even if they cannot see or access the inventory or use the credential in any way.
Here's how you assign permissions to a job template. Under each job template, there is a permissions screen, and you can choose a user or group to apply permissions to.
Job templates have two basic permissions:
1. Execute: the user or team can execute this job template, but cannot edit or change it
2. Admin: the user or team can both execute this job template, and also edit it
Note that you can, of course, do this via the API as well.
tower-cli role grant --job-template "Provision cloud instances" \ --team "Developer Team (Atlantic Division)" --type=execute tower-cli role grant --job-template "Provision cloud instances" \ --team "Ops (Atlantic Division)" --type=admin
With these permissions, a user will only see the job templates they explicitly have permissions to use.
MORE COMPLEX SCENARIOS: USING OTHER PERMISSIONSYou can also use Tower's RBAC engine to assign permissions to component parts of automation - projects, inventories, and credentials.
In each case, the ability to use an item in automation means you can plug it into an existing job template. Let's see how this works in practice.
One Playbook, many inventories
Let's say you've created a deployment Playbook to deploy your application. This Playbook can deploy in any environment, and you want to delegate that to the owners of the environments without creating separate job templates. Tower makes this easy.
First, set up the job template to not have an inventory specified, and set 'Prompt on Launch'.
Then, for each user/group who maintains an inventory, give them 'execute' access on the job template, and 'use' permission on their inventory.
Now, when they launch the automation, they can just fill in the inventory they want to deploy to.
We can also set up these permissions via the API:
tower-cli role grant --job-template "Deploy application" \ --team "Developer Team (Atlantic Division)" --type=execute tower-cli role grant --job-template "Deploy application" \ --team "Ops (Atlantic Division)" --type=execute tower-cli role grant --job-template "Deploy application" \ --team "Testing (Atlantic Division)" --type=execute tower-cli role grant --inventory "Dev" \ --team "Developer Team (Atlantic Division)" --type=use tower-cli role grant --inventory "Dev" \ --team "Testing (Atlantic Division)" --type=use tower-cli role grant --inventory "Dev" \ --team "Ops (Atlantic Division)" --type=use tower-cli role grant --inventory "Staging" \ --team "Testing (Atlantic Division)" --type=use tower-cli role grant --inventory "Staging" \ --team "Ops (Atlantic Division)" --type=use tower-cli role grant --inventory "Production" \ --team "Ops (Atlantic Division)" --type=use
In this case, we've set up three inventories: dev, staging, and production. The dev team can only access dev, the test team can only access dev and staging, while ops can access all three.
Build your own automation from components
Maybe you have a team that you want to have free reign in their own inventory, able to build, run, and re-delegate any automation from certain repos on that inventory. In that case, they would then be given access not just to the inventory, but also access to a project. They can then create new job templates at will, matching any Playbook in that repo with the inventories they have access to. Here's the API example; you can do the same thing in the Tower user interface easily.
tower-cli role grant --inventory "Dev" \ --team "Ops (Atlantic Division)" --type=use tower-cli role grant --inventory "Staging" \ --team "Ops (Atlantic Division)" --type=use tower-cli role grant --inventory "Production" \ --team "Ops (Atlantic Division)" --type=use tower-cli role grant --project "Infra admin" \ --team "Ops (Atlantic Division)" --type=use
NOTES ABOUT TEAMS
You'll notice in the above examples we use Tower's "team" functionality. Teams are a great way to colaesce permissions on multiple objects for multiple users.
If you've got a set of permissions you want to assign to multiple logical groups in your organization, that's easy to do with Tower's support for external authentication sources such as LDAP or Active directory. You can populate a team in Tower from one or many different groups and subsets of users in your external directory - see the Tower Administrator's Guide for details.
Automating adding of permissionsWith the above examples, we've shown that it's easy to delegate to the users that you need to with the controls in Ansible Tower. Tower's REST API also makes it easy to construct powerful RBAC controls, should the situation arise.
In this example, we're going to create a new deployment job, and automatically give access to all our teams that are involved with development (based on 'dev' being in their team name or description).
tower-cli job_template create --name "Deploy new application" --job-type run \ --project "Infra admin" --playbook "deploy.yml" --machine-credential "ssh key" --become-enabled true curl -k --basic -u admin:correcthorsebatterystaple \ -H "Content-Type: application/json" -X GET \ https://tower-test.local/api/v1/teams/?search=dev | \ jq '.["results"]["id"]' | while read id ; do tower-cli role grant --job-template "Deploy new application" \ --team $id --type=execute done
This example uses the 'jq' tool for parsing Tower's JSON output.
NOW GO FORTH AND DELEGATE!
We'll be back with more examples of how you can use Ansible and Ansible Tower to
manage your infrastructure in the near future.
In the meantime, you can find some of the examples from our blog posts at