Bulk Change to apply SPG Workflow
Choose language for code snippet
Python Php GoIn this section we present a workflow example to for bulk change on appling Security Profile group to all allowed security rules in a PAN-OS configuraiton.
Below flowhart demo the workflow and the related API calls in each of the steps:
#
Step 1. Obtain the API KeysRefer to Obtaining the API Keys section to obtain a valid API key stored in the hed
variable.
#
Step 2. Start the Expedition AgentRefer to Managing Expedition's Agent section to start the agent and be able to perform imports into a project.
#
Step 3. Add PAN-OS DeviceMaking a POST call to the Device route, we can create a Devive with a desired name.
Notice that we attach the credentials hed
in the CURL headers to present our credentials and verify we have permission to create a device.
API syntax for creating a new device :
Method | Route | Request Body Parameters |
---|---|---|
POST | https://localhost/api/v1/device | {"name": devicename, "serial": serialnumber,"hostname": panosip,"type": devicetype,"description": pandescription, } |
Example | https://localhost/api/v1/device | {"name":"mypanorama", "serial":"123456789","hostname":"pan1","type":"vm-panorama""description":"Project for testing"} |
info
The supported device "type" are below:
"m100", "m500", "m600", "vm-panorama", "pa200", "pa220", "pa500", "pa800", "pa3000", "pa3200", "pa4000", "pa5000", "pa5200", "pa7000", "vm-series"
- Python
- Php
- Go
print("*****Add a new PAN-OS device\n")panosip = '1.1.1.1'serialnumber = '123412'devicetype = "pa220"pandescription = 'test'url = "https://" + ip + "/api/v1/device"data = { "name": devicename, "serial": serialnumber, "hostname": panosip, "type": devicetype, "description": pandescription,}r = requests.post(url, data=data, verify=False, headers=hed)response = r.json()success = json.dumps(response["success"])if success == "true": print("New device created successfully" + " \n") DeviceId = json.dumps(response['data']['id']) print("Your Device-ID is " + str(DeviceId) + " \n")else: print("Unable to create the device")print("*****Upload PAN-OS config into device*****\n")
#
Step 4. Upload PAN-OS config into deviceAfter devcie has been created , the next step will be uploading your pan-os config to associate with the device.
API syntax for upload PAN-OS config into device :
Method | Route | Path Parameters |
---|---|---|
POST | "https://localhost/api/v1/device/{device_id}/upload_config" | "device_id": "device_id" |
Example | "https://localhost/api/v1/device/23/upload_config" | 23 |
- Python
- Php
- Go
print("*****Upload PAN-OS config into device*****\n")file = '/Users/user1/Downloads/panoramabase.xml'panosconfig = open(file, "rb")files = {"config": panosconfig}url = 'https://' + ip + '/api/v1/device/{0}/upload_config'.format(int(DeviceId))r = requests.post(url, files=files, verify=False, headers=hed)response = r.json()success = json.dumps(response["success"])if success == "true": print("Pan-OS config uploaded to the device successfully\n")else: result = json.dumps(response["messages"][0]["message"]) print(result)
#
Step 5. Create an Expedition ProjectIn the large amount of automation cases, we will require having an Expedition project. Making a POST call to the project route, we can create a project with a desired name.
API syntax for creating a new project:
Method | EndPoint | Parameters |
---|---|---|
POST | https://localhost/api/v1/project | in url { "project":"project1", "description":"Project for testing" } |
example | https://localhost/api/v1/project | {"project":"MyLittleProject", "description":"A migration project"} |
- Python
- Php
- Go
print("*****Create a new Expedition Project*****\n")projectName = input("Please enter project name: (Needs to start with letters): ")print(" \n")data = {"name": projectName, "device_id[0]": DeviceId}url="https://" + ip + "/api/v1/project"r = requests.post(url,data=data, verify=False, headers=hed)response = r.json()success = json.dumps(response["success"])if success == "true": print("New project created successfully" + " \n") projectId = json.dumps(response['data']['id']) print("Your project-ID is", str(projectId) + " \n")print("\n")
package mainimport "fmt"
func main() { //TODO}
echo "\n";echo "CREATE NEW PROJECT\n";$data = ["project"=> $projectName];$url = 'https://'.$ip.'/api/v1/project';$curl = curl_init($url);curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);curl_setopt($curl, CURLOPT_HTTPHEADER,$hed);curl_setopt($curl,CURLOPT_POST, TRUE);curl_setopt($curl,CURLOPT_POSTFIELDS, $data);curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);$response = curl_exec($curl);$jsonResponse = json_decode($response);$success = $jsonResponse->Contents->success;if ($success=='true'){ print_r($response); $projectId = $jsonResponse->Contents->response->data->content->id; print_r($jsonResponse->Contents->response->{'response-messages'}->messages[0]->message);}echo "\n";
#
Step 6. Import the PAN-OS configuration of your device to the projectThis step will associate the device with project. The API response will contain a job ID , you can then use API call to check job status. Please refer to checking job status Checking Job Status section
API syntax for the step:
Method | EndPoint | Parameters |
---|---|---|
POST | https://localhost/api/v1/project/project_id/import/device | in url "project_id":"project_id" in_body {"device_id":"device_id" } |
example | https://localhost/api/v1/project/22/import/device | {"device_id":"23""} |
- Python
- Php
- Go
print("*****Import the PAN-OS configuration of your device to the project\n")url = "https://" + ip + "/api/v1/project/{0}/import/device".format(int(projectId))print(url)data = {"device_id": DeviceId}r = requests.post(url, data=data, verify=False, headers=hed)response = r.json()jobId = json.dumps(response["data"]["job_id"])jobFinished = Falseprint("CHECK configuration upload status...........")r = requests.get( "https://" + ip + "/api/v1/job/" + jobId + "?complete=true", verify=False, headers=hed,)response = r.json()jobState = json.dumps(response["data"]["state"])percentage = float(jobState) * 100print( "Import PAN-OS configuration from devie to Project: " + str(round(percentage, 2)) + "%\n")# Wait until job is donewhile jobState != "1": sleep(5) r = requests.get( "https://" + ip + "/api/v1/job/" + jobId + "?complete=true", verify=False, headers=hed, ) response = r.json() jobState = json.dumps(response["data"]["state"]) percentage = float(jobState) * 100 print( "PAN-OS configuration has been imported to Project: " + str(round(percentage, 2)) + "%\n" )response = r.json()statusmessage = json.dumps(response["data"]["task"][0]["statusMessage"])print(statusmessage)
#
Step 7. Get Source ID of the config fileIn this step, we will make a API call to get source_id of the config file that's been imported to the project. After this API call, you will parse the response that contains source_id. The source_id represnet the pan-os config file that you would like to work on, and it will be used in the subsequent API calls.
API syntax for the step:
Method | Route | Parameters |
---|---|---|
GET | https://localhost/api/v1/project/{project_id}/source | in url "project_id":project_Id in_body {"device_id":device_Id} |
example | https://localhost/api/v1/project/22/source | {"device_id": 23} |
- Python
- Php
- Go
print("Get Source_ID of the config file")url = "https://" + ip + "/api/v1/project/" + projectId + "/source"r = requests.get(url, data=data, verify=False, headers=hed)response = r.json()print(response)source_id = json.dumps(response["data"]["source"][0]["id"])print("PAN-OS config source_id is: " + source_id)
#
Step 8. Create a filter for all allowed security rulesIn this step, we will create a filter for all security rules that have action "allowed" . Please refer to the Expedition-API Filters section for details on filters. In this specific exmaple, we are sending the request body contains below data, In the json response, you will get a filter_id , this filter_id will be used in the subsequent steps.
data = { "name": "all allowed rules", "filter": "[security_rule] action equals \"allow\"", }
API syntax for the step:
Method | Route | Parameters |
---|---|---|
POST | https://localhost/api/v1/project/{project_id}/tools/filter | in url "project_id":project_Id in_body {"name":filter_name,"filter":filter} |
example | https://localhost/api/v1/project/22/tools/filter | {"name": "all allowed rules", "filter" : "[security_rule] action equals \"allow\""} |
- Python
- Php
- Go
def Filter(): print("create a filter to list all allowed rules") url = "https://" + ip + "/api/v1/project/" + projectId + "/tools/filter" data = { "name": "all allowed rules", "filter": "[security_rule] action equals \"allow\"", } r = requests.post(url, data=data, verify=False, headers=hed) response = r.json() print(response) global filterID filterID = json.dumps(response["data"]["last_history_entry"]["filter_id"]) print("your filter ID is " + filterID)
#
Step 9. Execute the filterAfter create a filter, we will execute the filter based on filter_Id , in the request body, you will need to provide "source_id" obtained from the previous step as required parameter.
API syntax for the step:
Method | Route | Parameters |
---|---|---|
POST | https://localhost/api/v1/project/{project_id}/tools/filter/{filter_id}/execute | in url "project_id":project_Id, "filter_id":filter_Id in_body {"source_id": source_id of the PAN-OS config file} |
example | https://localhost/api/v1/project/22/tools/filter/1/execute | {"source_id": "23564"} |
- Python
- Php
- Go
def ExecuteFilter(): print("execute the filter") data = {"source_id": source_id} url = ( "https://" + ip + "/api/v1/project/" + projectId + "/tools/filter/" + filterID + "/execute" ) r = requests.post(url, data=data, verify=False, headers=hed) response = r.json() print(response) jobId = json.dumps(response["data"]["job_id"]) jobFinished = False print("CHECK filter execute status...........") r = requests.get( "https://" + ip + "/api/v1/job/" + jobId + "?complete=true", verify=False, headers=hed, ) response = r.json() print(response) jobState = json.dumps(response["data"]["state"]) percentage = float(jobState) * 100 print("Execute filter........: " + str(round(percentage, 2)) + "%\n")
# Wait until job is done while jobState != "1": sleep(5) r = requests.get( "https://" + ip + "/api/v1/job/" + jobId + "?complete=true", verify=False, headers=hed, ) response = r.json() print(response) jobState = json.dumps(response["data"]["state"]) print(jobState) percentage = float(jobState) * 100 print("Filter execute...... " + str(round(percentage, 2)) + "%\n") response = r.json() print(response) statusmessage = json.dumps(response["data"]["task"][0]["statusMessage"]) print(statusmessage)
#
Step 10. Print the filter execution resultAfter the filter is executed , we can view the result using below API call. The result should contain all the objects that matches with the filter. From the response, you will parse the collection_Id to be used in the subsequent API call.
API syntax for the step:
Method | Route | Parameters |
---|---|---|
GET | https://localhost/api/v1/project/{project_id}/tools/filter/{filter_id}/result | in url "project_id":project_Id, "filter_id":filter_Id |
example | https://localhost/api/v1/project/22/tools/filter/1/result |
- Python
- Php
- Go
print("Print the Filter Execution Result") url = ( "https://" + ip + "/api/v1/project/" + projectId + "/tools/filter/" + filterID + "/result" ) r = requests.get(url, verify=False, headers=hed) response = r.json() print(response) global Collection_ID Collection_ID = json.dumps(response["data"]["id"])
#
Step 11. Get Security Profile Grop IDIn order to apply the secruity profile group to the security policy, we will need to find out the object ID of the secruity profile group first. In the example, we will parse the first object ID from the response.
API syntax for the step:
Method | Route | Parameters |
---|---|---|
GET | https://localhost/api/v1/project/{project_id}/object/profile_group | in url "project_id":project_Id |
example | https://localhost/api/v1/project/22/object/profile_group |
- Python
- Php
- Go
print("Get Security Profile group")url = "https://" + ip + "/api/v1/project/" + projectId + "/object/profile_group"r = requests.get(url,verify=False, headers=hed)response=r.json()print(response)SPG_ID=json.dumps(response["data"]["profile_group"][0]["id"])print(SPG_ID)
#
Step 12. Bulk Change Apply SPG to all allowed rulesThe final step we perform a bulk change to apply the secruity profile group to all allowed rules.
API syntax for the step:
Method | Route | Parameters |
---|---|---|
PUT | https://localhost/api/v1/project/{project_id}/policy/security | in url "project_id":project_Id in_body {"add[profile][0]": object_id of the SPG, "id": collection_id} |
example | https://localhost/api/v1/project/22/policy/security | {"add[profile][0]": "11714", "id":"20793"} |
- Python
- Php
- Go
print("Bulk Change Apply SPG to all allowed rules")url = "https://" + ip + "/api/v1/project/" + projectId + "/policy/security"print(url)data = {"add[profile][0]": int(SPG_ID), "id": int(Collection_ID)}print(data)r = requests.put(url, data=data, verify=False, headers=hed)response = r.json()print(response)