• Skip to main content
  • Skip to footer

Andrew Roderos

Networking and Security

  • Blog
  • Resources
    • Book List
    • Freebies
  • About
  • Contact

Palo Alto Ansible Network Automation: Automating IP address validation

12/02/2024 by Andrew Roderos Leave a Comment

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

In my previous post, I shared a tutorial on writing an Ansible playbook to check for available and unavailable VSYS names on a Palo Alto Networks firewall. Today, we’ll explore an Ansible playbook designed to verify the availability of user-defined IP address with prefix length on a Palo Alto Networks firewall.

This post contains affiliate links, which means I may earn a commission if you click through and make a purchase. This comes at no additional cost to you. Full disclosure here.

The Ansible playbook

The playbook checks if the user-inputted IP address with prefix length is valid and within the range of RFC 1918. Moreover, it checks if the IP address overlaps with network ranges already used on the firewall. It also checks if existing networks on the firewall are subnets of the user-inputted IP address with prefix length.

Breaking it down

To help those folks who are new to Ansible, I will break down each section of the playbook.

---
- name: Check IPv4
  hosts: '{{ panfw }}'
  gather_facts: false
  connection: local

  collections:
    - paloaltonetworks.panos

The playbook begins by specifying its name, followed by the host or group of hosts to run the playbook against. The {{ panfw }} variable will be replaced with its actual value at runtime. In this case, the user will input the name of the target firewall by specifying it in the ansible-playbook -e command option.

The following line tells Ansible not to gather facts about the hosts before running the playbook. Facts are information about the hosts, such as their operating system, IP addresses, etc.

In line five, this specifies the connection method to use when communicating with the hosts. In this case, local means that Ansible will run the tasks on the local machine, rather than connecting to the hosts remotely.

Following line five, this tells Ansible to use paloaltonetworks.panos collection, which is a collection of modules and plugins for managing Palo Alto Networks firewalls.

First task

This task ensures that the input IPv4 address (ipadd), a user-supplied value, is valid and belongs to a defined set of networks (rfc1918). Before I explain the task further, I want to mention that I chose not to define the rfc1918 variable in the playbook and decided to put it in group_vars/PAN.yml.

    - name: Validate ipadd user-defined value
      ansible.builtin.assert:
        that:
          - ipadd.split('/')[0] is ansible.utils.in_any_network rfc1918
        fail_msg: "The provided IPv4 address '{{ ipadd }}' is not valid."
        success_msg: "The provided IPv4 address '{{ ipadd }}' is valid."

Alternatively, we can write the playbook with a variable section after the collections section.

  vars:
    rfc1918:
      - "10.0.0.0/8"
      - "172.16.0.0/12"
      - "192.168.0.0/16"

Let’s examine each component of this task in detail. The first line is self-explanatory. It describes what the task does.

The assert module on the second line verifies if a given expression is true. If not, it displays a message and terminates playbook execution.

The core validation logic is in the that section. This keyword always comes after the assert module line.

Next, I’m instructing Ansible to split it at the / character. By using [0] it extracts just the IP address portion of the user-defined value.

The fifth line checks if the extracted IP address is part of the RFC1918 networks. You can read more about the in_any_network test plugin here.

Want to learn more about Ansible? Ansible for DevOps

If the assertion logic fails, the message in the fail_msg line will be displayed. If the assertion logic passes, the message in the succes_msg line will be displayed.

Running the playbook

Let’s test the first task and see how it behaves.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa5250 ipadd=10.111.111.1/24"

