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:

$ ansible-playbook --version

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:

$ ansible-galaxy collection list

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…

$ git clone https://github.com/jamesholland-uk/automation-workshops.git

…then move into the Ansible directory

$ cd automation-workshops/ansible

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:

$ cat inventory
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:

$ cat host_vars/firewall.yml
---
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:

$ cat > host_vars/firewall.yml <<EOL
---
ip_address: 'YOUR_FIREWALL_IP'
EOL

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:

$ cat host_vars/firewall.yml
---
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.

$ export panos_username='YOUR_ADMIN_USERNAME'
$ export panos_password='YOUR_ADMIN_PASSWORD'

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:

$ ansible-playbook -i inventory system_info.yml --extra-vars "username=$panos_username password=$panos_password"

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:

$ cat system_info.yml

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:

$ ansible-playbook -i inventory check_ready.yml --extra-vars "username=$panos_username password=$panos_password"

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:

$ ansible-playbook -i inventory some_more_info.yml --extra-vars "username=$panos_username password=$panos_password"

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:

$ ansible-playbook -i inventory backup_config.yml --extra-vars "username=$panos_username password=$panos_password"

Once executed, you should be able to see the exported config file on yours host:

$ ls -l running-config.xml

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:

$ cat running-config.xml  | xmllint --format -

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:

$ cat simple_config.yml

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:

$ ansible-playbook -i inventory simple_config.yml --extra-vars "username=$panos_username password=$panos_password"

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.

- name: Perform an op command
  paloaltonetworks.panos.panos_op:
    provider: '{{ device }}'
    cmd: 'command goes here'
  register: op_command_output

- name: Show output
  debug:
    msg:
      - "{{ op_command_output }}"