Getting Started with 'IronSkillet' Best Practices Templates

Community Manager

The "IronSkillet, day one configuration templates" are an amazing new tool we've created to help customers deploy new firewalls with the least amount of effort while leveraging best practices. The goal is to make life easy for everyone and improve overall security posture.


The templates library contains easy to use snippets that allow for granular configuration add-ons or assembly of full config files that can be used to bootstrap or import onto a firewall or panorama. 



These are my own first steps for creating a fresh IronSkillet config:

Disclaimer: You may notice me using vi as a text editor, feel free to use nano or any other editor.




You can either do a quick ssl grab of the repository, or the lengthy way of fetching it through ssh

The short way: (thanks @cbernstein )

git clone


The long way:

Set up my keypair following the GitHub instructions (this had me baffled for a moment as I am a total GitHub noob).


MyPuter:~ reaper$ ssh-keygen -t rsa -b 4096 -C "" <- generate the keypair
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/reaper/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): <- password prompted here
Enter same passphrase again: 
Your identification has been saved in /Users/reaper/.ssh/id_rsa.
Your public key has been saved in /Users/reaper/.ssh/
The key fingerprint is:
The key's randomart image is:
+---[RSA 4096]----+
|        .       |
|       .o       |
|       .+.      |
|      ..+..     |
|     o..+..o    |
|  . o .* *. o . |
|    .. Bo ..    |
|    . .oX...    |
|  ..++o . o++.. |
MyPuter:~ reaper$ eval "$(ssh-agent -s)" <- start the ssh-agent in the background
Agent pid 39618
MyPuter:~ reaper$ vi ~/.ssh/config <- automatically add my keypair to the agent
MyPuter:~ reaper$ cat ~/.ssh/config
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa
MyPuter:~ reaper$ ssh-add -K ~/.ssh/id_rsa <- store passphrase in keychain Enter passphrase for /Users/reaper/.ssh/id_rsa: Identity added: /Users/reaper/.ssh/id_rsa (/Users/reaper/.ssh/id_rsa) MyPuter:~ reaper$ pbcopy < ~/.ssh/ <- this copies the public key to clipboard

 Once I managed to add the key to GitHub, I downloaded the snippets.

MyPuter:~ reaper$ git clone
Cloning into 'iron-skillet'...
remote: Enumerating objects: 208, done.
remote: Counting objects: 100% (208/208), done.
remote: Compressing objects: 100% (150/150), done.
remote: Total 1516 (delta 110), reused 141 (delta 57), pack-reused 1308
Receiving objects: 100% (1516/1516), 588.37 KiB | 1.32 MiB/s, done.
Resolving deltas: 100% (867/867), done.




Now I set up my python virtual environment.

MyPuter:~ reaper$ cd iron-skillet/tools/
MyPuter:tools reaper$ python3.7 -m venv env <- sets up the virtual environment
MyPuter:tools reaper$ source env/bin/activate <- activates the virtual environment
(env) MyPuter:tools reaper$ pip install -r requirements.txt <- installs some required packages
Collecting Jinja2==2.10 (from -r requirements.txt (line 1))
  Downloading (126kB)
    100% |████████████████████████████████| 133kB 2.6MB/s 
Collecting MarkupSafe==1.0 (from -r requirements.txt (line 2))
Collecting passlib==1.7.1 (from -r requirements.txt (line 3))
  Downloading (498kB)
    100% |████████████████████████████████| 501kB 3.3MB/s 
Installing collected packages: MarkupSafe, Jinja2, passlib
  Running install for MarkupSafe ... done
Successfully installed Jinja2-2.10 MarkupSafe-1.0 passlib-1.7.1


Next, I'll edit the to reflect values I want to use in my environment.

(env) MyPuter:tools reaper$ vi config_variables.yaml


# variables list to set values used in tools for local configs
    description: Panorama hostname
    value: panorama01
# Panorama mgmt inteface type and if static update the IP info
# DHCP is used for cloud deployments only
    description: Panorama management IP type - static or cloud (for dhcp)
    value: cloud
  - name: PANORAMA_IP
    description: Panorama IP
    value: <- Panorama management IP
    description: Panorama netmask
  - name: PANORAMA_DG
    description: Panorama default gateway
    value: <- panorama default gateway IP
    description: IP address for scheduled config exports
  - name: TEMPLATE
    description: Template name for Panorama
    value: sample_template
  - name: STACK
    description: Template stack name for Panorama
    value: sample_stack
  - name: DEVICE_GROUP
    description: Device-group name for Panorama
    value: sample_devicegroup
  - name: FW_NAME
    description: Device Name for NGFW
    value: sample
