1. Ansible L100
Hands-on tasks for this workshop will be using Ansible playbooks against a PAN-OS firewall, from your command-line environment. For each task, you can use the copy button to take the command into the clipboard, but ensure you replace any UPPERCASE_VARIABLES with your own values.
Assumptions: A host with the following installed: curl, git, Python 3, Ansible, PAN-OS-Python, PAN-OS Ansible Collection, and all prerequisite requirements for those items. Plus some form of text editor on your host. And, access to a PAN-OS next-generation firewall from your host.
- Note:
Lookout for text in uppercase, such as
YOUR_FIREWALL_IP, and replace the text with the relevant value for your environment.Commands you could/should execute are denoted with
$at the start, and have copy buttons; other text boxes show expected outputs.You may wish to have a text editor open on your machine, to amend copied commands before pasting them into the host’s CLI.
1.1. Ansible pre-flight checks
First let’s check that Ansible is installed on our host:
The output should look something like this:
ansible-playbook [core 2.11.5]
config file = None
configured module search path = ['/Users/jholland/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.9/site-packages/ansible
ansible collection location = /Users/jholland/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible-playbook
python version = 3.9.7 (default, Oct 13 2021, 06:45:31) [Clang 13.0.0 (clang-1300.0.29.3)]
jinja version = 2.11.3
libyaml = True
The PAN-OS Collection has been pre-installed for you. We can check the Collection is present using this command:
The output should list all the collections installed, including the PAN-OS collection, and the list should look something like this:
Collection Version
---------------------- -------
community.general 4.0.2
paloaltonetworks.panos 2.9.0
1.2. Download Ansible playbooks
In this workshop, we’re going to be using some existing playbooks. We’ll use git to download the playbooks from a repository…
…then move into the Ansible directory
1.3. Setup the inventory
Ansible needs to know the details for the hosts against which it should execute playbooks. This inventory can take many formats and locations, and for this workshop we will use the inventory format from the example playbooks repository.
In the ansible-playbooks directory, the inventory file contains a list of available hosts for us to run playbooks against:
firewall
ha_pair
panorama
panorama_ha_pair
All our example playbooks begin with a reference to a default target host from our inventory file, which is firewall:
- hosts: '{{ target | default("firewall") }}'
We provide the firewall’s IP address in the host_vars/firewall.yml file:
---
ip_address: '192.168.55.10'
Change the IP address in this file to match your firewalls’s management IP address, either use your preferred text editor to replace the IP address in host_vars/firewall.yml, or use this command:
Re-check the host_vars/firewall.yml file and ensure it now contains your firewall’s IP address, which for an example IP address of 10.10.10.10 should look like this:
---
ip_address: '10.10.10.10'
1.4. Prepare the firewall credentials
Before you can execute any Ansible playbooks, you need to be able to login to the firewall. We will store the admin username and admin password as variables.
For example:
$ export panos_username='adminuser'
$ export panos_password='ChangeMe#123!'
In production environments, credentials should be stored, accessed and used securely, per the security policy and compliance requirements. There are a variety of methods for this, today we will store these credentials as variables in memory for the duration of the CLI session with the export command.
1.5. Run our first Ansible playbook
Our first Ansible playbook will gather system information from the firewall. Data gathering or read-only tasks are good candidates for anyone starting out in automation. Execute the system-info.yml playbook using the command below:
Notice that we execute the ansible-playbook command, pass in the previously mentioned inventory using -i inventory, then specify the name of the playbook we want to run, system_info.yml, and finally pass in the firewall credentials with --extra-vars "username=$panos_username password=$panos_password".
Let’s look at the playbook we executed:
Breaking down the component parts of the playbook:
After the “comments” which are the lines starting with # characters, first we see the default host is firewall, from the previously mentioned inventory. Our connection type is local (we don’t use Ansible in a traditional method, because executing code on PAN-OS would work and would not be secure; instead we execute commands locally on our host, and those commands call the PAN-OS XML API).
- hosts: '{{ target | default("firewall") }}'
connection: local
Second we see a section of variables. We get the ip_address of the firewall from the previously mentioned inventory, and we get the username and password from the export commands we typed into the CLI. We don’t use the api_key in this instance.
vars:
device:
ip_address: '{{ ip_address }}'
username: '{{ username | default(omit) }}'
password: '{{ password | default(omit) }}'
api_key: '{{ api_key | default(omit) }}'
Now we get to our tasks, the jobs we want Ansible to do for us. We are just data gathering, so our first task is to gather facts, which in Ansible unsurprisingly are information about the target system. The second task uses the built-in debug to display a series of useful system information.
tasks:
- name: Gather facts for device
paloaltonetworks.panos.panos_facts:
provider: "{{ device }}"
- name: Display model, PAN-OS version
debug:
msg:
- "Hostname: {{ ansible_facts['net_hostname'] }}"
- "Serial: {{ ansible_facts['net_serial'] }}"
.
.
.
The output should look something like this, specifically the highlighted lines showing the information from our firewall:
PLAY [firewall] ***************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************
ok: [firewall]
TASK [Gather facts for device] ************************************************************************************************************
ok: [firewall]
TASK [Display model, PAN-OS version] ******************************************************************************************************
ok: [firewall] => {
"msg": [
"Hostname: vm-series-01",
"Serial: 01234567890",
"Model: PA-VM",
"Version: 10.1.3",
"Uptime: 46 days, 3:03:16",
"HA Enabled: True",
"HA Type: Active-Passive",
"HA Status: active",
"Multi-VSYS: off",
"1546 out of 256000 sessions in use"
]
}
PLAY RECAP ********************************************************************************************************************************
firewall : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1.6. Ansible Playbook 2 - Are you ready?
Our second playbook executes the show chassis-ready command. This is useful to ensure the firewall is ready to accept further operations such as configuration changes, software downloads and upgrades, and more. The check_ready.yml playbook runs the show chassis-ready command on a loop until it gets the positive yes result that the firewall is ready. Run the playbook using the following:
The playbook has the same opening sections for the hosts, connection, and variables. The tasks section is different, where this time we use a single task ( using`panos_op` to run show chassis-ready), then use Ansible’s retries and until to create the loop which waits for the firewall to be ready by virtue of the yes response. It will retry 50 times, trying every 30 seconds, until the output from the show chassis-ready is yes.
tasks:
- name: Check to see if device is ready
paloaltonetworks.panos.panos_op:
provider: '{{ device }}'
cmd: 'show chassis-ready'
changed_when: false
register: result
until: result is not failed and (result.stdout | from_json).response.result == 'yes'
retries: 50
delay: 30
The successful output should look something like this, specifically the highlighted line showing the “ok” response to checking if the firewall is ready:
PLAY [firewall] **************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************
ok: [firewall]
TASK [Check to see if device is ready] ***************************************************************************
ok: [firewall]
PLAY RECAP *******************************************************************************************************
firewall : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If the firewall is booting up, or not reachable, you would receive failure messages, and the loop of checking would kick in, like this:
PLAY [firewall] **************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************
ok: [firewall]
TASK [Check to see if device is ready] ***************************************************************************
FAILED - RETRYING: Check to see if device is ready (50 retries left).
FAILED - RETRYING: Check to see if device is ready (49 retries left).
1.7. Ansible Playbook 3 - More firewall information
The third example playbook, some_more_info.yml again gathers facts in order to display information about the running configuration and state of the firewall. This could be useful information on its own, but could also be used to feed into other tasks later on. Run the playbook using the following:
The playbook should provide information about the security policy rules, the network interfaces, and the route table.
1.8. Ansible Playbook 4 - Config backup/export
The next Ansible playbook uses the panos_export module to export the running config to a local file. Run the playbook using the following:
Once executed, you should be able to see the exported config file on yours host:
Confirm the exported file has a recent timestamp:
-rw-rw-r-- 1 labadmin labadmin 96164 Jun 22 10:00 running-config.xml
Optionally inspect the config:
1.9. Ansible Playbook 5 - Firewall configuration tasks
Our next playbook is focused on configuration tasks, and this playbook configures all the required items for a basic firewall setup, including zones, interfaces, objects and more:
tasks:
- name: Create DMZ zone
paloaltonetworks.panos.panos_zone:
provider: "{{ device }}"
zone: "dmz"
mode: "layer3"
.
.
.
You can see all the configuration items by viewing the playbook:
By logging into the firewall web GUI, you should be able to observe that these configuration items do not already exist.
Let’s execute the playbook:
By observing the firewall web GUI, you should be able to see the new configuration items.
1.10. Modify a playbook
The panos_op module is very useful within playbooks for gathering information and executing operational commands like gathering system information, software upgrades, content downloads, and more. It was used in the second playbook, check_ready.yml, to run the show chassis-ready command.
Choose one (or more) of the following operational commands to run with Ansible.
show clock
show admins all
show system disk-space
Edit the template.yml playbook (shown below) playbook with your preferred text editor, then execute your chosen commands. The output from the commands should be displayed.