├── README.md
├── pan-qb.py
├── srrm-monitor-public.py
├── url-check.py
├── pan-rcli.py
└── pan-rcli-nopass.py
/README.md:
--------------------------------------------------------------------------------
1 | # Palo Alto Networks Toolbox
2 |
3 | This will be a repository of scripts written to handle some checks and other things on
4 | on the Palo Alto Networks firewalls.
5 |
6 | ## url-check.py
7 | This script will query the PANDB cloud with data from a flat text file and return the
8 | categories in a CSV. This is a CLI executed script that utilizes argparse, requests,
9 | and the lxml library.
10 |
11 | ## pan-rcli.py
12 | This script will allow you to execute commands on a remote Palo Alto Networks firewall
13 | and then read back the responses. You can feed it either a single command or a text
14 | file of commands. It should be noted that the commands are executed as is, there is no
15 | logic in place to check the validity of the commands.
16 |
17 | ## pan-qb.py
18 | This script will perform a quick backup of a firewall where there is a known API key to
19 | make life easier. If anyone wants to update it to auto-gen an API key from a fed username
20 | and password.
21 |
22 | ## srrm-monitor-public.py
23 | This script will hit the API to pull stats around the "show running resource-monitor" command
24 | and pull data from the DP's of firewalls.
25 |
--------------------------------------------------------------------------------
/pan-qb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import requests
4 | import argparse
5 | requests.packages.urllib3.disable_warnings()
6 |
7 |
8 | '''
9 | This is a quick script to grab a backup a firewall with a known API key. Next iteration will pull a username and
10 | password as needed to gen the API key on it's own for use. This was a quick script though used out of a private
11 | server with cron to pull these.
12 |
13 | - Tighe Schlottog tschlottog@paloaltonetworks.com
14 | '''
15 |
16 |
17 | def parse_args():
18 | parser = argparse.ArgumentParser(description='Quick Backup of onboard firewall configuration')
19 | parser.add_argument('-fw', type=str, help='IP Address of Firewall')
20 | parser.add_argument('-k', '--api_key', type=str, help='API Key with access to Firewall')
21 | parser.add_argument('-out', type=str, help='Output file where the configuration should be written')
22 | parser.add_argument('-fwlist', type=str, help='CSV file of firewalls to backup')
23 | args = parser.parse_args()
24 | return parser, args
25 |
26 |
27 | def pull_backup(fw, api_key, outfile):
28 | config_out = open(outfile, 'w')
29 | backup_headers = {'type': 'export', 'key': api_key, 'category': 'configuration'}
30 | backup_req = requests.get('https://%s/api' % fw, params=backup_headers, verify=False)
31 | config_out.write(backup_req.content)
32 | config_out.close()
33 |
34 |
35 | def pull_firewalllist(fwlist):
36 | with open(fwlist, 'r') as fwdata:
37 | for line in fwdata:
38 | (fw, apikey) = line.split(',')
39 | pull_backup(fw, apikey, '%s.cfg' % fw.replace('.', '_'))
40 |
41 |
42 | def control():
43 | backup_parser, backup_args = parse_args()
44 | if backup_args.fw and backup_args.api_key and backup_args.out:
45 | pull_backup(backup_args.fw, backup_args.api_key, backup_args.out)
46 | elif backup_args.fwlist:
47 | pull_firewalllist(backup_args.fwlist)
48 | else:
49 | backup_parser.print_help()
50 |
51 |
52 | if __name__ == '__main__':
53 | control()
--------------------------------------------------------------------------------
/srrm-monitor-public.py:
--------------------------------------------------------------------------------
1 | import lxml.etree as etree
2 | import requests
3 | import datetime
4 |
5 | requests.packages.urllib3.disable_warnings()
6 |
7 | __author__ = 'Tighe Schlottog || tschlottog@paloaltonetworks.com'
8 | __description__ = 'Pull the stats from the show running resource-monitor on the firewall in a structured manner'
9 | __version__ = '1.0'
10 |
11 | # These are the configurable variables
12 | MAX_CPU = 3 # Max CPU percent, this is your mark to start throwing errors
13 | time_window = 15 # Numeric value of length time slices wanted for the measurement
14 | time_measure = 'minute' # This is either second, minute, hour, day, week
15 | fw_host = '' # This is the Management (or in-path Management) IP of the firewall
16 | CSV_OUT = True # This is used to define whether or not to dump the data out to a csv formated document
17 | csv_file = 'srrm-stats.csv'
18 | api_key = '' # This is the API Key used to access the firewall
19 |
20 |
21 | # Nothing past here needs to be configured
22 | srrm_params = {'type': 'op', 'cmd': '<%s>%d%s>' % (time_measure, time_window, time_measure), 'key': api_key}
23 | srrm = requests.get('https://%s/api' % fw_host, params=srrm_params, verify=False)
24 | print srrm.content
25 | srrm_stats = {}
26 | time_now = datetime.datetime.now().strftime('%Y/%m/%d@%H:%M:%S')
27 |
28 | if srrm.status_code == 200:
29 | root = etree.fromstring(srrm.content)
30 | dp_xpath = root.xpath('.//data-processors')
31 | dp_list = []
32 | for dps in dp_xpath:
33 | for dp in dps:
34 | dp_list.append(dp.tag)
35 |
36 | for dp in dp_list:
37 | if dp not in srrm_stats:
38 | srrm_stats[dp] = {}
39 | srrm_stats[dp]['cpu_avgs'] = {}
40 | srrm_stats[dp]['cpu_maxs'] = {}
41 | cpu_avgs = root.xpath('.//data-processors/%s/%s/cpu-load-average/entry' % (dp, time_measure))
42 | for entry in cpu_avgs:
43 | for item in entry:
44 | if item.tag == 'coreid':
45 | core_id = item.text
46 | if item.tag == 'value':
47 | core_data = item.text
48 | srrm_stats[dp]['cpu_avgs'][core_id] = core_data
49 | cpu_maxs = root.xpath('.//data-processors/%s/%s/cpu-load-maximum/entry' % (dp, time_measure))
50 | for entry in cpu_maxs:
51 | for item in entry:
52 | if item.tag == 'coreid':
53 | core_id = item.text
54 | if item.tag == 'value':
55 | core_data = item.text
56 | srrm_stats[dp]['cpu_maxs'][core_id] = core_data
57 |
58 | if CSV_OUT:
59 | csv_out = open(csv_file, 'a')
60 |
61 | for DP in srrm_stats:
62 | for type in srrm_stats[DP]:
63 | for core in srrm_stats[DP][type]:
64 | cpu_data = [int(x) for x in srrm_stats[DP][type][core].split(',')]
65 | for idx, val in enumerate(cpu_data):
66 | if CSV_OUT:
67 | csv_out.write('%s,%s %s,%s,%s,%s,%s\n' % (time_now, time_window, time_measure, type, DP, core, srrm_stats[DP][type][core]))
68 | if val > MAX_CPU:
69 | print '%s | %s | Core %s | %d CPU Utilization | %d minutes ago' % (DP, type, core, val, idx)
70 |
--------------------------------------------------------------------------------
/url-check.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import requests
4 | import lxml.etree
5 | import argparse
6 | import sys
7 | requests.packages.urllib3.disable_warnings()
8 |
9 | '''
10 | url-check.py - 2017 Tighe Schlottog
11 |
12 | This script will pull in data from a text file and then utilize it querying the URL Cloud w/PANDB.
13 | '''
14 |
15 |
16 | def parse_args():
17 | parser = argparse.ArgumentParser(description='Query URL Cloud to determine the category of URLs.')
18 | parser.add_argument('-fw', type=str, help='IP Address of Firewall for querying', required=True)
19 | parser.add_argument('-k', '--api_key', type=str, help='API Key with access to Firewall', required=True)
20 | parser.add_argument('-ui', '--urls_in', type=str, help='Input file containing a list of URLS for querying', required=True)
21 | parser.add_argument('-uo', '--urls_out', type=str, help='Output file where the URL and category are written in CSV', required=True)
22 | parser.add_argument('-d', '--debug', type=bool, default=False, help='Enable Debugging for additional Outputs')
23 | parser.add_argument('-c', '--cname', type=bool, default=False, help='Enable CNAME/Recursion on domain')
24 | args = parser.parse_args()
25 | return parser, args
26 |
27 |
28 | def url_query(fw, api_key, urls_in, urls_out, debug, cname):
29 | resp_out = open(urls_out, 'a')
30 | with open(urls_in, 'r') as urls_file:
31 | for url in urls_file:
32 | if url.strip() != '':
33 | test_headers = {'type': 'op', 'key': api_key, 'cmd': '' + requests.utils.requote_uri(str(url.strip())) + ''}
34 | if debug:
35 | print '***Request to API***'
36 | print 'URL: https://%s/api' % fw
37 | print 'Parameters:'
38 | print test_headers
39 | print '***End API Request\n\n'
40 | url_req = requests.get('https://%s/api' % fw, params=test_headers, verify=False)
41 | if debug:
42 | print '***Response from API***'
43 | print url_req.content
44 | print '***End API Response\n\n'
45 | if url_req.status_code is requests.codes.ok:
46 | resp_root = lxml.etree.fromstring(url_req.content)
47 | if resp_root.xpath('//result') is not None:
48 | for x in resp_root.xpath('//result')[0].text.split():
49 | if not x.startswith('BM:'):
50 | if cname:
51 | if debug:
52 | print '***Data in //result xpath: %s' % x
53 | if ',' in x:
54 | y = x.split(',')
55 | print y[0], y[-1]
56 | resp_out.write('%s,%s\n' % (y[0], y[-1]))
57 | else:
58 | if debug:
59 | print '***Data in //result xpath: %s' % x
60 | if ',' in x:
61 | y = x.split(',')
62 | print url, y[-1]
63 | resp_out.write('%s,%s\n' % (url.strip(), y[-1]))
64 | break
65 | else:
66 | print 'Caught an error '
67 | else:
68 | sys.exit('API Connection to %s returned %s' % (fw, url_req.status_code))
69 |
70 |
71 | def control():
72 | url_parser, url_args = parse_args()
73 | url_query(url_args.fw, url_args.api_key, url_args.urls_in, url_args.urls_out, url_args.debug, url_args.cname)
74 |
75 |
76 | if __name__ == '__main__':
77 | control()
78 |
--------------------------------------------------------------------------------
/pan-rcli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import paramiko
3 | import sys
4 | from datetime import datetime
5 | import argparse
6 |
7 | __author__ = 'Tighe Schlottog || workapegmailcom'
8 |
9 |
10 | def parse_args():
11 | '''
12 | This function will parse the command line arguments passed in via ARGV.
13 | :return:
14 | '''
15 | parser = argparse.ArgumentParser(description='Script to remotely execute CLI commands on Palo Alto Networks firewalls')
16 | parser.add_argument('-fw', '--firewall', type=str, help='IP address of remote Firewall')
17 | parser.add_argument('-u', '--user', type=str, help='Remote Firewall Username')
18 | parser.add_argument('-cmd', type=str, help='Remote Command to be run surrounded by double quotes. For example "show system info".')
19 | parser.add_argument('-cf', '--command_file', type=str, help='Read commands to be executed remotely from a defined file')
20 | parser.add_argument('-stdout', dest='stdout', action='store_true', help='Output command data to STDOUT')
21 | parser.set_defaults(stdout=False)
22 | parser.add_argument('-f', '--file', type=str, help='Output command data to named file')
23 | fw_password = raw_input('Enter Remote Firewall Password: ')
24 | args = parser.parse_args()
25 | return parser, args, fw_password
26 |
27 |
28 | def parse_command_file(command_file):
29 | '''
30 | This function will parse the lines of the command file, excluding the comment lines starting with #, based on the
31 | newline character and return a list for use in other functions.
32 | :param command_file: This is the name/location of the command file pulled in from the CLI.
33 | :return: Returns a dict of the non-comment command lines from the file.
34 | '''
35 | commands = []
36 | with open(command_file, 'r') as cf:
37 | for line in cf.read().split('\n'):
38 | if not line.startswith('#'):
39 | commands.append(line)
40 | return commands
41 |
42 |
43 | def setup_conn(fw_ip, username, password):
44 | '''
45 | This function will set up the SSH connection via Paramiko's SSH Client.
46 | :param fw_ip: IP address of the firewall that is being connected too.
47 | :param username: Username used to log into the firewall.
48 | :param password: Password used to log into the firewall.
49 | :return: Returns the connection handler for use in other functions.
50 | '''
51 | print fw_ip, username, password
52 | test_conn = paramiko.SSHClient()
53 | test_conn.load_system_host_keys()
54 | test_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
55 | try:
56 | print 'Connecting to firewall'
57 | test_conn.connect(fw_ip, username=username, password=password)
58 | except:
59 | print 'Unable to connect to firewall, please check your settings'
60 | sys.exit(1)
61 |
62 | return test_conn # Paramiko SSH Handler
63 |
64 |
65 | def execute_remote_command(ssh_con, cmd):
66 | '''
67 | This function will invoke a Paramiko shell and execute commands in a remote manner.
68 | :param ssh_con: This is the Paramiko SSH connection handler which is handed into the system.
69 | :param cmd: This is the command which will be executed in the Paramiko SSH Shell
70 | :return: It will return a string of the data that is pulled back from the results of the command.
71 | '''
72 | ssh_shell = ssh_con.invoke_shell()
73 | while not ssh_shell.recv_ready():
74 | pass
75 | ssh_shell.send('set cli pager off\n')
76 | while not ssh_shell.recv_ready():
77 | pass
78 | if cmd[-1] != '\n':
79 | cmd += '\n'
80 | ssh_shell.send(cmd)
81 | prompt_search = ''
82 | results_data = ''
83 | while prompt_search != '>':
84 | results_data += ssh_shell.recv(4096).replace('\r', '')
85 | prompt_search = results_data.strip()[-1]
86 | return results_data
87 |
88 |
89 | def main():
90 | cmd_parser, cmd_args, fw_pass = parse_args()
91 |
92 | if cmd_args.file:
93 | cmd_out = open(cmd_args.file, 'a+')
94 | cmd_out.write('---------> %s <---------\n' % datetime.now().strftime('%Y/%m/%d@%H:%M:%S'))
95 | if cmd_args.command_file:
96 | cmds = parse_command_file(cmd_args.command_file)
97 | else:
98 | cmds = [ cmd_args.cmd ]
99 |
100 | cmd_handler = setup_conn(cmd_args.firewall, cmd_args.user, fw_pass)
101 |
102 | for fw_cmd in cmds:
103 | cmd_data = execute_remote_command(cmd_handler, fw_cmd)
104 | if cmd_args.file:
105 | cmd_out.write(cmd_data)
106 | if cmd_args.stdout:
107 | print cmd_data
108 |
109 |
110 | if __name__ == '__main__':
111 | main()
112 |
113 |
--------------------------------------------------------------------------------
/pan-rcli-nopass.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import paramiko
3 | import sys
4 | from datetime import datetime
5 | import argparse
6 |
7 | __author__ = 'Tighe Schlottog || workapegmailcom'
8 |
9 | def parse_args():
10 | '''
11 | This function will parse the command line arguments passed in via ARGV.
12 | :return:
13 | '''
14 | parser = argparse.ArgumentParser(description='Script to remotely execute CLI commands on Palo Alto Networks firewalls')
15 | parser.add_argument('-fw', '--firewall', type=str, help='IP address of remote Firewall')
16 | parser.add_argument('-u', '--user', type=str, help='Remote Firewall Username')
17 | parser.add_argument('-p', '--password', type=str, help='Remote Firewall Password')
18 | parser.add_argument('-cmd', type=str, help='Remote Command to be run surrounded by double quotes. For example "show system info".')
19 | parser.add_argument('-cf', '--command_file', type=str, help='Read commands to be executed remotely from a defined file')
20 | parser.add_argument('-stdout', dest='stdout', action='store_true', help='Output command data to STDOUT')
21 | parser.add_argument('-debug', dest='debug', action='store_true', help='Enable additional debugging')
22 | parser.set_defaults(stdout=False, debug=False)
23 | parser.add_argument('-f', '--file', type=str, help='Output command data to named file')
24 | args = parser.parse_args()
25 |
26 | return parser, args
27 |
28 |
29 | def parse_command_file(command_file):
30 | '''
31 | This function will parse the lines of the command file, excluding the comment lines starting with #, based on the
32 | newline character and return a list for use in other functions.
33 | :param command_file: This is the name/location of the command file pulled in from the CLI.
34 | :return: Returns a dict of the non-comment command lines from the file.
35 | '''
36 | commands = []
37 | with open(command_file, 'r') as cf:
38 | for line in cf.read().split('\n'):
39 | if not line.startswith('#'):
40 | commands.append(line)
41 | return commands
42 |
43 |
44 | def setup_conn(fw_ip, username, password):
45 | '''
46 | This function will set up the SSH connection via Paramiko's SSH Client.
47 | :param fw_ip: IP address of the firewall that is being connected too.
48 | :param username: Username used to log into the firewall.
49 | :param password: Password used to log into the firewall.
50 | :return: Returns the connection handler for use in other functions.
51 | '''
52 | print fw_ip, username, password
53 | test_conn = paramiko.SSHClient()
54 | test_conn.load_system_host_keys()
55 | test_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
56 | try:
57 | print 'Connecting to firewall'
58 | test_conn.connect(fw_ip, username=username, password=password)
59 | except:
60 | print 'Unable to connect to firewall, please check your settings'
61 | sys.exit(1)
62 |
63 | return test_conn # Paramiko SSH Handler
64 |
65 |
66 | def execute_remote_command(ssh_con, cmds, cmd_args):
67 | '''
68 | This function will invoke a Paramiko shell and execute commands in a remote manner.
69 |
70 | It will search for two ending prompt conditions the '>' which is the standard prompt and the ':'
71 | which is the prompt used for passwords.
72 |
73 | :param ssh_con: This is the Paramiko SSH connection handler which is handed into the system.
74 | :param cmd: This is the command which will be executed in the Paramiko SSH Shell
75 | :param cmd_args: These are the CLI arguments to cehck for debugging, file destination, etc.
76 | :return: It will return a string of the data that is pulled back from the results of the command.
77 | '''
78 | if cmd_args.file:
79 | cmd_out = open(cmd_args.file, 'a+')
80 | ssh_shell = ssh_con.invoke_shell()
81 | while not ssh_shell.recv_ready():
82 | pass
83 | ssh_shell.send('set cli pager off\n')
84 | while not ssh_shell.recv_ready():
85 | pass
86 | for cmd in cmds:
87 | if len(cmd) > 0:
88 | if cmd[-1] != '\n':
89 | cmd += '\n'
90 | if cmd_args.debug:
91 | print 'Sending "%s" to remote firewall' % cmd
92 | ssh_shell.send(cmd)
93 | prompt_search = ''
94 | results_data = ''
95 | while prompt_search not in ['>', ':']:
96 | results_data += ssh_shell.recv(4096).replace('\r', '')
97 | prompt_search = results_data.strip()[-1]
98 | if cmd_args.file:
99 | cmd_out.write(results_data)
100 | if cmd_args.stdout:
101 | print results_data
102 | if cmd_args.debug:
103 | print 'All commands executed'
104 |
105 | def main():
106 | cmd_parser, cmd_args = parse_args()
107 |
108 | if cmd_args.file:
109 | cmd_out = open(cmd_args.file, 'a+')
110 | cmd_out.write('---------> %s <---------\n' % datetime.now().strftime('%Y/%m/%d@%H:%M:%S'))
111 | cmd_out.close()
112 | if cmd_args.command_file:
113 | cmds = parse_command_file(cmd_args.command_file)
114 | else:
115 | cmds = [ cmd_args.cmd ]
116 | if cmd_args.debug:
117 | print 'Setting up SSH connection'
118 | cmd_handler = setup_conn(cmd_args.firewall, cmd_args.user, cmd_args.password)
119 | if cmd_args.debug:
120 | print 'Successfully set up SSH connection and received connection handler back'
121 |
122 | execute_report_command(cmd_handler, cmds, cmd_args)
123 |
124 |
125 | if __name__ == '__main__':
126 | main()
127 |
128 |
--------------------------------------------------------------------------------