In an earlier post, I showed how to retrieve credentials from AWS Secrets Manager using Ansible. This can be a useful way to get around storing sensitive credentials within your code repositories.
This post will show how to achieve the same thing using Python.
Similar to the previous post, I’ll use the retrieved credentials to log on to a Palo Alto Networks firewall and create a new test object.
In this exercise, I’ll use 3 Python libraries as follows:
- boto3: This is a python library used for interacting with AWS infrastructure services
- json: This is useful for parsing JSON data
- requests: This is a popular python library used for making HTTP requests. I use this for interacting with the Palo Alto Networks API
I started off by creating my Secret entry in AWS Secrets manager called python_user_login
.
After that, I created an admin role profile on the Palo Alto Networks firewall. The role will have permissions to access the REST API as shown below
I then assigned this role to the admin user whose credentials i’ll retrieve from Secrets manager.
When I used Ansible, I didn’t have to use an API key. The paloaltonetworks.panos ansible collection gives me an option to specify the username and password directly as part of my ‘provider‘ config. In this case though, I’ll need to use the API key to authenticate my API calls to the firewall.
Generating the API key for the Palo Alto Networks firewall is straightforward. Just run the following command:
https://<firewall_ip_address>/api/?type=keygen&user=<username>&password=<password>
Replace <firewall_ip_address>, <username> and <password> with your own details
Now that I have my username, password and API key stored in Secrets Manager, I can move on to my python code.
import boto3
import json
import requests
## Call the boto3.client() function to retrieve my secret from AWS Secrets manager
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId='python_user_login')
## Parse the JSON data received from Secrets Manager and convert to a Python dictionary
secret_dict = json.loads(response["SecretString"])
## Retrieve API key from Secrets manager entry
firewall_api_key = secret_dict["api_key"]
## Define query parameters required for the API call
query_params = {
"name" :"test_python_object",
"location" : "vsys",
"vsys": "vsys1"
}
## Define firewall URL
url = "https://<firewall_ip>/restapi/v10.1/Objects/Addresses"
## Define header information that will be passed with the HTTP request
headers_field = {
"X-PAN-KEY": firewall_api_key
}
## Define address object details for the new object to be created
new_address_details = {
"entry": {
"@name": "test_python_object",
"ip-netmask": "10.55.0.0/24",
"description": "Test object from python"
}
}
## HTTP Post request
create_object = requests.post(url=url, json=new_address_details, headers=headers_field, params=query_params, verify=False)
print(create_object.json)
print(create_object.json())
To understand more about the query parameters, header information and other information that is passed as part of the HTTP request to the Palo Alto Networks firewall via the REST API, check the Palo Alto Networks documentation here.
After running my Python script, I get confirmation that the new object was successfully created with the below messages:
<Response [200]>
{'@status': 'success', '@code': '20', 'msg': 'command succeeded'}
The firewall also shows the newly created object
Note: There is a separate Palo Alto Networks SDK for Python called ‘pan-python‘ which can also be used for interacting with the API. In this example, I just chose to use the generic ‘requests’ library.