PLAY [Check IPv4] *********************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **********************************************************************************************************************************************************************************
ok: [pa5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '10.111.111.1/24' is valid."
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************
pa5250             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

As shown, the validation check confirms the user input is a valid address within the RFC1918 private address space.

Now, let’s put an invalid IP address.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa5250 ipadd=300.300.300.300/24"

PLAY [Check IPv4] *********************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **********************************************************************************************************************************************************************************
fatal: [pa5250]: FAILED! => {
    "assertion": "ipadd.split('/')[0] is ansible.utils.in_any_network rfc1918",
    "changed": false,
    "evaluated_to": false,
    "msg": "The provided IPv4 address '300.300.300.300/24' is not valid."
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************
pa5250             : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

As shown, the assertion failed, and the playbook execution was terminated.

Second task

This task retrieves information about the firewall’s network interfaces using the paloaltonetworks.panos.panos_facts module. The register keyword allows us to register the value in memory for further actions in the next task.

    - name: Gather interface facts for the device
      paloaltonetworks.panos.panos_facts:
        provider: "{{ palo_provider }}"
        gather_subset: ['interfaces']
      register: int_list

Running the playbook

As you can see, there are multiple fields that we don’t care about, so in the next task, we need to extract only the IPv4 address prefixes.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa5250 ipadd=10.111.111.1/24"

PLAY [Check IPv4] *********************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **********************************************************************************************************************************************************************************
ok: [pa5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '10.111.111.1/24' is valid."
}

TASK [Gather interface facts for the device] ******************************************************************************************************************************************************************************
ok: [pa5250]

TASK [ansible.builtin.debug] **********************************************************************************************************************************************************************************************
ok: [pa5250] => {
    "int_list": {
        "ansible_facts": {
            "ansible_net_full_commit_required": false,
            "ansible_net_gather_subset": [
                "system",
                "interfaces"
            ],
            "ansible_net_hostname": "PA-5250",
            "ansible_net_interfaces": [
                {
                    "comment": null,
                    "ip": null,
                    "ipv6": [],
                    "name": "ae1"
                },
                {
                    "comment": null,
                    "ip": [
                        "172.27.184.113/29"
                    ],
                    "ipv6": [
                        "2001:aaaa:bbbb:cccc::bad:c0ff:ee:1/64"
                    ],
                    "name": "ae1.501",
                    "tag": 501
                },
                {
                    "comment": null,
                    "ip": [
                        "172.27.184.129/25"
                    ],
                    "ipv6": [
                        "2001:aaaa:bbbb:cccc:bad:c0ff:ee:1/64"
                    ],
                    "name": "ae1.502",
                    "tag": 502
                },
                {
                    "comment": null,
                    "ip": [
                        "10.41.247.1/24"
                    ],
                    "ipv6": [
                        "2001:aaaa:bbbb:cccc:bad:c0ff:ee:1/64"
                    ],
                    "name": "ae1.503",
                    "tag": 503
                },
                {
                    "comment": null,
                    "ip": [
                        "10.41.244.137/29"
                    ],
                    "ipv6": [
                        "2001:aaaa:bbbb:cccc:bad:c0ff:ee:1/64"
                    ],
                    "name": "ae1.504",
                    "tag": 504
                },
                {
                    "comment": "Testing",
                    "ip": [
                        "8.8.8.1/22"
                    ],
                    "ipv6": [],
                    "name": "ethernet1/1"
                },
                {
                    "comment": "Internet",
                    "ip": [
                        "1.1.1.1/29"
                    ],
                    "ipv6": [],
                    "name": "ethernet1/1.2269",
                    "tag": 2269
                },
                {
                    "comment": null,
                    "ip": null,
                    "ipv6": [],
                    "name": "ethernet1/2"
                },
                {
                    "comment": null,
                    "ip": [
                        "10.118.0.129/25",
                        "172.24.55.225/27"
                    ],
                    "ipv6": [],
                    "name": "ethernet1/2.100",
                    "tag": 3675
                },
                {
                    "comment": null,
                    "ip": [
                        "2.2.2.1/24"
                    ],
                    "ipv6": [],
                    "name": "ethernet1/2.35",
                    "tag": 35
                },
                {
                    "comment": null,
                    "ip": [
                        "172.20.42.113/28"
                    ],
                    "ipv6": [],
                    "name": "ethernet1/2.3674",
                    "tag": 3674
                },
                {
                    "comment": "rtr1",
                    "ip": [
                        "169.254.224.25/30"
                    ],
                    "ipv6": [],
                    "name": "tunnel.1"
                },
                {
                    "comment": "rtr2",
                    "ip": [
                        "169.254.224.29/30"
                    ],
                    "ipv6": [],
                    "name": "tunnel.2"
                }
            ],
            "ansible_net_model": "PA-5250",
            "ansible_net_multivsys": "on",
            "ansible_net_serial": "111111111111",
            "ansible_net_uncommitted_changes": false,
            "ansible_net_uptime": "62 days, 2:21:26",
            "ansible_net_version": "10.2.8",
            "discovered_interpreter_python": "/usr/bin/python3"
        },
        "changed": false,
        "failed": false
    }
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************
pa5250             : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Third task

This task extracts all defined IPv4 addresses from the previous information from the firewall. It uses the ansible.buitin.set_fact module to create a new variable for future use.

    - name: Extract IPv4 addresses only
      ansible.builtin.set_fact:
        ipv4_list: "{{ int_list['ansible_facts']['ansible_net_interfaces'] int_list | selectattr('ip', 'defined') | map(attribute='ip') | flatten | select('string') | list }}"

The ipv4_list: "{{ int_list['ansible_facts']['ansible_net_interfaces'] part accesses the interface data collected from the previous task. Since we are interested in the key-value pairs that contain the IP information, we needed to access the ansible_net_interfaces dictionary.

Using selectattr('ip', 'defined'), Ansible filters the data to include only items with a defined IP address.

Do you find this content useful?
If so, consider buying me a coffee!

☕️ Buy me a coffee

Next, the map(attribute='ip') extracts the IP address attribute from the filtered results.

Since the output shows a nested list, I used the flatten Jinja2 filter to flatten the list.

Using the select('string') ensures the list only includes string values with valid IPs.

Then, the list converts the result into a Python list format.

Running the playbook

As you can see, we now have a list of IPv4 addresses that we can use for the next task.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=10.111.111.1/24"

PLAY [Check IPv4] *********************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **********************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '10.111.111.1/24' is valid."
}

TASK [Gather interface facts for the device] ******************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ******************************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [ansible.builtin.debug] **********************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "ipv4_list": [
        "172.27.184.113/29",
        "172.27.184.129/25",
        "10.41.247.1/24",
        "10.41.244.137/29",
        "8.8.8.1/22",
        "1.1.1.1/29",
        "10.118.0.129/25",
        "172.24.55.225/27",
        "2.2.2.1/24",
        "172.20.42.113/28",
        "169.254.224.25/30",
        "169.254.224.29/30"
    ]
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************
pa-5250             : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Fourth task

This task is responsible for converting the list of IPv4 addresses from the previous task into their respective network address representations in CIDR notation. It uses the ansible.builtin.set_fact module to create a new variable for future use. Performing this task allows us to have a standardized format that can be used for validation or checks in subsequent tasks.

    - name: Convert the list into network address CIDR notation
      ansible.builtin.set_fact:
        ipv4_list_net: "{{ ipv4_list | ansible.utils.ipaddr('network/prefix') | ansible.utils.ipaddr('0') }}"

The ansible.utils.ipaddr('network/prefix') part converts the individual IP addresses into their respective network address representations using CIDR notation.

The ansible.utils.ipaddr('0') part specifies a network mask of 0, which ensures that the converted output correctly contains the network address.

Running the playbook

As you can see, the updated list now shows all network address CIDR notations. This updated list allows us to use it in the latter part of the playbook.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=10.111.111.1/24"

PLAY [Check IPv4] *********************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **********************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '10.111.111.1/24' is valid."
}

TASK [Gather interface facts for the device] ******************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ******************************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the ipadd to network address CIDR notation] **********************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "ipv4_list": [
        "172.27.184.112/29",
        "172.27.184.128/25",
        "10.41.247.0/24",
        "10.41.244.136/29",
        "8.8.8.0/22",
        "1.1.1.0/29",
        "10.118.0.128/25",
        "172.24.55.224/27",
        "2.2.2.0/24",
        "172.20.42.112/28",
        "169.254.224.24/30",
        "169.254.224.28/30"
    ]
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************
pa-5250             : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Fifth task

