Config As Code With The Ansible Automation Platform Controller
A question we get off and on is how to automate the configuration of the Ansible Automation Platform(AAP) in the same way we would any other product. This could be for a lot of reasons, but the one I hear most often is “We need to have change control associated with AAP for compliance…so how do we do that?”
To solve this problem I created a quick bit of automation to demonstrate using AAP to automate its own configuration…a bit meta. In short I create some variable files in my git repository that represent how my AAP controller should be configured. I then have automation that will take those files and idempotently apply them to the controller.
Video Demo
Playbooks And Files
All files can be found in my github repo here.
Variable Files
I’ve got all of my settings stored in separate files in a data model I’ve created. This could technically be in a single file, I just chose to break it out for readability for this demo. Each file really just contains variables in whatever format I chose to put them in.
Here’s the inventory variable file for example(inventory.yml):
1 2 3 4 5 | --- inv_var: - name: AWS Inventory state: present org: Default |
^^ It’s really just a simple set of variables that define the inventory name, its state, and the org it’s associated to.
Playbook
I built this simple demo into a single playbook. The idea being that I created this idempotently, so I can rerun it multiple times and only the necessary adjustments will be made.
My playbook is as follows(main.yml):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | --- - name: config as code demo for AAP hosts: controller gather_facts: false vars: controller_user: code controller_pass: codepassword tasks: - name: bring in credentials variables include_vars: file: cred.yml run_once: true - name: manage credentials ansible.controller.credential: controller_host: "https://{{ ansible_host }}" controller_username: "{{ controller_user }}" controller_password: "{{ controller_pass }}" name: "{{ item.name }}" organization: "{{ item.org }}" description: Added by automation credential_type: "{{ item.type }}" state: "{{ item.state }}" inputs: # secret key password: "{{ item.password }}" # access key username: "{{ item.username }}" validate_certs: false loop: "{{ creds }}" - name: bring in inventory variables include_vars: file: inventory.yml run_once: true - name: manage inventories ansible.controller.inventory: controller_host: "https://{{ ansible_host }}" controller_username: "{{ controller_user }}" controller_password: "{{ controller_pass }}" name: "{{ item.name }}" description: Added by automation state: "{{ item.state }}" organization: "{{ item.org }}" validate_certs: false loop: "{{ inv_var }}" - name: bring in inventory source variables include_vars: file: inventory_source.yml run_once: true - name: manage inventory sources ansible.controller.inventory_source: controller_host: "https://{{ ansible_host }}" controller_username: "{{ controller_user }}" controller_password: "{{ controller_pass }}" name: "{{ item.name }}" description: Added via automation inventory: "{{ item.inventory_name }}" credential: "{{ item.inventory_credential }}" overwrite: True update_on_launch: True source: "{{ item.source }}" # source_vars: # private: false validate_certs: false loop: "{{ inv_source }}" |
I won’t walk through it completely, as each small section is really a copy and paste of the previous.
First I load in the variables:
1 2 3 4 | - name: bring in credentials variables include_vars: file: cred.yml run_once: true |
It just simply grabs the file and brings in the variables. It does this only once(that way if I’m updating a cluster of controllers it doesn’t waste time).
Next I use the ansible.controller collection to start placing my configurations. In this case I’m updating credentials so I use the ansible.controller.credential module:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - name: manage credentials ansible.controller.credential: controller_host: "https://{{ ansible_host }}" controller_username: "{{ controller_user }}" controller_password: "{{ controller_pass }}" name: "{{ item.name }}" organization: "{{ item.org }}" description: Added by automation credential_type: "{{ item.type }}" state: "{{ item.state }}" inputs: # secret key password: "{{ item.password }}" # access key username: "{{ item.username }}" validate_certs: false loop: "{{ creds }}" |
Here you can see that I’m just quickly looping through the variable that was imported and adding in my configurations.
Conclusion
Once you have an example laid out in front of you, it really is pretty simple. The best options for this is to have as many components as external queryable systems as possible(secrets engines and dynamic inventories). Using these methods you could start treating your AAP configurations just like any other infrastructure as code project.
If you have any questions or comments, please let me know. Thanks and happy automating!