I have been doing a lot of ISE deployments lately. One of my customers is doing a TACACS only implementation of ISE. I have also been studying up on Ansible and trying to use it in real world scenarios. One idea I’ve come up with is using Ansible to test ISE TACACS policies before actually using the real gear.

The first part of this was trying to find a python module that can interact with TACACS. Thankfully, Ansible itself has a github repo with such a module called tacacs_plus. This module actually contains a standlone client which is pretty nice in on it’s own, but naturally I want to shoehorn this into Ansible.

Part 1 of this post involves getting this Python module into an Ansible module, that I can call from my playbook. Part 2 of this post will move this module into an ansible collection to make it fit within the newer Ansible methodologies.

Ansible Modules Fundamentals

Look, I’m not going to rewrite things here. You can search for Ansible module fundamentals, and the documentation site itself contains a lot of really good information about creating a custom module here.

What I have learned, is that the simplest(and now legacy) way to do this is as follows.

For a module to be loaded by a playbook, the playbook has to know where to find it. There is documentation on this setup within ansible.cfg documentation. However if you don’t specify that, ansible will by default look at the library folder within your playbooks run path. The filesystem tree would look like this:

.
library/
    custommodule.py
playbook.yml
credentials.yml

Pretty simple, you can then directly call module from your playbook, an example:

---
- name: Simple Playbook
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Load Module
      custommodule:
        module_vars: 'test'

Variables get passed to the module, everything runs as it should.

Tacacs_plus Module

For my use case, I needed to write a tacacs_plus module in Ansible to call my newly found tacacs_plus python library. I have published my code on github here. Modules have a very defined format, I have included the required things, however I didn’t fill out all fields as I should if I were to submit this to Ansible to include (or later Galaxy).

My module runs as a simple python script, hence the if __name__ == '__main__' to launch and run the code. The developer documentation from Ansible is really good (linked above) at giving you details on what is required and how you specify arguments. I decided to split my module into two separate entities. One module will handle authentication, one will handle authorization (with a simple show version command). This is pretty specific, however hopefully easy to adjust to whatever customer requirements might be. If I get time I might try to make it as generic as possible with different options for command vs not command authorization. I also need to include accounting.

Since my modules are standalone python scripts, they can import python libraries. The python tacacs_plus library is included, a client is setup and runs the authentication or authorization steps. I do need to add some error detection and return the proper ansible syntax to alert people to problems (invalid credentials, unreachable servers, invalid servers, etc) but for now this works.

My playbook does use vault to store encrypted passwords and include that into the playbook, so to run my playbook it’s simply ansible-playbook playbook.yml --ask-vault-pass

Future

Ansible has moved to content collections, things you publish via Galaxy and people consume. Modules can exist inside of collections, again my next post will detail this a bit more (how I moved my moudule to a collection).

As usual, this blog post is mostly for my own notes, but hope it’s helpful to someone else.