This task converts a user-provided IP address (ipadd) into network address CIDR notation. It creates a new variable (ipadd_net) to hold this formatted address, which we will use in the latter part of the playbook.

    - name: Convert the ipadd to network address CIDR notation
      ansible.builtin.set_fact:
        ipadd_net: "{{ ipadd | ansible.utils.ipaddr('network/prefix') | ansible.utils.ipaddr('0') }}"

The ansible.utils.ipaddr('network/prefix') converts the user-defined IP address with prefix length into its corresponding network representation in CIDR notation.

Using the ansible.utils.ipaddr('0') ensures that the result will always be the network address.

Running the playbook

As you can see, the task successfully converted the user-defined IP address with prefix length into its equivalent network address in CIDR notation format.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=10.111.111.1/24"

PLAY [Check IPv4] *********************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **********************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '10.111.111.1/24' is valid."
}

TASK [Gather interface facts for the device] ******************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ****************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the list into network address CIDR notation] ****************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the ipadd to network address CIDR notation] *****************************************************************************************************************************************************************
ok: [pa-5250]

TASK [ansible.builtin.debug] **********************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "ipadd_net": "10.111.111.0/24"
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************
pa-5250             : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Sixth task

This task verifies the network’s availability or unavailability by checking the user-defined value (ipadd) against existing networks on the firewall. Moreover, the task loops through the list of networks and appends the availability or unavailability message to the net_check_reuslts_ipadd variable. This information is crucial for avoiding network conflicts.

    - name: Check if the network for ipadd is available or not
      ansible.builtin.set_fact:
        net_check_ipadd: >
          {{ net_check_ipadd | default([]) + [{ 'item': item,
          'msg': 'The network is already in use.' if ipadd_net == item or ipadd_net is ansible.utils.subnet_of(item) or
          item is ansible.utils.subnet_of(ipadd_net) else 'The network is available to be used.' }] }}

