Sunday, October 18, 2015

Using cURL to access the RESTful API of a Palo Alto Networks Firewall

There may be a situation where you would need to access the API of a Palo Alto Networks firewall. Some IT administrators may be more comfortable using cURL to access an API than a scripting language like PYTHON. Here's a few examples of how to perform some tasks using cURL.

The first thing you need to do is get an API key. How do you get an API Key? You query the firewall itself.

?type=keygen is the parameter to use.

curl -k "https://<firewall ip>/api/?type=keygen&user=<username>&password=<password>"


Make sure you wrap your url with Quotes. I tried this before and would get an error 400 response. 

You will get a response in xml. The value for key is the API key.

curl -k "https://192.168.1.1/api/?type=keygen&user=admin&password=admin"

<response status = 'success'>
<result>     
 <key>
   1234....
 </key>
 </result>
</response>


Then you can query the firewall using the API key instead of passing a username and password.

curl -k "https://<firewall ip>/api/?type=<api type>&<parameters>&key=<api-key>"

To get a list of api types and what commands to pass, you can use the REST API browser on the firewall. Just bring up a browser and authenticate against your firewall. After that you can add the path /api to the url.   https://<firewall ip>/api



Here you have the different api "types" you can query the firewall. Each of these types have some caveats as to the way you send your


For our first example, lets execute an operational command. From the cli the equivalent command would be "show system info".


If you drill down the Operational Commands to show system and info you will see the REST API URL at the bottom of the page. This is the url path you would copy to your curl command.










user@ubuntu-vm:~/API/curl$ curl -k "https://192.168.1.1/api/?

type=op&cmd=<show><system><info></info></system></show>&key=<API-KEY>"

<response status="success">
<result>
<system>
<hostname>NG-FW</hostname>
<ip-address>192.168.1.1</ip-address>
<netmask>255.255.255.0</netmask>
<default-gateway>192.168.1.254</default-gateway>
... TRUNCATED...

Notice that the command is in XML format. The firewall takes input and outputs in XML. 
This is important to note as you'll need to know the XPATH for most queries.

The following is to query the hostname with. You will need to add "action=get" as one of the parameters to read the hostname.


user@ubuntu-vm:~/API/curl$ curl -k "https://192.168.1.1/api/?type=config&action=get&xpath=/config/devices/entry\[@name='localhost.localdomain'\]/deviceconfig/system/hostname&key=<API-KEY>"
<response status="success" code="19"><result total-count="1" count="1">
  <hostname>NG-FW</hostname>

Notice that I had to put the literal '\[' for special characters like the square brackets. cURL would complain if I didn't have this.

curl: (3) [globbing] bad range specification in column 78


Now that we did a get. Let's try a set. When we do a set command, we need an extra parameter "element" that will contain the xml of the new content.

user@ubuntu-vm:~/API/curl$ curl -k "https://192.168.1.1/api/?type=config&action=set&xpath=/config/devices/entry\[@name='localhost.localdomain'\]/deviceconfig/system&element=<hostname>test</hostname>&key=<API-KEY>"
<response status="success" code="20"><msg>command succeeded</msg></response>

Doing a get command again shows us the hostname is changed.

user@ubuntu-vm:~/API/curl$curl -k "https://192.168.1.1/api/?type=config&action=get&xpath=/config/devices/entry\[@name='localhost.localdomain'\]/deviceconfig/system/hostname&key=<API-KEY>"
<response status="success" code="19"><result total-count="1" count="1">
  <hostname admin="admin" time="2015/10/14 11:08:11">test</hostname>

Next you need to commit the set command.

user@ubuntu-vm:~/API/curl$curl -k "https://192.168.1.1/api/?type=commit&cmd=<commit></commit>&key=<API-KEY>"
<response status="success" code="19"><result><msg><line>Commit job enqueued with jobid 699</line></msg><job>69

The response code will return a job id.

The last API type I'll cover are logs. Log retrieval is an asynchronous process so you need to query the particular log type first which will create a job id in the response and then query the FW again with the job id. Here’s an example using a threat log.

The first one is to generate the job id.
curl -k "https://<FW-IP>/api/?type=log&log-type=threat&key=<API-KEY>

The second will show you the results after the job task is finished.
curl -k "https://<FW-IP>/api/?type=log&action=get&jobid=<JOB-ID>&key=<API-KEY>

user@ubuntu-vm:~$ curl -k "https://192.168.1.1/api/?type=log&log-type=threat&key=<API-KEY>"
<response status="success" code="19"><result><msg><line>query job enqueued with jobid 3605</line></msg><job>3605</job></result></response>


user@ubuntu-vm:~$ curl -k "https://192.168.1.1/api/?type=log&action=get&jobid=3605&key=<API-KEY>"
<response status="success"><result>
  <job>
    <tenq>17:57:29</tenq>
    <tdeq>17:57:29</tdeq>
    <tlast>17:57:30</tlast>
    <status>FIN</status>
    <id>3605</id>
    <cached-logs>33</cached-logs>
  </job>
  <log>
   ... TRUNCATED ...
  </log>
  <meta>
    <devices>
      <entry name="localhost.localdomain">
        <hostname>localhost.localdomain</hostname>
        <vsys>
          <entry name="vsys1">
            <display-name>vsys1</display-name>
          </entry>
        </vsys>
      </entry>
    </devices>
  </meta>


No comments:

Post a Comment