# Management interface type of dhcp or static
# If static be sure to set the IP attributes
  - name: MGMT_TYPE
    description: firewall management IP type (static or dhcp-client)
    value: dhcp-client
  - name: MGMT_IP
    description: NGFW management IP
    value: <- Firewall management IP
  - name: MGMT_MASK
    description: NGFW management netmask
  - name: MGMT_DG
    description: NGFW management default gateway
    value: <- Firewall default gateway IP
  - name: NTP_1
    description: Network Time Protocol Server
  - name: NTP_2
    description: Network Time Protocol Server 2
    description: admin username
    value: admin <- this is a default value, it is recommended to change this in the next step
    description: admin password
    value: admin <- this is a default value, it is recommended to change this in the next step
  - name: DNS_1
    description: primary dns server
  - name: DNS_2
    description: secondary dns server
  - name: SINKHOLE_IPV4
    description: sinkhole address IPv4
    value: <- this is the default Palo Alto Networks sinkhole IP
  - name: SINKHOLE_IPV6
    description: sinkhole address IPv6
    value: 2600:5200::1 <- this is the default Palo Alto Networks sinkhole IPv6
    description: untrust zone to filter out in reports
    value: internet
    description: email gateway address for critical alerts
    value: <- smtp server IP
    description: from address in email alerts
    description: to address in email alerts
    description: syslog server ip address
# option built into the templates to ignore the panw published external dynamic lists security rules
# should ONLY be excluded based on licensing limitations outside of best practices
    description: include the predefined Palo Alto Networks external lists
    value: 'yes'

 A description of all the variables is available in the Iron Skillet documentation.




And now, I can run the builder.

(env) MyPuter:tools reaper$ python3


                            Welcome to Iron-Skillet                             

datetime used for folder creation: 20190529_003029

Enter the name of the output directory: myconfig
Enter the superuser administrator account username: reaper   <- here you can choose your initial admin username
This username will be created instead of the default 'admin', so make sure to remember the password

a phash will be created for superuser reaper and added to the config file Enter the superuser administrator account password: Enter password again to verify: created new archive folder myconfig-20190529_003029 created new subdirectories for panos working with full config template ..creating template for iron_skillet_panos_full.xml ..saving template for iron_skillet_panos_full.xml ---cut for brevity--- configs have been created and can be found in /Users/reaper/iron-skillet/loadable_configs/myconfig-20190529_003029 along with the metadata values used to render the configs

I can now go find the full config file that was generated.

(env) MyPuter:tools reaper$ pwd
(env) MyPuter:tools reaper$ cd ..
(env) MyPuter:iron-skillet reaper$ ls	LICENSE	docs		loadable_configs	templates	tools
(env) MyPuter:iron-skillet reaper$ cd loadable_configs/
(env) MyPuter:loadable_configs reaper$ ls
reaper_config-20190529_003029	sample-cloud-Azure		sample-mgmt-dhcp
sample-cloud-AWS		sample-cloud-GCP		sample-mgmt-static
(env) MyPuter:my_configs reaper$ cd reaper_config-20190529_003029/
(env) MyPuter:reaper_config-20181002_165508 reaper$ ls
config_variables.yaml	panorama	panos
(env) MyPuter:reaper_config-20181002_165508 reaper$ cd panos/
(env) MyPuter:panos reaper$ ls
iron_skillet_panos_full.conf iron_skillet_panos_full.xml
(env) MyPuter:panos reaper$ cat iron_skillet_panos_full.xml
<config urldb="paloaltonetworks" version="8.0.0">   <mgt-config>     <users>       <entry name="reaper">         <phash>$1$oRM2HOOQ$K0M2ovg2.qU/sAuRd9g2H1</phash>         <permissions>           <role-based>             <superuser>yes</superuser>           </role-based>         </permissions>       </entry>     </users>   </mgt-config>




Import it into my firewall (I'd go to Device > Setup > Operations > Import named configuration snapshot).

snapshot of import config


Next, I load the config into the firewall by clicking "Load Named Configuration Snapshot."

snapshot of load configLoad Named Configuration Snapshot

After reloading the page, browsing through sections of the firewall, several things have been automatically prepared in accordance with my '' file and best practices. 


Snapshot of Iron Skillet security policy


Several security profiles have been prepared in each section.

Snapshots of Profiles in each section


Also, Inbound, Outbound, Internal, Alert-Only and default Security Profile Groups have been prepared.

Snapshot of security profile group

Note: A cool little trick here is the use of 'default' as a Security Profile Group. This ensures that any new security rule that's created will automatically be loaded with a set of Security Profiles.



So what's next?

If I commit this configuration, the management port will assume the IP I configured in, but there are no interfaces, zones or security policies configured yet. Here's a little checklist to get you rolling:


- Create zones (don't forget to add zone protection)

- Configure virtual router (for default gateway)

- Configure interfaces

- Create additional security policies (review the Best Practices for recommendations on identifying whitelist applications)

- Create NAT rules if needed


Check out the Iron Skillet page for instructions on how to add partial config, additional information on individual snippets and keep an eye out for updates and new snippets.



Additional Information 

IronSkillet templates documentation

IronSkillet GitHub repository

Best practices recommendations 

L0 Member

You can skip all of the SSH configuration steps and just grab the repository via HTTPS:


git clone


It is publicly available and does not require a GitHub account to download.

Community Manager

@cbernstein  I've updated the blog, thanks for the protip!

L0 Member

Been trying to follow the instructions, but I'm getting stuck at Step 3.


(env) root@Expedition:~/iron-skillet/tools#
(env) root@Expedition:~/iron-skillet/tools# python3.7
python3.7: can't open file '': [Errno 2] No such file or directory
(env) root@Expedition:~/iron-skillet/tools#
Community Manager

hi @SilkyZ 


the procedure has changed a little, i've updated the article to reflect the latest state

Ask Questions Get Answers Join the Live Community