Custom Jinja Filters

Custom filters are used to simplify validation skillets by using a small set of filter options to check the most common configuration components contained in tags, attributes, and element text values.

Review the XML Basics documentation for the XML terminology used in the custom filters.

Additional examples can be found in the skilletlib examples directory

Capturing XML Objects

In order to properly validate a config it is often necessary to convert the XML structure to an object, which can then be used in a Jinja expression to perform basic logic and validation. The captured object is associated to an XPath plus its corresponding XML element and assigned a variable name used in the custom filter.

Each custom filter example below shows its respective captured object for use in the filter.

When building skillets, the Builder needs to:

  • know the XPath for each object to capture

  • determine what part of the XML element will be referenced: attribute, tag, element text value

  • which custom filter to select based on the XML element reference

  • what conditions have to be met: a specific or range of values, item present or absent, etc.

Checking Attributes

Attribute filters are most commonly used to check object names although other attributes can exist within the XML configuration.

attribute_present(tag name, attribute name, attribute value)
attribute_absent(tag name, attribute name, attribute value)

The attribute being checked in this example is the external-list entry name. Therefore the input values for the attribute filters are:

  • tag name: <entry>

  • attribute name: ‘name’

  • the attribute value of interest

A sample XML element found at XPath /config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/external-list is used as reference for the attribute custom filters examples. The element will be a captured object variable called external-list.

<external-list>
  <entry name="tutorial_edl">
    <type>
      <ip>
        <recurring>
          <five-minute/>
        </recurring>
        <description/>
        <url>http://tutorial.com</url>
      </ip>
    </type>
  </entry>
  <entry name="my_edl">
    <type>
      <ip>
        <recurring>
          <five-minute/>
        </recurring>
        <description/>
        <url>http://my_url.com</url>
      </ip>
    </type>
  </entry>
</external-list>

attribute_present

Checks if an attribute value exists and returns True if the attribute value is found. This filter is used to ensure a named object or policy exists in the configuration. This item should be present as part of a best practice validation or other config skillets may have dependencies on this item.

external-list | attribute_present('entry', 'name', 'my_edl')
external-list | attribute_absent('entry', 'name', 'new_edl')

The first filter will return True since my_edl is in the external-list object. The second filter will return False since new_edl is not in the external-list object.

attribute_absent

Checks if an attribute value exists and returns True if the attribute value is not found. This filter is used to ensure a named object or policy does not already exist in the configuration. If the item exists it may cause config merge conflicts or override an existing configuration.

external-list | attribute_absent('entry', 'name', 'my_edl')
external-list | attribute_absent('entry', 'name', 'new_edl')

The first filter will return False since my_edl is in the external-list object. The second filter will return True since new_edl is not in the external-list object.

Checking an Element Value

Element value filters are most commonly used to check specific text values in the XML configuration.

element_value('tag name') [expression] value

Any valid jinja expression can be used to evaluate the text value.

A sample XML element found at XPath /config/devices/entry[@name='localhost.localdomain']/deviceconfig/system will be used as reference for the element value custom filter example. The element will be a captured object variable called device_system.

<update-schedule>
  <anti-virus>
    <recurring>
      <hourly>
        <at>4</at>
        <action>download-and-install</action>
      </hourly>
    </recurring>
  </anti-virus>
  <wildfire>
    <recurring>
      <every-min>
        <action>download-and-install</action>
      </every-min>
    </recurring>
  </wildfire>
</update-schedule>
<snmp-setting>
  <access-setting>
    <version>
      <v3/>
    </version>
  </access-setting>
</snmp-setting>
<ntp-servers>
  <primary-ntp-server>
    <ntp-server-address>0.pool.ntp.org</ntp-server-address>
  </primary-ntp-server>
  <secondary-ntp-server>
    <ntp-server-address>1.pool.ntp.org</ntp-server-address>
  </secondary-ntp-server>
</ntp-servers>
<login-banner>You have accessed a protected system.
    Log off immediately if you are not an authorized user.
</login-banner>
<timezone>EST</timezone>

element_value

