Skip to content

Automating & Scripting The Network with Ansible – Palo Alto: Create tag objects, and attach to network address objects.

Hope everyone had a great Easter break!

You know I have to say this little mini series has been really fun for me, it has also been super easy. I hope if you have access to a Palo Alto and are slightly interested in getting started with moving your network changes to code you start off small like this. It is really not that hard or scary – I promise you!

Administrative stuff…

GitHub Repo:

Palo Alto Ansible Module Documentation:

So without further adue…

Let’s get started!

There is no new playbook with this post. I am simply adding to the playbook used in the last post, and I am adding the module in, creating a new vars file and updating existing ones. That’s all there is to it, if you make your playbooks modular, this is what you can do!

Building the Variables

So I can keep everything clean and easy like the previous posts, I have created a new dict vars file. I would like to point out that like with many things in life there is a time and place for everything, vars files are especially one of them and I am sure we all personally have views.

I want to share from my limited experiences that there are pro’s and con’s to the two overarching type of vars files I am using in these blog posts, I should also state jinja templates are a same but different thing, and a whole other beast to talk about. However Lets go over these quickly (feel free to comment below if you agree or disagree!).

Central Multi Purpose Dictionary Vars File

  1. Single place to update all variables
  2. Can be leveraged throughout playbook(s) over multiple different modules
  3. Can help keep better uniformity with naming conventions
  1. Does not scale
  2. Needs to be quite general in nature otherwise gets very hard to manage

Multiple Singular Purpose Dictionary Vars File

  1. Scales very well
  2. More re-usable for playbooks that are used regularly for regular changes (objects, routes, security policies etc)
  3. Can be tailored more specifically to the Ansible module needs and does not need to be so general
  4. Easier to digest and explain in documentation
  1. Uniformity of naming conventions or other misc things can be broken easily
  2. Is very specific and does not include vars outside of what is is necessary for its module it is being used with

There are probably some other things I have missed in both but just from my limited this is my point of view.

In summary, I will often create a central dictionary vars file for say an application deployment, but use multiple single purpose dictionary vars files on those playbooks which are constantly re-run so I can update the specific dictionaries as needed. But then again, sometimes I use a mix of both, Ansible is that flexible!

Now that, the side track is over, lets actually look at the new vars file…

    name: 'Addr_Obj_Grp1'
    color: 'purple'
    comments: 'Address Object Group1'
    name: 'Addr_Obj_Grp2'
    color: 'blue'
    comments: 'Address Object Group2'
    name: 'Addr_Obj_Grp3'
    color: 'orange'
    comments: 'Address Object Group3'

This has a very similar structure to what I have already been using. I just want to point out a gotcha – “color” key-pair has to match a very limited set of colors, compared to what is currently available through the PanOS web gui. I suspect they will expand the Python under the module eventually to contain all the other colors, for now you are limited to the colors listed in the documentation which is at the start of this blog.

The rest of the key pairs here are quite self explanatory, so I will go onto the var files that I updated to include the tags to be used in the playbook.

    address_name: Server1
    address_ip: ''
    address_description: This is a test address object1
    tag: 'Addr_Obj_Grp1'
    address_name: Server2
    address_ip: ''
    address_description: This is a test address object2
    tag: ['Addr_Obj_Grp1', 'Addr_Obj_Grp2']
    address_name: Server3
    address_ip: ''
    address_description: This is a test address object3
    tag: 'Addr_Obj_Grp1'

Starting with address_objects vars dictionary file. In here I simply added the tag key pair. With AddressObject2 you will notice I added two there instead. This is to just show you what I could do. In fact you can have many in there, and all over the place too, which is what I was trying to show with the tag not really corresponding to the actual group.

Remember when the module grabs this var, and the spelling is not exact (case sensitive), it will create new tags.

    address_group_name: Address_Group_Object1
    address_objects: ['Server1', 'Server2']
    tag: 'Addr_Obj_Grp1'
    address_group_name: Address_Group_Object2
    address_objects: Server3
    tag: 'Addr_Obj_Grp2'

I have done a similar thing here with the address_object_groups, except that I have limited it to just the two respective groups. As another side note, typically what happens with individual address objects and service objects the tags are little bit more liberal and can be part of multiple group tags. There is obviously a plethora of reasons for this. Object Groups will typically have less tags and I have kind of represented that here in this example in my vars file.

Alright so lets look at new and re-invigorated playbook!

    - vars/address_objects.yml
    - vars/address_object_groups.yml
    - ./tag_objects.yml

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

    - admins:
       - fwadmin1

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

  - name: Create the tags
      provider: '{{ panos_provider }}'
      name: '{{ }}'
      color: '{{ item.value.color }}'
      comments: '{{ item.value.comments }}'
      commit: no
    with_dict: "{{ tag_objects }}"

  - name: Create address objects from vars file - address_objects.yml
      provider: '{{ panos_provider }}'
      name: '{{ item.value.address_name }}'
      value: '{{ item.value.address_ip }}'
      description: '{{ item.value.address_description }}'
      state: 'present'
      tag: '{{ item.value.tag }}'
      commit: no
    with_dict: "{{ address_objects }}"

  - name: Create address object groups from vars file - address_groups.yml
      provider: '{{ panos_provider }}'
      name: '{{ item.value.address_group_name }}'
      static_value: '{{ item.value.address_objects }}'
      commit: no
      tag: '{{ item.value.tag }}'
    with_dict: "{{ address_object_groups }}"


  - name: Commit pending Panorama changes for specified admin list
      provider: "{{ panos_provider }}"
      admins: "{{ admins }}"

As you will see here the new portion added is the “panos_address_object” module. This module will leverage the previously shown vars file and create the objects.

The following two modules that were discussed in the previous two posts will leverage the updates in their respective vars file and additionally add the respective tags to their objects.

Lets check out the results now with the addition of the tags being added.

So anyone who is familiar enough with Ansible, will understand why the recap says ok=6 and changed=4. However quickly for those who are not.

Last post I pointed out that Ansible has very helpful default position when pushing any changes, Ansible effectively will unless instructed otherwise not overwrite current configuration. This is why at the recap it says ok=6 and changed=4. If you look closely at the detailed log of what was changed, you will see only the key pairs that are new were deployed. Great stuff Ansible!

What this means in a production environment effectively is that we could use the same playbook again and it will just update all these objects and groups by adding the tag and not have them (address objects and address object groups) overwritten or replaced.

Lets check it out on the Palo to confirm everything is as Ansible is saying.

Huzzah, everything worked beautifully and was actually all very easy. Now I could easily scale all this and quickly deploy 100’s of address objects, group them and tag them. At that stage, I would probably stop using static address groups and probably move to dynamic address groups which give me some built in device automation and flexibility. But more on that later when I get to showing you guys how I do this at scale and then move onto CSV!

Hope you all have a great rest of your week and learn lots, God bless!

Leave a Reply

Skip to toolbar