The net_check_ipadd | default([]) checks if net_check_ipadd is already defined. If it is not, it defaults to an empty list ([]).

The [{ 'item': item, 'msg' part defines a dictionary with two keys: 'item' and 'msg'. The 'item': item: sets the value of the 'item' key to the value of the variable item. The 'msg': 'The network is already in use.' if ipadd_net == item or ipadd_net is ansible.utils.subnet_of(item) or item is ansible.utils.subnet_of(ipadd_net) else 'The network is available to be used.' part sets the value of the 'msg' key based on a conditional expression.

Related: Automating VSYS name management

Let’s explore the three conditional expressions. The first condition checks if the network represented by ipadd_net is the same as item. The second condition checks if ipadd_net is a subnet of item using the ansible.utils.subnet_of function. The last condition checks if item is a subnet of ipadd_net using the ansible.utils.subnet_of function.

Running the playbook

As you can see, the task successfully validated whether the user’s input is available to be used on the firewall.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=172.27.184.193/26"

PLAY [Check IPv4] *************************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '172.27.184.193/26' is valid."
}

TASK [Gather interface facts for the device] **********************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ********************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the list into network address CIDR notation] ********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the ipadd to network address CIDR notation] *********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Check if the network for ipadd is available or not] *********************************************************************************************************************************************************************
ok: [pa-5250] => (item=172.27.184.112/29)
ok: [pa-5250] => (item=172.27.184.128/25)
ok: [pa-5250] => (item=10.41.247.0/24)
ok: [pa-5250] => (item=10.41.244.136/29)
ok: [pa-5250] => (item=8.8.8.0/22)
ok: [pa-5250] => (item=1.1.1.216/29)
ok: [pa-5250] => (item=10.118.0.128/25)
ok: [pa-5250] => (item=172.24.55.224/27)
ok: [pa-5250] => (item=2.2.2.0/24)
ok: [pa-5250] => (item=172.20.42.112/28)
ok: [pa-5250] => (item=169.254.224.24/30)
ok: [pa-5250] => (item=169.254.224.28/30)

