From c9bcb1494686d6edde800da02e6a25e9e06f2e99 Mon Sep 17 00:00:00 2001 From: Yaakov Praisler <59408745+yaakovpraisler@users.noreply.github.com> Date: Thu, 8 Jun 2023 07:51:54 +0300 Subject: [PATCH] [Panorama] Tags Management (#27044) * panorama tag commands * release notes * release notes * tpb * fix tpb * fix * add kew_words and update description * fix device-group * revert non-relevat change * bump version * - Added device group location to the tags result - Added list request when editing tags to get the properties that are not given in arguments * Update Packs/PAN-OS/Integrations/Panorama/Panorama.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/PAN-OS/Integrations/Panorama/Panorama.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * docs fixes * fix UT * pre-commit fix * bump version * pre-commit * CR fix --------- Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> --- .../PAN-OS/Integrations/Panorama/Panorama.py | 341 +++++++- .../PAN-OS/Integrations/Panorama/Panorama.yml | 101 ++- .../Integrations/Panorama/Panorama_test.py | 176 +++- Packs/PAN-OS/Integrations/Panorama/README.md | 144 ++++ .../Panorama/command_examples.txt | 4 + Packs/PAN-OS/ReleaseNotes/1_17_6.md | 10 + .../playbook-palo_alto_panorama_test_pb.yml | 749 +++++++++++++++++- Packs/PAN-OS/pack_metadata.json | 8 +- 8 files changed, 1523 insertions(+), 10 deletions(-) create mode 100644 Packs/PAN-OS/ReleaseNotes/1_17_6.md diff --git a/Packs/PAN-OS/Integrations/Panorama/Panorama.py b/Packs/PAN-OS/Integrations/Panorama/Panorama.py index a98a73013b50..35e3c64a3288 100644 --- a/Packs/PAN-OS/Integrations/Panorama/Panorama.py +++ b/Packs/PAN-OS/Integrations/Panorama/Panorama.py @@ -6930,7 +6930,7 @@ def apply_security_profile(xpath: str, profile_name: str, profile_type: str) -> profile_types_result = dict_safe_get(result, ['response', 'result', 'entry', 'profile-setting', 'profiles'], default_return_value={}) - # align the response for both committed and un-committed profiles + # align the response for both committed and un-committed profiles parse_pan_os_un_committed_data(profile_types_result, ['@admin', '@dirtyId', '@time']) # remove from the types the given profile type, since we update it anyway @@ -13097,6 +13097,337 @@ def pan_os_delete_application_group_command(args): ) +def build_tag_xpath(is_shared: bool = False, name: str = None) -> str: + """Builds the tag request xpath. + + Args: + is_shared (bool): Whether the device group is shared. + name (str): The tag name. + + Returns: + str: The xpath to send the request with. + """ + _xpath = f"{XPATH_RULEBASE}tag" + if is_shared: + _xpath = "/config/shared/tag" + if name: + _xpath = f"{_xpath}/entry[@name='{name}']" + return _xpath + + +def build_tag_element(disable_override: bool, comment: str, new_name: str = None, color: Optional[str] = None) -> str: + """Build the request element in XML format + + Args: + disable_override (bool): Whether to disable overriding the tag. + comment (str): The comment for the tag. + new_name (str): When editing - the new name for the tag. + color (str): The color of the tag. + + Returns: + str: The element in XML format. + """ + api_disable_override = 'yes' if disable_override else 'no' + element = f'{api_disable_override}' \ + f'{comment}' + if color: + element += f'{color}' + if new_name: + element = f'{element}' + return element + + +def pan_os_list_tag(is_shared: bool = False) -> tuple[dict, list]: + """builds the params and sends the request to get the list of tags. + + Args: + is_shared (bool): If True, then the list of tags are from the shared device group. + + Returns: + dict: The raw response of the tags list from panorama. + list: The list of tags from response. + """ + params = { + 'type': 'config', + 'action': 'get', + 'key': API_KEY, + 'xpath': build_tag_xpath(is_shared=is_shared) + } + + raw_response = http_request(URL, 'GET', params=params) + tags_list_result = extract_tags_list(raw_response) + add_location(tags_list_result, is_shared_tags=is_shared) + return raw_response, tags_list_result + + +def prettify_tags(tags: list) -> list: + """Prettify the keys in the tags for the HR table. + + Args: + tags (list): The tags list. + + Return: + list: the result of the prettify list for the table. + """ + result = [] + + for tag in tags: + tag['name'] = tag.pop('@name') # remove the '@' + new_tag = {'Name': tag['name'], 'Location': tag['location']} + + if 'color' in tag: + new_tag['Color'] = tag['color'] + + if 'comments' in tag: + new_tag['Comment'] = tag['comments'] + + result.append(new_tag) + return result + + +def extract_tags_list(raw_response: dict) -> list: + """Extracts the tags list result from the API's raw response. + + Args: + raw_response (dict): The raw response. + + Returns: + list: The list of tags from the response. + """ + tags_list_result = raw_response.get("response", {}).get("result", {}).get("tag", {}) + tags_list_result = [] if tags_list_result is None else tags_list_result.get("entry", []) + + if not isinstance(tags_list_result, list): + tags_list_result = [tags_list_result] + return tags_list_result + + +def add_location(tags_list: list, is_shared_tags: bool = False) -> None: + """Adds the location property to the tags. + + Args: + tags_list (list): The given tags list. + is_shared_tags (bool, optional): Whether the tags are from shared location. + """ + for tag in tags_list: + tag.update({'location': DEVICE_GROUP if not is_shared_tags else 'shared'}) + + +def pan_os_list_tag_command(args: dict) -> CommandResults: + """Sends the request and returns the result of the command pan-os-list-tag. + + Args: + args (dict): The command arguments. + + Returns: + CommandResults: The command results with raw response, outputs and readable outputs. + """ + include_shared = argToBoolean(args.get('include_shared_tags', False)) + + raw_response, tags_list_result = pan_os_list_tag() + + if include_shared: + _, shared_tags_list_result = pan_os_list_tag(include_shared) + tags_list_result.extend(shared_tags_list_result) + + for tag in tags_list_result: + parse_pan_os_un_committed_data(tag, ['@admin', '@dirtyId', '@time']) + + prettify_tags_list = prettify_tags(tags_list_result) + return CommandResults( + raw_response=raw_response, + outputs=tags_list_result, + readable_output=tableToMarkdown( + f'Tags:', + prettify_tags_list, + ['Name', 'Color', 'Comment', 'Location'] + ), + outputs_prefix='Panorama.Tag', + outputs_key_field='name' + ) + + +def pan_os_create_tag( + tag_name: str, + disable_override: bool, + is_shared: bool, + comment: str +) -> dict: + """builds the params and sends the request to create the tag. + + Args: + tag_name (str): The tag name. + disable_override (bool): Whether to disable overriding the tag. + is_shared (bool): Whether to create the tag in the shared device group. + comment (str): The tag comment. + + Returns: + dict: The raw response from panorama's API. + """ + params = { + 'xpath': build_tag_xpath(name=tag_name, is_shared=is_shared), + 'element': build_tag_element(disable_override, comment), + 'action': 'set', + 'type': 'config', + 'key': API_KEY + } + + return http_request(URL, 'GET', params=params) + + +def pan_os_create_tag_command(args: dict) -> CommandResults: + """Creates a tag in Panorama. + + Args: + args (dict): The commmand arguments to create the tag with. + + Returns: + CommandResults: The command results with raw response and readable outputs. + """ + tag_name = args.get('name', '') + disable_override = argToBoolean(args.get('disable_override', False)) + is_shared = argToBoolean(args.get('is_shared', False)) + comment = args.get('comment', '') + + raw_response = pan_os_create_tag(tag_name, + disable_override, + is_shared, + comment) + + return CommandResults( + raw_response=raw_response, + readable_output=f'The tag with name "{tag_name}" was created successfully.', + ) + + +def pan_os_edit_tag( + tag_name: str, + new_tag_name: str, + disable_override: bool, + comment: str, + color: Optional[str] +) -> dict: + """builds the params and sends the request to edit the tag. + + Args: + tag_name (str): The tag name to edit. + new_tag_name (str): The new tag name. + disable_override (bool): Whether to disable overriding the tag. + comment (str): The tag comment. + + Returns: + dict: The raw response from panorama's API. + """ + params = { + 'xpath': build_tag_xpath(name=tag_name), + 'element': build_tag_element(disable_override, comment, new_name=new_tag_name, color=color), + 'action': 'edit', + 'type': 'config', + 'key': API_KEY + } + + try: + response = http_request(URL, 'GET', params=params) + except Exception as e: + if 'Status code: 12' in str(e): + # try in shared group + params['xpath'] = build_tag_xpath(name=tag_name, is_shared=True) + response = http_request(URL, 'GET', params=params) + else: + raise + + return response + + +def pan_os_edit_tag_command(args: dict) -> CommandResults: + """Edits the given tag in Panorama. + + Args: + args (dict): The command arguments to edit the tag. + + Returns: + CommandResults: The command results with raw response and readable outputs. + """ + tag_name = args.get('name', '') + new_tag_name = args.get('new_name', tag_name) + disable_override = args.get('disable_override') + comment = args.get('comment', '') + + # To not override tag properties that are not given in the arguments + # we need to list the tags and take these properties from there + _, tags_list = pan_os_list_tag() + tags_list.extend(pan_os_list_tag(is_shared=True)[1]) + tag_to_edit_from_list = [tag for tag in tags_list if tag['@name'] == tag_name] + + try: + tag_to_edit = tag_to_edit_from_list[0] + except IndexError as e: + raise DemistoException(f"Can't find the tag with name '{tag_name}' in tags list.\n" + f"Please run the pan-os-list-tag command and verify that the tag '{tag_name}' exists.") + + parse_pan_os_un_committed_data(tag_to_edit, ['@admin', '@dirtyId', '@time']) + + disable_override = disable_override if disable_override else tag_to_edit.get("disable-override", "no") + disable_override = argToBoolean(disable_override) + comment = comment if comment else tag_to_edit.get("comments", "") + color = tag_to_edit.get("color", "") + + raw_response = pan_os_edit_tag(tag_name, new_tag_name, disable_override, comment, color) + + return CommandResults( + raw_response=raw_response, + readable_output=f'The tag with name "{tag_name}" was edited successfully.', + ) + + +def pan_os_delete_tag(tag_name: str) -> dict: + """builds the params and sends the request to delete the tag. + + Args: + tag_name (str): The tag name to delete. + + Returns: + dict: The raw response from panorama's API. + """ + params = { + 'xpath': build_tag_xpath(name=tag_name), + 'action': 'delete', + 'type': 'config', + 'key': API_KEY + } + + try: + response = http_request(URL, 'GET', params=params) + except Exception as e: + if 'Object not present' in str(e) or 'Status code: 12' in str(e): + # try in shared group + params['xpath'] = build_tag_xpath(name=tag_name, is_shared=True) + response = http_request(URL, 'GET', params=params) + else: + raise + + return response + + +def pan_os_delete_tag_command(args: dict) -> CommandResults: + """Deletes the tag from panorama + + Args: + args (dict): The command arguments. + + Returns: + CommandResults: The command results with raw response and readable outputs. + """ + tag_name = args.get('name', '') + + raw_response = pan_os_delete_tag(tag_name) + + return CommandResults( + raw_response=raw_response, + readable_output=f'The tag with name "{tag_name}" was deleted successfully.', + ) + + """ Fetch Incidents """ @@ -14210,6 +14541,14 @@ def main(): # pragma: no cover return_results(pan_os_delete_application_group_command(args)) elif command == 'pan-os-list-templates': return_results(pan_os_list_templates_command(args)) + elif command == 'pan-os-list-tag': + return_results(pan_os_list_tag_command(args)) + elif command == 'pan-os-create-tag': + return_results(pan_os_create_tag_command(args)) + elif command == 'pan-os-edit-tag': + return_results(pan_os_edit_tag_command(args)) + elif command == 'pan-os-delete-tag': + return_results(pan_os_delete_tag_command(args)) else: raise NotImplementedError(f'Command {command} is not implemented.') except Exception as err: diff --git a/Packs/PAN-OS/Integrations/Panorama/Panorama.yml b/Packs/PAN-OS/Integrations/Panorama/Panorama.yml index 3b6eeb73befd..0480aa3d57e0 100644 --- a/Packs/PAN-OS/Integrations/Panorama/Panorama.yml +++ b/Packs/PAN-OS/Integrations/Panorama/Panorama.yml @@ -213,7 +213,7 @@ configuration: required: false type: 13 section: Connect -description: Manage Palo Alto Networks Firewall and Panorama. For more information see Panorama documentation. +description: Manage Palo Alto Networks Firewall and Panorama. Use this pack to manage Prisma Access through Panorama. For more information, see the Panorama documentation display: Palo Alto Networks PAN-OS name: Panorama script: @@ -9557,6 +9557,105 @@ script: description: Deletes an application-group name: pan-os-delete-application-group outputs: [] + - arguments: + - description: Whether to include shared tags in the list. + isArray: false + name: include_shared_tags + required: false + auto: PREDEFINED + predefined: + - 'Yes' + - 'No' + defaultValue: 'No' + - description: The device group that the tags are part of. + isArray: false + name: device-group + required: false + description: Returns a list of tags from Panorama. + name: pan-os-list-tag + outputs: + - contextPath: Panorama.Tag.name + description: The name of the tag. + type: String + - contextPath: Panorama.Tag.color + description: The color of the tag. + type: String + - contextPath: Panorama.Tag.comment + description: The comment in the tag. + type: String + - contextPath: Panorama.Tag.disable-override + description: Whether overriding the tag is disabled. + type: String + - contextPath: Panorama.Tag.location + description: The tag's device group location. + type: String + - arguments: + - description: The name for the new tag to be created. + isArray: false + name: name + required: true + - description: The device group that the tag will be part of. + isArray: false + name: device-group + required: false + - description: Whether to disable overriding the tag. + isArray: false + name: disable_override + required: false + auto: PREDEFINED + predefined: + - 'true' + - 'false' + defaultValue: 'false' + - description: Whether the tag should be generated in a shared location. + isArray: false + name: is_shared + required: false + auto: PREDEFINED + predefined: + - 'true' + - 'false' + defaultValue: 'false' + - description: The comment for the tag. + isArray: false + name: comment + required: false + description: Creates a new tag in Panorama. + name: pan-os-create-tag + - arguments: + - description: The existing name for the tag to be edited. + isArray: false + name: name + required: true + - description: The new name for the tag to be replaced with. + isArray: false + name: new_name + required: false + - description: The device group of the tag. + isArray: false + name: device-group + required: false + - description: Whether to disable overriding the tag. + isArray: false + name: disable_override + required: false + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - description: The comment for the tag. + isArray: false + name: comment + required: false + description: Edits a tag in Panorama. + name: pan-os-edit-tag + - arguments: + - description: The name of the tag to delete. + isArray: false + name: name + required: true + description: Deletes a tag from Panorama. + name: pan-os-delete-tag dockerimage: demisto/pan-os-python:1.0.0.61510 feed: false isfetch: true diff --git a/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py b/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py index 1974e571efdf..ea8439611b2e 100644 --- a/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py +++ b/Packs/PAN-OS/Integrations/Panorama/Panorama_test.py @@ -1,10 +1,10 @@ import json import io +from defusedxml import ElementTree import pytest import requests_mock import demistomock as demisto -from lxml import etree from unittest.mock import patch, MagicMock from panos.device import Vsys from panos.panorama import Panorama, DeviceGroup, Template @@ -2539,7 +2539,7 @@ def test_without_specify(self, requests_mock): def load_xml_root_from_test_file(xml_file: str): """Given an XML file, loads it and returns the root element XML object.""" - return etree.parse(xml_file).getroot() + return ElementTree.parse(xml_file).getroot() MOCK_PANORAMA_SERIAL = "111222334455" @@ -6787,3 +6787,175 @@ def test_panorama_list_rules(): assert rules['application']['member'][0] == 'dns' assert mock_request.last_request.qs['xpath'][0] == \ "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[(application/member = 'dns')]" + + +@pytest.mark.parametrize('include_shared', ['No', 'Yes']) +def test_panorama_list_tags(mocker, include_shared): + """ + Given: + - The include_shared argument. + When: + - Running the pan_os_list_tag_command method. + Then: + - Ensure the returned tags list output and HR table is as expected. + """ + import Panorama + import requests + Panorama.URL = 'https://1.1.1.1:443/' + Panorama.API_KEY = 'thisisabogusAPIKEY!' + Panorama.DEVICE_GROUP = '' + tags_response_xml = """ + + + color13 + + + color39 + + + color39 + no + text text text + """ + + shared_tags_response_xml = """ + + + color15 + + + color34 + """ + + tags_mock_response = MockedResponse(text=tags_response_xml, status_code=200) + shared_tags_mock_response = MockedResponse(text=shared_tags_response_xml, status_code=200) + + mocker.patch.object(requests, 'request', side_effect=[tags_mock_response, shared_tags_mock_response]) + + expected_outputs_tags_list = [{"name": "tag1", "color": "color13", "location": ""}, + {"name": "tag2", "color": "color39", "location": ""}, + {"name": "tag3", "color": "color39", "location": "", + "disable-override": "no", "comments": "text text text"}] + + expected_hr_result = '### Tags:\n|Name|Color|Comment|Location|\n|---|---|---|---|\n| tag1 | color13' \ + ' | | |\n| tag2 | color39 | | |\n| tag3 | color39 | text text text | |\n' + + if include_shared == 'Yes': + expected_outputs_tags_list.extend([ + {"name": "sharedtag1", "color": "color15", "location": "shared"}, + {"name": "sharedtag2", "color": "color34", "location": "shared"} + ]) + expected_hr_result += '| sharedtag1 | color15 | | shared |\n| sharedtag2 | color34 | | shared |\n' + + command_results = Panorama.pan_os_list_tag_command({"include_shared_tags": include_shared}) + + assert command_results.outputs == expected_outputs_tags_list + assert command_results.readable_output == expected_hr_result + + +def test_pan_os_create_tag_command(mocker): + """ + Given: + - The tag name to create. + When: + - Running the pan_os_create_tag_command method. + Then: + - Ensure the returned response and readable outputs is as expected. + """ + import Panorama + import requests + Panorama.URL = 'https://1.1.1.1:443/' + Panorama.API_KEY = 'thisisabogusAPIKEY!' + expected_text_response = 'command succeeded' + + create_tag_mock_response = MockedResponse(text=expected_text_response, status_code=200) + mocker.patch.object(requests, 'request', return_value=create_tag_mock_response) + + command_results = Panorama.pan_os_create_tag_command({"name": "testtag"}) + + assert command_results.raw_response == {'response': {'@status': 'success', '@code': '20', 'msg': 'command succeeded'}} + assert command_results.readable_output == 'The tag with name "testtag" was created successfully.' + + +@pytest.mark.parametrize('is_shared', [False, True]) +def test_pan_os_edit_tag_command(mocker, is_shared): + """ + Given: + - The command arguments to edit the tag. + When: + 1. The tag is not in a shared device group. + 2. The tag is in a shared device group. + - Running the pan_os_edit_tag_command method. + Then: + - Ensure the request method call counts is according to if the tag is shared. + - Ensure the returned response and readable outputs is as expected. + """ + import Panorama + import requests + Panorama.URL = 'https://1.1.1.1:443/' + Panorama.API_KEY = 'thisisabogusAPIKEY!' + expected_first_text_response_if_shared = '' \ + 'Edit breaks config validity' + expected_text_response = 'command succeeded' + expected_list_text_response = """ + + + color39 + no + text text text + """ + expected_request_count = 4 if is_shared else 3 + + edit_tag_mock_response = MockedResponse(text=expected_text_response, status_code=200) + edit_tag_first_mock_response = MockedResponse(text=expected_first_text_response_if_shared, status_code=200) + list_tag_mr = MockedResponse(text=expected_list_text_response, status_code=200) + + responses = [list_tag_mr, list_tag_mr, edit_tag_first_mock_response, edit_tag_mock_response] if is_shared else \ + [list_tag_mr, list_tag_mr, edit_tag_mock_response] + request_mocker = mocker.patch.object(requests, 'request', side_effect=responses) + + command_results = Panorama.pan_os_edit_tag_command({"name": "testtag", "new_name": "newtesttag"}) + + assert request_mocker.call_count == expected_request_count + assert command_results.raw_response == {'response': {'@status': 'success', '@code': '20', 'msg': 'command succeeded'}} + assert command_results.readable_output == 'The tag with name "testtag" was edited successfully.' + + +@pytest.mark.parametrize('is_shared', [False, True]) +def test_pan_os_delete_tag_command(mocker, is_shared): + """ + Given: + - The tag name to delete. + When: + 1. The tag is not in a shared device group. + 2. The tag is in a shared device group. + - Running the pan_os_delete_tag_command method. + Then: + - Ensure the request method call counts is according to if the tag is shared. + - Ensure the returned response and readable outputs is as expected. + """ + import Panorama + import requests + Panorama.URL = 'https://1.1.1.1:443/' + Panorama.API_KEY = 'thisisabogusAPIKEY!' + Panorama.DEVICE_GROUP = 'somedevice' + + expected_first_text_response_if_shared = 'Object doesn\'t exist' + expected_second_text_response_if_shared = '' \ + '' + expected_text_response = 'command succeeded' + expected_request_count = 3 if is_shared else 1 + + delete_tag_mock_response = MockedResponse(text=expected_text_response, status_code=200) + delete_tag_first_mock_response = MockedResponse(text=expected_first_text_response_if_shared, status_code=200) + delete_tag_second_mock_response = MockedResponse(text=expected_second_text_response_if_shared, status_code=200) + + responses = [delete_tag_first_mock_response, delete_tag_second_mock_response, + delete_tag_mock_response] if is_shared else [delete_tag_mock_response] + request_mocker = mocker.patch.object(requests, 'request', side_effect=responses) + + command_results = Panorama.pan_os_delete_tag_command({"name": "testtag", "new_name": "newtesttag"}) + + assert request_mocker.call_count == expected_request_count + assert command_results.raw_response == {'response': {'@status': 'success', '@code': '20', 'msg': 'command succeeded'}} + assert command_results.readable_output == 'The tag with name "testtag" was deleted successfully.' diff --git a/Packs/PAN-OS/Integrations/Panorama/README.md b/Packs/PAN-OS/Integrations/Panorama/README.md index 2880ab55f632..76a6b96fffbf 100644 --- a/Packs/PAN-OS/Integrations/Panorama/README.md +++ b/Packs/PAN-OS/Integrations/Panorama/README.md @@ -8673,3 +8673,147 @@ There is no context output for this command. #### Human Readable Output >application-group test-3 was deleted successfully. +### pan-os-list-tag + +*** +Returns a list of tags from Panorama. + +#### Base Command + +`pan-os-list-tag` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| include_shared_tags | Whether to include shared tags in the list. Possible values are: Yes, No. Default is No. | Optional | +| device_group | The device group that the tags are part of. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| Panorama.Tag.name | String | The name of the tag. | +| Panorama.Tag.color | String | The color of the tag. | +| Panorama.Tag.comment | String | The comment in the tag. | +| Panorama.Tag.disable-override | String | Whether overriding the tag is disabled. | + +#### Command example +```!pan-os-list-tag include_shared_tags=No``` +#### Context Example +```json +{ + "Panorama": { + "Tag": [ + { + "name": "tag1", + "color": "color13" + }, + { + "name": "tag2", + "color": "color39" + }, + { + "name": "tag3", + "color": "color39", + "disable-override": "no", + "comments": "text text text" + } + ] + } +} +``` + +#### Human Readable Output + +>### Tags: +>|Name|Color|Comment| +>|---|---|---| +>| tag1 | color13 | | +>| tag2 | color39 | | +>| tag3 | color39 | text text text | + +### pan-os-create-tag + +*** +Creates a new tag in Panorama. + +#### Base Command + +`pan-os-create-tag` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The name for the new tag to be created. | Required | +| device_group | The device group that the tag will be part of. | Optional | +| disable_override | Whether to disable overriding the tag. Possible values are: true, false. Default is false. | Optional | +| is_shared | Whether the tag should be generated in a shared location. Possible values are: true, false. Default is false. | Optional | +| comment | The comment for the tag. | Optional | + +#### Context Output + +There is no context output for this command. +#### Command example +```!pan-os-create-tag name="testtag" comment="some comment" is_shared=false``` + +#### Human Readable Output + +>The tag with name "testtag" was created successfully. + +### pan-os-edit-tag + +*** +Edits a tag in Panorama. + +#### Base Command + +`pan-os-edit-tag` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The existing name for the tag to be edited. | Required | +| new_name | The new name for the tag to be replaced with. | Optional | +| device_group | The device group of the tag. | Optional | +| disable_override | Whether to disable overriding the tag. Possible values are: true, false. Default is false. | Optional | +| comment | The comment for the tag. | Optional | + +#### Context Output + +There is no context output for this command. + +#### Command example +```!pan-os-edit-tag name="testtag" new_name="newtesttag" comment="some comment"``` + +#### Human Readable Output + +>The tag with name "testtag" was edited successfully. + +### pan-os-delete-tag + +*** +Deletes a tag from Panorama. + +#### Base Command + +`pan-os-delete-tag` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The name of the tag to delete. | Required | + +#### Context Output + +There is no context output for this command. + +#### Command example +```!pan-os-delete-tag name="testtag"``` + +#### Human Readable Output + +>The tag with name "testtag" was deleted successfully. diff --git a/Packs/PAN-OS/Integrations/Panorama/command_examples.txt b/Packs/PAN-OS/Integrations/Panorama/command_examples.txt index 49a3ad98259d..af745bb32569 100644 --- a/Packs/PAN-OS/Integrations/Panorama/command_examples.txt +++ b/Packs/PAN-OS/Integrations/Panorama/command_examples.txt @@ -140,3 +140,7 @@ not_running_this!panorama-get-ssl-decryption-rules !pan-os-edit-application-group name=test-3 action=remove applications=4shared !pan-os-delete-application-group name=test-3 !pan-os-query-logs log-type=traffic number_of_logs=1 polling=true +!pan-os-list-tag include_shared_tags=No +!pan-os-create-tag name="testtag" comment="some comment" is_shared=false +!pan-os-edit-tag name="testtag" new_name="newtesttag" comment="some comment" +!pan-os-delete-tag name="testtag" \ No newline at end of file diff --git a/Packs/PAN-OS/ReleaseNotes/1_17_6.md b/Packs/PAN-OS/ReleaseNotes/1_17_6.md new file mode 100644 index 000000000000..8d283f4b211a --- /dev/null +++ b/Packs/PAN-OS/ReleaseNotes/1_17_6.md @@ -0,0 +1,10 @@ + +#### Integrations + +##### Palo Alto Networks PAN-OS + +Added the following new commands to manage Panorama tags: +- ***pan-os-list-tag*** +- ***pan-os-create-tag*** +- ***pan-os-edit-tag*** +- ***pan-os-delete-tag*** diff --git a/Packs/PAN-OS/TestPlaybooks/playbook-palo_alto_panorama_test_pb.yml b/Packs/PAN-OS/TestPlaybooks/playbook-palo_alto_panorama_test_pb.yml index e7d8dd362dab..8cb95a1c4008 100644 --- a/Packs/PAN-OS/TestPlaybooks/playbook-palo_alto_panorama_test_pb.yml +++ b/Packs/PAN-OS/TestPlaybooks/playbook-palo_alto_panorama_test_pb.yml @@ -2101,7 +2101,7 @@ tasks: isoversize: false nexttasks: '#none#': - - '119' + - '137' note: false quietmode: 0 scriptarguments: @@ -2152,8 +2152,8 @@ tasks: view: |- { "position": { - "x": 680, - "y": 5830 + "x": 695, + "y": 7290 } } continueonerrortype: "" @@ -2194,6 +2194,749 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + "121": + id: "121" + taskid: 22de8d80-056a-4fa2-8170-1bc45c1774a0 + type: title + task: + id: 22de8d80-056a-4fa2-8170-1bc45c1774a0 + version: -1 + name: Tags + type: title + iscommand: false + brand: "" + nexttasks: + '#none#': + - "122" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6010 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "122": + id: "122" + taskid: 57c8aa57-6230-499a-888b-75f96e9bdee5 + type: regular + task: + id: 57c8aa57-6230-499a-888b-75f96e9bdee5 + version: -1 + name: Create tag + description: Creates a new tag. + script: Panorama|||pan-os-create-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "123" + scriptarguments: + comment: + simple: some comment + disable_override: + simple: "true" + name: + simple: test-tag + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6155 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "123": + id: "123" + taskid: 4993a8cc-68ed-40d2-883e-06e41e3eceb7 + type: regular + task: + id: 4993a8cc-68ed-40d2-883e-06e41e3eceb7 + version: -1 + name: pan-os-list-tag + description: Returns a list of tags. + script: Panorama|||pan-os-list-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "124" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6320 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "124": + id: "124" + taskid: 0af41bbd-dadb-4a89-8272-c4b5da7e6ebd + type: condition + task: + id: 0af41bbd-dadb-4a89-8272-c4b5da7e6ebd + version: -1 + name: Check new tag exist + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "125" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: containsGeneral + left: + value: + complex: + root: Panorama.Tag + accessor: name + iscontext: true + right: + value: + simple: test-tag + - - operator: isEqualString + left: + value: + complex: + root: Panorama.Tag + filters: + - - operator: isEqualString + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: test-tag + accessor: comments + iscontext: true + right: + value: + simple: some comment + - - operator: isEqualString + left: + value: + complex: + root: Panorama.Tag + filters: + - - operator: isEqualString + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: test-tag + accessor: disable-override + iscontext: true + right: + value: + simple: "yes" + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6480 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "125": + id: "125" + taskid: 716745be-ef04-460a-837d-9a0f5efbd371 + type: regular + task: + id: 716745be-ef04-460a-837d-9a0f5efbd371 + version: -1 + name: pan-os-edit-tag + description: Edits a tag in panorama. + script: Panorama|||pan-os-edit-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "126" + scriptarguments: + comment: + simple: other comment + name: + simple: test-tag + new_name: + simple: new-test-tag + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6630 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "126": + id: "126" + taskid: 484ab27d-5ace-4c5a-8dd0-95bca93d90aa + type: regular + task: + id: 484ab27d-5ace-4c5a-8dd0-95bca93d90aa + version: -1 + name: pan-os-list-tag + description: Returns a list of tags. + script: Panorama|||pan-os-list-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "127" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6780 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "127": + id: "127" + taskid: 7320e2ed-ed76-42b1-84f2-38129a6a4a88 + type: condition + task: + id: 7320e2ed-ed76-42b1-84f2-38129a6a4a88 + version: -1 + name: Check edited tag exist + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "128" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: containsGeneral + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: new-test-tag + - - operator: isEqualString + left: + value: + complex: + root: Panorama.Tag + filters: + - - operator: isEqualString + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: new-test-tag + accessor: comments + iscontext: true + right: + value: + simple: other comment + - - operator: isEqualString + left: + value: + complex: + root: Panorama.Tag + filters: + - - operator: isEqualString + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: new-test-tag + accessor: disable-override + iscontext: true + right: + value: + simple: "yes" + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 6930 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "128": + id: "128" + taskid: 540bbabc-d588-4bda-86aa-be52d743bae7 + type: regular + task: + id: 540bbabc-d588-4bda-86aa-be52d743bae7 + version: -1 + name: pan-os-delete-tag + description: Deletes a tag from panorama. + script: Panorama|||pan-os-delete-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "119" + scriptarguments: + name: + simple: new-test-tag + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 7080 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "129": + id: "129" + taskid: 1a0d7e55-ff12-4aa7-8288-a804f2c258fc + type: title + task: + id: 1a0d7e55-ff12-4aa7-8288-a804f2c258fc + version: -1 + name: Shared tags + type: title + iscommand: false + brand: "" + nexttasks: + '#none#': + - "130" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6010 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "130": + id: "130" + taskid: bcbbe822-4142-4e4a-8473-425a5445fec0 + type: regular + task: + id: bcbbe822-4142-4e4a-8473-425a5445fec0 + version: -1 + name: Create tag + description: Creates a new tag. + script: Panorama|||pan-os-create-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "131" + scriptarguments: + comment: + simple: some shared comment + is_shared: + simple: "true" + name: + simple: test-shared-tag + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6155 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "131": + id: "131" + taskid: a0d83c01-2700-42e6-806f-3198271f52a9 + type: regular + task: + id: a0d83c01-2700-42e6-806f-3198271f52a9 + version: -1 + name: pan-os-list-tag + description: Returns a list of tags. + script: Panorama|||pan-os-list-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "132" + scriptarguments: + include_shared_tags: + simple: "Yes" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6320 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "132": + id: "132" + taskid: 9ddd7865-7f72-41a2-85e7-05b4d76c3e48 + type: condition + task: + id: 9ddd7865-7f72-41a2-85e7-05b4d76c3e48 + version: -1 + name: Check new tag exist + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "133" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: containsGeneral + left: + value: + complex: + root: Panorama.Tag + accessor: name + iscontext: true + right: + value: + simple: test-shared-tag + - - operator: isEqualString + left: + value: + complex: + root: Panorama.Tag + filters: + - - operator: isEqualString + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: test-shared-tag + accessor: comments + iscontext: true + right: + value: + simple: some shared comment + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6480 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "133": + id: "133" + taskid: 6b3b83b3-6804-4568-8173-e5603c0cf636 + type: regular + task: + id: 6b3b83b3-6804-4568-8173-e5603c0cf636 + version: -1 + name: pan-os-edit-tag + description: Edits a tag in panorama. + script: Panorama|||pan-os-edit-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "134" + scriptarguments: + comment: + simple: other shared comment + name: + simple: test-shared-tag + new_name: + simple: new-test-shared-tag + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6630 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "134": + id: "134" + taskid: 581ab5bd-dd32-4844-8d0c-aabb0d764803 + type: regular + task: + id: 581ab5bd-dd32-4844-8d0c-aabb0d764803 + version: -1 + name: pan-os-list-tag + description: Returns a list of tags. + script: Panorama|||pan-os-list-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "135" + scriptarguments: + include_shared_tags: + simple: "Yes" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6780 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "135": + id: "135" + taskid: fca8a9b4-b0f8-4295-8140-148ad0f05e69 + type: condition + task: + id: fca8a9b4-b0f8-4295-8140-148ad0f05e69 + version: -1 + name: Check edited tag exist + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "136" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: containsGeneral + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: new-test-shared-tag + - - operator: isEqualString + left: + value: + complex: + root: Panorama.Tag + filters: + - - operator: isEqualString + left: + value: + simple: Panorama.Tag.name + iscontext: true + right: + value: + simple: new-test-shared-tag + accessor: comments + iscontext: true + right: + value: + simple: other shared comment + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 6930 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "136": + id: "136" + taskid: e72e56a7-7a23-4242-8d17-3c2679a0ba3b + type: regular + task: + id: e72e56a7-7a23-4242-8d17-3c2679a0ba3b + version: -1 + name: pan-os-delete-tag + description: Deletes a tag from panorama. + script: Panorama|||pan-os-delete-tag + type: regular + iscommand: true + brand: Panorama + nexttasks: + '#none#': + - "119" + scriptarguments: + name: + simple: new-test-shared-tag + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 920, + "y": 7080 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "137": + id: "137" + taskid: f7479d12-1312-4732-8420-29e2e21bc29a + type: regular + task: + id: f7479d12-1312-4732-8420-29e2e21bc29a + version: -1 + name: DeleteContext + description: |- + Delete field from context. + + This automation runs using the default Limited User role, unless you explicitly change the permissions. + For more information, see the section about permissions here: + https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.10/Cortex-XSOAR-Administrator-Guide/Automations + scriptName: DeleteContext + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "129" + - "121" + scriptarguments: + all: + simple: "yes" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 680, + "y": 5830 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false version: -1 view: |- { diff --git a/Packs/PAN-OS/pack_metadata.json b/Packs/PAN-OS/pack_metadata.json index 4c8669ec6783..8aa1bcedefc6 100644 --- a/Packs/PAN-OS/pack_metadata.json +++ b/Packs/PAN-OS/pack_metadata.json @@ -1,8 +1,8 @@ { "name": "PAN-OS by Palo Alto Networks", - "description": "Manage Palo Alto Networks Firewall and Panorama. For more information see Panorama documentation.", + "description": "Manage Palo Alto Networks Firewall and Panorama. Use this pack to manage Prisma Access through Panorama. For more information see Panorama documentation.", "support": "xsoar", - "currentVersion": "1.17.5", + "currentVersion": "1.17.6", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", @@ -15,7 +15,9 @@ "keywords": [ "Panorama", "Firewall", - "vsys" + "vsys", + "SASE", + "Access" ], "dependencies": { "CommonPlaybooks": {