Automating & Scripting The Network with Ansible – Palo Alto: Deploy Address Objects

Hey guys,

I know it has been some time since I posted something, I have been quite busy with family, work and studies and I haven’t had really anything that I wanted to post on. However as I have been developing my skills in Python and Ansible, I have come up with some material which I will slowly share over the next few weeks and I hope it will be quite helpful.

To get started, I want you to check out the GitHub repo link below. This contains all the playbooks I will be showing throughout these posts (in fact there will be playbooks in there which are a few weeks ahead of schedule most likely). The playbooks here are not exactly what is used in my tests as I will be modifying it for general usage and then pushing it to GitHub. So feel free to use the plays and playbooks in this repo to your hearts content and also feel free to offer me feedback on how to improve it or add functionality!

GitHub Repo – https://github.com/danielbostock/ansible-panos

Let’s get started!

Anyone who has used a security device (aka: Network Firewall) in the last 5 years or more will be quite familiar with objects and the various uses within the respective security devices. In this post I am limiting it to how PanOS uses them specifically within the context of an address object.

With that in mind, I am going to leave out any explanation about objects and let you do your own research if necessary.

create_address_objects.yml
https://github.com/danielbostock/ansible-panos/blob/master/objects/create_address_objects.yml

1. Leverage Palo Alto’s Collection

  collections:
    - paloaltonetworks.panos

In my opinion (which by the way is extremely limited at this point), I believe that part of writing really good Ansible playbooks is definitely in leveraging Roles or their parent collections (as of Ansible 2.9). It’s like making really good classes and definitions in other scripting languages, it essentially allows us to make more repeatable code.

In this instance I am obviously using Palo Alto’s maintained collection, which is quite extensible and very easy to leverage. If you would like to get your hands on it, follow the link below and make sure you obtain the required python modules as well.

https://ansible-pan.readthedocs.io/en/latest/index.html

2. Building the Variables

  vars_files:
    - vars/address_objects.yml

  vars:
    - panos_provider: 
        ip_address: '{{ fw_ip_address }}'
        username: '{{ fw_username }}'
        password: '{{ fw_password }}'
        api_key: '{{ api_key }}'
    - address_objects: vars/address_objects.yml

In this portion I build my vars that I will use in this playbook. The vars_files parameter allows me to reference external vars through another variable which is created below. The reason I have chosen to do this is because I want this playbook to be quite static, and allow variable files to constantly be changed. This is to create a standard and repeatable way in which I deploy changes to my firewall – this is foundational to all code I write, be it Python or Ansible playbooks.

The panos_provider is another example of this, as it is leveraged by the ansible vault file, which for the sake of showing the flexible nature of Ansible I have pulled the vars file using the command include_vars. Which you will find in the tasks portion of the playbook, see below.

  tasks:
  - name: Grab the credentials from ansible-vault
    include_vars: 'vars/vaultfile1.yml'
    no_log: 'yes'

This vault file is encrypted with a Sha256 encryption algorithm and decrypted when I run the ansible-playbook command using the additonal argument –ask-vault-pass. This allows me to keep my username and password stored safely and in one file – I strongly encourage doing this!

So as you can see by leveraging vars I have created a rather modular playbook. In fact, I will go further and show you how modular it is in my next post and then some other subsequent ones. One of the key things I have learned recently with my studies is following the DRY principle – Don’t Repeat Yourself!

I just want to touch on this bit of code below which seems a bit random for any not familiar with PanOS.

     - admins:
       - fwadmin1

Whenever someone is in a Palo or Panorama and is doing changes, configuration will be stored in what is called candidate configuration and is assigned to the user. Without going into it too far (refer to Palo’s documentation if you wish to know more), depending on your Palo configuration it may lock (config lock) the changes to an admin (automatically, if configured this way).

However if it is unlocked, you can either choose to push commit configuration based on your user or you can commit all configuration sitting in candidate configuration. It is obviously recommended to only apply configuration under your username in a shared environment. So this portion will be leveraged in the post_task which commits the candidate config.

3. Create Address Objects

  - name: Create address objects
    panos_address_object:
      provider: '{{ panos_provider }}'
      name: '{{ item.value.address_name }}'
      value: '{{ item.value.address_ip }}'
      description: '{{ item.value.address_description }}'
      state: 'present'
      #tag: ['AnsibleTest']
      commit: no
    with_dict: "{{ address_objects }}"

This is the actual PanOS module we are all really here for, so I will attempt to break it down for you. Remember Palo has all the documentation at a more technical level for all PanOS ansible modules – https://ansible-pan.readthedocs.io/en/latest/

Provider: “{{ panos_provider }}”

This actually has sub parameters, but I have created a dictionary variable file entry (in the form of a ansible-vault encrypted file) which matches the required credentials for the provider. You could make one yourself too, here this is what I have done. Obviously enter in your respective credentials. I should note the API key entry is not needed if you put in username and password. Refer to the documentation link above.

fw_ip_address:
fw_username:
fw_password:
api_key:

Parameter Vars: name, value, description

Since we are now discussing vars files, here is the vars file entry. You can find this in my ansible-panos repo.

address_objects:
  AddressObject1:
    address_name: Server1
    address_ip: '10.20.10.1'
    address_description: This is a test address object1
  AddressObject2:
    address_name: Server2
    address_ip: '10.20.10.2'
    address_description: This is a test address object2
  AddressObject3:
    address_name: Server3
    address_ip: '10.20.10.3'
    address_description: This is a test address object3

It is quite self explanatory, but these 3 var key value pairs are adjustable, and in fact you can keep copying and pasting them and make many more. In a subsequent post, I will be discussing how we could leverage a CSV file instead for larger amounts of objects, but it is not in the scope of this post – keeping it simple!

State: Present

If you have used Ansible with anything else you will be aware of the parameter – state, it is quite universal throughout Ansible and is very handy. This parameter, will make a new object if it is not present, if it is present it will not make one.

Commit: No

This one is rather important. If you are intending to create multiple objects, this will cause significant delays because after each object it will commit the configuration. This is why I have the commit module in the post tasks as I want to commit together in order to save significant time. I wish it commit: no was the default position, it makes more sense in an Ansible playbook.

With_dict: “{{ address_objects }}”

It is obvious what this is doing, but I will add that I like using dict files as they are quite flexible and modular as opposed to with_items (or some of the other Ansible loop types), but again a personal preference. It is quite a solid loop action to use and gives nice readable structure to the var files leveraged by it.

Final Thoughts

Quite simple huh!? If you are familiar with Ansible and have it installed and have access to a Palo, go on give it a crack! If you need help getting going on doing this send me a message and I will help get you going along with links to walk throughs I have also used.

Also I want to note that this is the first playbook of two. I will build upon this playbook and indeed keep the idea of keeping my code modular and repeatable. Once these two playbooks have been done and dusted, I will move onto tags, because I am a firm believer in the power of tags and what can be done with them in code and through the GUI in PanOS.

Have a great rest of the week and stay safe everyone!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.