TASK [ansible.builtin.debug] **************************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "net_check_ipadd": [
        {
            "item": "172.27.184.112/29",
            "msg": "The network is available to be used."
        },
        {
            "item": "172.27.184.128/25",
            "msg": "The network is already in use."
        },
        {
            "item": "10.41.247.0/24",
            "msg": "The network is available to be used."
        },
        {
            "item": "10.41.244.136/29",
            "msg": "The network is available to be used."
        },
        {
            "item": "8.8.8.0/22",
            "msg": "The network is available to be used."
        },
        {
            "item": "1.1.1.216/29",
            "msg": "The network is available to be used."
        },
        {
            "item": "10.118.0.128/25",
            "msg": "The network is available to be used."
        },
        {
            "item": "172.24.55.224/27",
            "msg": "The network is available to be used."
        },
        {
            "item": "2.2.2.0/24",
            "msg": "The network is available to be used."
        },
        {
            "item": "172.20.42.112/28",
            "msg": "The network is available to be used."
        },
        {
            "item": "169.254.224.24/30",
            "msg": "The network is available to be used."
        },
        {
            "item": "169.254.224.28/30",
            "msg": "The network is available to be used."
        }
    ]
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************
pa-5250             : ok=7    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Seventh task

This task checks if there are any messages in the net_check_results_ipadd list that contain the phrase “The network is already in use.” If the messages exist, it sets the variable unavail_net_ipadd to True; otherwise, it sets it to False.

    - name: Check if any message contains already in use for net_check_ipadd
      ansible.builtin.set_fact:
        unavail_net_ipadd: "{{ net_check_ipadd | selectattr('msg', 'search', 'The network is already in use.') | list | length > 0 }}"

The net_check_ipadd | selectattr('msg', 'search', 'The network is already in use.') part uses the selectattr filter to filter the net_check_ipadd list. The selectattr('msg', 'search', 'The network is already in use.')selects only those dictionaries in the net_check_ipadd list where the value of the msg key contains the substring “The network is already in use.” The | list converts the filtered result into a list. The | length calculates the length of the resulting list. The > 0 checks if the length of the list is greater than 0.

Running the playbook

As you can see, the task identified at least one message with the phrase “The network is already in use”.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=172.27.184.193/26"

PLAY [Check IPv4] *************************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '172.27.184.193/26' is valid."
}

TASK [Gather interface facts for the device] **********************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ********************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the list into network address CIDR notation] ********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the ipadd to network address CIDR notation] *********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Check if the network for ipadd is available or not] *********************************************************************************************************************************************************************
ok: [pa-5250] => (item=172.27.184.112/29)
ok: [pa-5250] => (item=172.27.184.128/25)
ok: [pa-5250] => (item=10.41.247.0/24)
ok: [pa-5250] => (item=10.41.244.136/29)
ok: [pa-5250] => (item=8.8.8.0/22)
ok: [pa-5250] => (item=1.1.1.216/29)
ok: [pa-5250] => (item=10.118.0.128/25)
ok: [pa-5250] => (item=172.24.55.224/27)
ok: [pa-5250] => (item=2.2.2.0/24)
ok: [pa-5250] => (item=172.20.42.112/28)
ok: [pa-5250] => (item=169.254.224.24/30)
ok: [pa-5250] => (item=169.254.224.28/30)

TASK [Check if any message contains already in use for ipadd] *****************************************************************************************************************************************************************
ok: [pa-5250]

TASK [ansible.builtin.debug] **************************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "unavail_net_ipadd": true
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************
pa-5250             : ok=8    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Eighth task

This task will display the message “The network for the first IP address/prefix is already in use.” if the variable unavail_net_ipadd is True. If the previous task resulted in a False condition, this will be skipped.

    - name: Display message if any networks are unavailable for net_check_ipadd
      ansible.builtin.debug:
        msg: "The network is already in use."
      when: unavail_net_ipadd

Running the playbook

As you can see, I ran the same command as the previous one to show that this task correctly displayed that the network is already in use.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=172.27.184.193/26"

PLAY [Check IPv4] *************************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '172.27.184.193/26' is valid."
}