Checks an element_value expression and returns True if the expression is true. This filter is used to check a specific value or range based on best practices or expected configuration settings. Various checks such as ‘==’, ‘!=’, ‘>=’, and ‘<=’ can be used in the filter.

device_system | element_value('update-schedule.wildfire.recurring.every-min.action') == 'download-and-install'
device_system | element_value('timezone') == 'UTC'

The first filter uses the dot notation to step down the tree to the wildfire dynamic update action. This allows a single captured object to be used for multiple tests instead of an explicit capture object for each test using a granular XPath. The filter will return True since the action for Wildfire updates is set to ‘download-and-install’.

The second filter will return False since the XML configuration for timezone is ‘EST’ and not ‘UTC’.

Checking Tags

The tag filters are most commonly used to check specific tags that are used in the data structure as configuration values.

tag_present('tag name')
tag_absent('tag name')

The example below references the same device_system captured object used in the element_value example.

tag_present

Checks for a tag name and returns True if the tag is found. This filter is used to check for a specific tag in cases where configuration values are tags instead of text values. In the device_system example the recurring interval for Wildfire updates is a tag shown as <every-min>

device_system | tag_present('update-schedule.wildfire.recurring.every-min')
device_system | tag_present('update-schedule.wildfire.recurring.every-hour')

The filters use the dot notation to step down the tree to the wildfire recurring interval. This allows a single captured object to be used for multiple tests instead of an explicit capture object for each test using a granular XPath.

The first filter will return True since the Wildfire update interval is set to ‘every-min’. The second filter will return False since every-hour is not found.

Other examples using tag_present from the same device_system capture object:

device_system | tag_present('snmp-setting.access-setting.version.v3') --> check if SNMP v3 configured
device_system | tag_present('ntp-servers.primary-ntp-server') --> check if an NTP server is configured

tag_absent

Checks for a tag name and returns False if the tag is found. This filter is used to check for tag-based configuration components that should NOT exist in the configuration. In the device_system example the recurring interval for Wildfire updates is a tag shown as <every-min>

device_system | tag_absent('update-schedule.wildfire.recurring.every-min')
device_system | tag_absent('update-schedule.wildfire.recurring.every-hour')

The filters use the dot notation to step down the tree to the wildfire recurring interval. This allows a single captured object to be used for multiple tests instead of an explicit capture object for each test using a granular XPath.

The first filter will return False since the Wildfire update interval is set to ‘every-min’. The second filter will return True since every-hour is not found.

Checking a Set of Element Values

In some cases multiple values are contained with a portion of the configuration. These are often referenced in the configuration file with <member> tags. Examples of multiple entries include:

  • zones, addresses, users, or tags assigned to a security policy

  • URL categories assigned to block or alert actions

  • interfaces assigned to a zone or virtual-router

To check multiple element values, the element_value_contents custom filter can search across all members to find a specific value.

element_value_contains

The inputs to the filter are the tag name and the search value.

element_value_contains('tag name', 'search value')

This example checks a security rule to see if a specific destination address using an external-list is found. The XPath for the Outbound Block Rule is /config/devices/entry[@name=’localhost.localdomain’]/vsys/entry[@name=’vsys1’]/rulebase/security/rules/entry[@name=’Outbound Block Rule’]

Below is an abbreviated XML element showing the <destination> content of interest.

<entry name="Outbound Block Rule">
  <to>
    <member>any</member>
  </to>
  <from>
    <member>any</member>
  </from>
  <destination>
    <member>panw-highrisk-ip-list</member>
    <member>panw-known-ip-list</member>
    <member>panw-bulletproof-ip-list</member>
  </destination>
  <action>deny</action>
  <log-setting>default</log-setting>
  <tag>
    <member>Outbound</member>
  </tag>
</entry>

The custom filter looks for the inclusion of the panw-bulletproof-ip-list EDL as a destination address.

security_rule_outbound_edl | element_value_contains('destination.member', 'panw-bulletproof-ip-list')

Since the member value is found a True result is returned.

Referencing the same example, other element_value_contains checks could be used for <to> or <from> zones and <tag> members.