Skip to main content

Creating Address Objects from a CSV File

In this guide, you will create a number of address objects using a CSV file as the source configuration data. This is a common task when data is provided to you in a generic format like CSV.

The playbook created in this guide can be modified for data in CSV in many formats. For this example, we will use a format like this which includes a header row:

hostname,ip
test1,1.1.1.1
test2,2.2.2.2
test3,3.3.3.3
test4,4.4.4.4

Assumptions

This tutorial/guide assumes:

  • you have a working installation of Ansible with the PAN-OS collection installed (see example instructions here)
  • you have working connectivity to the firewall and/or Panorama
  • you have administrative credentials capable of performing the relevant operations on the firewall and/or Panorama

Important - Work in a Lab Environment First

With all of the tutorials and guides presented on this website, please ensure that you attempt the tasks in a lab or a similar safe and non-production environment first. In public cloud scenarios, this should be a non-production cloud account which contains no production assets or data. Confirm the tasks behave as expected and perform the operations you require, before using them in production or other live environments.

Create playbook files and define connectivity to the firewall

Create a new Ansible yaml file named csv-address-objects.yml, establish a variable block called device for the firewall, and reference the PAN-OS collection:

---
- name: Create Address Object from a CSV Source File
hosts: '{{ target | default("firewall") }}'
connection: local

vars:
device:
ip_address: "{{ ip_address }}"
username: "{{ username | default(omit) }}"
password: "{{ password | default(omit) }}"
api_key: "{{ api_key | default(omit) }}"

collections:
- paloaltonetworks.panos

Read the CSV file

You will first read in the CSV and register the data to a variable. The file should be stored in a location accessible to the host executing Ansible, and could be passed as an extra runtime variable. For one-off operations, the variable could be defined in the playbook itself

csv_filename: "../test.csv"

The first task in the playbook by uses read_csv to load the CSV file and store (register) the data in a variable called csv_data:

tasks:
- name: Read CSV file
ansible.builtin.read_csv:
path: "{{ csv_filename }}"
key: hostname
register: csv_data

Create address objects with a loop

You will now use the panos_address_object module, with an extra statement with_items at the end. This is one looping mechanism available in Ansible (more details here). The with_items statement asks the module to loop over the data passed in, which in your case is the csv_data from the first task (passed in dict format and looped over with dict2items):

    - name: Create address objects
paloaltonetworks.panos.panos_address_object:
provider: "{{ device }}"
name: "{{ item.value.hostname }}"
value: "{{ item.value.ip }}"
with_items: "{{ csv_data.dict | dict2items }}"

Add the new address objects to a group

The playbook could end there if your only objective is to create address objects based on the CSV source file. A follow-on task adds the newly created address objects to an address group. First, you will use set_fact to create a list of the address object names, based on the csv_data data from the CSV file, and store the list in a variable called address_objects_list:

- name: Create a list of the address objects
ansible.builtin.set_fact:
address_objects_list: "{{ csv_data.dict | dict2items | map(attribute='key') | list }}"

The list of address object names can now be added to an address group:

    - name: Add address objects to address group
paloaltonetworks.panos.panos_address_group:
provider: "{{ device }}"
name: test_group
static_value: "{{ address_objects_list }}"

Note that if the address group defined in the above task already exists, Ansible will overwrite the list of address objects in the group. If your goal is to add the new address objects to the existing group (not overwrite the existing list of address objects), use state: merged per the example below:

    - name: Add address objects to address group
paloaltonetworks.panos.panos_address_group:
provider: "{{ device }}"
name: test_group
static_value: "{{ address_objects_list }}"
state: merged

Create a security rule

Finally for this playbook, you will create a security rule which uses the address group created in the previous task:

    - name: Create a security rule
paloaltonetworks.panos.panos_security_rule:
provider: "{{ device }}"
state: "present"
rule_name: "Test rule"
source_zone: ["any"]
destination_zone: ["any"]
source_ip: ["test_group"]
source_user: ["any"]
destination_ip: ["any"]
application: ["ssh"]
action: "allow"

Final playbook

Putting all the sections together, the playbook in entirety looks like this:

---
- name: Create Address Object from a CSV Source File
hosts: "firewall"
connection: local

vars:
device:
ip_address: "{{ ip_address }}"
username: "{{ username }}"
password: "{{ password }}"

csv_filename: "../test.csv"

collections:
- paloaltonetworks.panos

tasks:
- name: Read CSV file
ansible.builtin.read_csv:
path: "{{ csv_filename }}"
key: hostname
register: csv_data

- name: Create address objects
paloaltonetworks.panos.panos_address_object:
provider: "{{ device }}"
name: "{{ item.value.hostname }}"
value: "{{ item.value.ip }}"
with_items: "{{ csv_data.dict | dict2items }}"

- name: Create a list of the address objects
ansible.builtin.set_fact:
address_objects_list: "{{ csv_data.dict | dict2items | map(attribute='key') | list }}"

- name: Add address objects to address group
paloaltonetworks.panos.panos_address_group:
provider: "{{ device }}"
name: test_group
static_value: "{{ address_objects_list }}"

- name: Create a security rule
paloaltonetworks.panos.panos_security_rule:
provider: "{{ device }}"
state: "present"
rule_name: "Test rule"
source_zone: ["any"]
destination_zone: ["any"]
source_ip: ["test_group"]
source_user: ["any"]
destination_ip: ["any"]
application: ["ssh"]
action: "allow"