TASK [Gather interface facts for the device] **********************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ********************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the list into network address CIDR notation] ********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the ipadd to network address CIDR notation] *********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Check if the network for ipadd is available or not] *********************************************************************************************************************************************************************
ok: [pa-5250] => (item=172.27.184.112/29)
ok: [pa-5250] => (item=172.27.184.128/25)
ok: [pa-5250] => (item=10.41.247.0/24)
ok: [pa-5250] => (item=10.41.244.136/29)
ok: [pa-5250] => (item=8.8.8.0/22)
ok: [pa-5250] => (item=1.1.1.216/29)
ok: [pa-5250] => (item=10.118.0.128/25)
ok: [pa-5250] => (item=172.24.55.224/27)
ok: [pa-5250] => (item=2.2.2.0/24)
ok: [pa-5250] => (item=172.20.42.112/28)
ok: [pa-5250] => (item=169.254.224.24/30)
ok: [pa-5250] => (item=169.254.224.28/30)

TASK [Check if any message contains already in use] *******************************************************************************************************************************************************
ok: [pa-5250]

TASK [Display message if any networks are unavailable] ****************************************************************************************************************************************************
ok: [pa-5250] => {
    "msg": "The network is already in use."
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************
pa-5250             : ok=9    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ninth task

This task will display the message “The network for the first IP address/prefix is available.” if the variable unavail_net_ipadd is False. If the previous task resulted in a True condition, this will be skipped.

    - name: Display message if all networks are available
      ansible.builtin.debug:
        msg: "The network is available."
      when: not unavail_net_ipadd

Running the playbook

As you can see, I entered a different network that I know is available to show that this task will correctly display that the network is available.

$ ansible-playbook pan-check-ipv4.yml -e "panfw=pa-5250 ipadd=10.1.1.0/24"

PLAY [Check IPv4] *************************************************************************************************************************************************************************************************************

TASK [Validate ipadd user-defined value] **************************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "changed": false,
    "msg": "The provided IPv4 address '172.27.184.193/26' is valid."
}

TASK [Gather interface facts for the device] **********************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Extract IPv4 addresses only] ********************************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the list into network address CIDR notation] ********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Convert the ipadd to network address CIDR notation] *********************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Check if the network for ipadd is available or not] *********************************************************************************************************************************************************************
ok: [pa-5250] => (item=172.27.184.112/29)
ok: [pa-5250] => (item=172.27.184.128/25)
ok: [pa-5250] => (item=10.41.247.0/24)
ok: [pa-5250] => (item=10.41.244.136/29)
ok: [pa-5250] => (item=8.8.8.0/22)
ok: [pa-5250] => (item=1.1.1.216/29)
ok: [pa-5250] => (item=10.118.0.128/25)
ok: [pa-5250] => (item=172.24.55.224/27)
ok: [pa-5250] => (item=2.2.2.0/24)
ok: [pa-5250] => (item=172.20.42.112/28)
ok: [pa-5250] => (item=169.254.224.24/30)
ok: [pa-5250] => (item=169.254.224.28/30)

TASK [Check if any message contains already in use] ***************************************************************************************************************************************************************************
ok: [pa-5250]

TASK [Display message if any networks are unavailable] ************************************************************************************************************************************************************************
skipping: [pa-5250]

TASK [Display message if all networks are available] **************************************************************************************************************************************************************************
ok: [pa-5250] => {
    "msg": "The network is available."
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************
pa-5250             : ok=9    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Final words

In this post, I discussed an Ansible playbook that will ensure user-defined IP addresses conform to RFC1918 standards and checks if they are already in use on the firewall. By automating these tasks, network engineers can efficiently manage network configurations, saving time and reducing errors. This playbook is a valuable tool for maintaining an organized and conflict-free network environment.

Disclosure

AndrewRoderos.com is a participant of a few referral programs, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to company websites.

Related posts

Ansible: Accepting user input variables

BUY ME COFFEE

Did you find this content useful?
If so, show your appreciation by buying me a coffee!

☕️ Buy me a coffee

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Filed Under: Automation Tagged With: Ansible, Network Automation, Network Security, Palo Alto Networks, PAN-OS, PANOS

About Andrew Roderos

I am a network security engineer with a passion for networking and security. Follow me on Twitter, LinkedIn, and Instagram.

Footer

WANT TO REACH ME?

Let’s talk!

CONTACT ME

Copyright © 2019–2026 · Andrew Roderos · All Rights Reserved · Privacy Policy · Terms of Use