Collect objects from the Strata Cloud Manager

Having a Strata Cloud Manager filled with all kinds of different objects, you may ask „What about the Strata Cloud Manager object collection?”. That’s the topic of today’s article! We will use Python with some libraries to collect objects from the selected tenant.

Codebase

The code presented in this article is committed to this GitHub repository.

Dependencies

For the automation, I’ve picked the pan-scm-sdk Python library. It’s a great way to make life easier, because we don’t have to construct each REST API call manually, rather we have a library that gives us complete methods to accomplish what we want.

You can install it manually, but you can also clone scm-automation-examples and use Poetry to install all dependencies.

Execute the poetry install —no-root —sync command and watch Poetry do its magic!

Objects collection

Objects on the Strata Cloud Manager have been created earlier with automation. If you’re curious about how to create objects in an automated manner, check this article.

Base

Before we look at the specific object collection, let’s go through the baseline of each script.

from scm.client import Scm


CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'

api_client = Scm(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    tsg_id=TSG_ID,
)

For the automation, you need to prepare your Strata Cloud Manager first, here’s article on that topic.

Here we’re importing the necessary Scm class, then defining the credentials for the connection to Strata Cloud Manager, and at the end, we’re creating objects of Scm class filled with the client ID, secret, and tenant ID.

Now we’re ready to go through the collection of various object types.

Tags

To collect tags, we need to create an instance of the Tag class. In our case, it’s assigned to the tag_instance variable. From now on, we can interact with tag objects.

from scm.client import Scm
from scm.config.objects import Tag


CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'

api_client = Scm(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    tsg_id=TSG_ID,
)

tag_instance = Tag(api_client)

tags = tag_instance.list(folder='All', exact_match=True)

for tag in tags:
    print(f'Tag name: {tag.name}, color: {tag.color.value if tag.color else None}, UUID: {tag.id}')

To collect tags we can use a list method. As an arguments, we’re passing the folder from which we want to collect tags – All in our case, and the exact_match with value True to collect only tags that match our criteria. After the execution, all collected tags are available under the tags variable.

There are folders in the Strata Cloud Manager that have different name in the UI and REST API calls. For example the Global folder in the back-end is identified as All.

Next, we’re iterating through the list, and printing information about each tag.

Tag name: Web Security Global, color: Green, UUID: 6ac39ca5-0ead-479a-4321-48ebeb140af0
Tag name: PA_predefined_embargo_rule, color: Green, UUID: 0d7ef08e-dce1-4caa-4321-d9cfe0f84a01
Tag name: best-practice, color: Green, UUID: 709c078e-7c0d-4705-4321-e57728a4de23
Tag name: Sanctioned, color: Olive, UUID: 1cec1022-df54-4ea9-4321-873fb6e4d218
Tag name: Tolerated, color: Maroon, UUID: fb3d4d0f-695b-4b17-4321-b5164d60f5d9
Tag name: [Generative AI], color: Red-Orange, UUID: None
Tag name: [Audio Generator], color: Yellow-Orange, UUID: None
Tag name: [Conversational Agent], color: Forest Green, UUID: None
Tag name: [Code Assistant & Generator], color: Turquoise Blue, UUID: None
Tag name: [Developer Platform], color: Azure Blue, UUID: None
Tag name: [Enterprise Search], color: Cerulean Blue, UUID: None
Tag name: [Image Editor & Generator], color: Midnight Blue, UUID: None
Tag name: [Meeting Assistant], color: Medium Blue, UUID: None
Tag name: [Productivity Assistant], color: Cobalt Blue, UUID: None
Tag name: [Video Editor & Generator], color: Violet Blue, UUID: None
Tag name: [Writing Assistant], color: Blue Violet, UUID: None
Tag name: empty, color: None, UUID: f46ced46-af47-4e96-a784-4a76b54fadda
Tag name: Domestic, color: Blue, UUID: a145bb8e-f69d-4958-4321-69146982c3f7
Tag name: International, color: Red, UUID: f872baa1-0e06-4b0f-4321-15a22678a2c2

If you’re curious about what data can we collect from the tag objects, take a look at the TagBaseModel definition.

URL Categories

After tags, let’s go with the URL Categories.

The workflow is similar, we need to create a URLCategories object instance, and that object will be used to collect all URL Categories from the SCM.

from scm.client import Scm
from scm.config.security import URLCategories


CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'

api_client = Scm(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    tsg_id=TSG_ID,
)

url_category_instance = URLCategories(api_client)

url_categories = url_category_instance.list(folder='All', exact_match=True)

for url_category in url_categories:
    print(f'URL category name: {url_category.name}, URL list: {url_category.list} , UUID: {url_category.id}')

After we have collected all URL Categories objects, we’re printing some of the available data in the console. Here is the definition of URLCategoriesBaseModel.

URL category name: Icelandic_websites, URL list: ['*.is'] , UUID: 9fec3734-bf74-43b9-4321-aefdacf912ad
URL category name: Norwegian_websites, URL list: ['*.no'] , UUID: b3939705-2c0a-434f-4321-30a7a4379068

Addresses

In the previous article, we have created a few address objects. Let’s see if we can fetch them!

from scm.client import Scm
from scm.config.objects import Address


CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'

api_client = Scm(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    tsg_id=TSG_ID,
)

address_instance = Address(api_client)

addresses = address_instance.list(folder='All', exact_match=True)

for address in addresses:
    address_value = address.ip_netmask or address.ip_range or address.ip_wildcard
    print(f'Address name: {address.name}, address value: {address_value}, UUID: {address.id}')

Besides the standard workflow, in the printing loop, we have one more step – we’re fetching the address_value. In the SCM there are multiple types of address objects, so if we want to have a common message with the address value, we need to fetch it according to the processed object. Model definitions for addresses are available here.

Address name: Palo Alto Networks Sinkhole, address value: None, UUID: 05f1afdc-bbf9-4f00-4321-895b87b25ebe
Address name: Reykjavik, address value: 10.0.0.1/24, UUID: a0811d90-0d42-40aa-4321-e1bed7422c42
Address name: Keflavik, address value: 10.0.1.1/24, UUID: 17250605-8f94-4754-4321-813838b2b245
Address name: Akureyri, address value: 10.0.2.1/24, UUID: c1fa7aec-869b-4d44-4321-a7ae95121ec1
Address name: Oslo, address value: 10.1.0.1/24, UUID: 0320e489-16fa-46c4-4321-869d36966deb
Address name: Bergen, address value: 10.1.1.1/24, UUID: f9d5f566-bab4-4510-4321-689c49a5ef7b
Address name: Tromso, address value: 10.1.2.1/24, UUID: 4e980b9e-29d0-4b05-4321-2ae5aab829e7

Address Groups

After addresses, it’s time for address groups. Let’s fetch them!

from scm.client import Scm
from scm.config.objects import AddressGroup


CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'

api_client = Scm(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    tsg_id=TSG_ID,
)

address_group_instance = AddressGroup(api_client)

address_groups = address_group_instance.list(folder='All', exact_match=True)

for address_group in address_groups:
    print(
        f'Address name: {address_group.name}, static values: {address_group.static}, UUID: {address_group.id}',
    )

The structure is similar to the previous examples. Here’s the definition of address object models.

Address group name: Icelandic_addresses, static values: ['Reykjavik', 'Keflavik', 'Akureyri'], UUID: b04bb128-094c-44f1-4321-957b10786598
Address group name: Norwegian_addresses, static values: ['Oslo', 'Bergen', 'Tromso'], UUID: 6de716c2-2ed2-4640-4321-9a48f60135d9

Security Rules

It’s time for the security rules, but this time, we will dive a bit deeper into collection methods.

from scm.client import Scm
from scm.config.security import SecurityRule


FOLDER = 'All'
RULEBASE = 'pre'

CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'

api_client = Scm(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    tsg_id=TSG_ID,
)

security_rule_instance = SecurityRule(api_client)

print(f'All security rules from the "{RULEBASE}" rulebase:')
security_rules = security_rule_instance.list(folder=FOLDER, rulebase=RULEBASE, exact_match=True)
print(f'Number of security rules - {len(security_rules)}')
for security_rule in security_rules:
    print(f'Name - {security_rule.name}')


print('\n\nFiltered security rules with tag "International":')
filters = {
    'tag': ['International'],
}
security_rules = security_rule_instance.list(folder=FOLDER, rulebase=RULEBASE, exact_match=True, **filters)
print(f'Number of security rules - {len(security_rules)}')
for security_rule in security_rules:
    print(f'Name - {security_rule.name}')


print('\n\nFiltered security rules with tag "International" and source "Oslo":')
filters = {
    'tag': ['International'],
    'source': ['Oslo'],
}
security_rules = security_rule_instance.list(folder=FOLDER, rulebase=RULEBASE, exact_match=True, **filters)
print(f'Number of security rules - {len(security_rules)}')
for security_rule in security_rules:
    print(f'Name - {security_rule.name}')


print('\n\nFiltered security rules with service set to "service-http":')
security_rules = security_rule_instance.list(
    folder=FOLDER,
    rulebase=RULEBASE,
    exact_match=True,
    service=['service-http'],
)
print(f'Number of security rules - {len(security_rules)}')
for security_rule in security_rules:
    print(f'Name - {security_rule.name}')

In the beginning, we’re collecting all security rules from the All folder and pre rulebase. Rulebase is key here, for each action, we need to specify if we want rules from the pre or post rulebase.

The complete structure of collected security rules is following.

{'name': 'default', 'disabled': False, 'description': None, 'tag': [], 'from_': ['any'], 'source': ['any'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['any'], 'destination': ['any'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': None, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('c9301af1-a15f-4afc-4321-74182ca6f503')}
{'name': 'Web-Security-Default', 'disabled': False, 'description': None, 'tag': [], 'from_': ['any'], 'source': ['any'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['any'], 'destination': ['any'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': None, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('d00d2d9f-077d-4054-4321-53bb52357f36')}
{'name': 'hip-default', 'disabled': False, 'description': None, 'tag': [], 'from_': ['any'], 'source': ['any'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['any'], 'destination': ['any'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': None, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('b44446b6-0da7-41b5-4321-b9954dff3833')}
{'name': 'Allow-Icelandic-websites', 'disabled': False, 'description': 'Allow websites with Icelandic domain', 'tag': ['International'], 'from_': ['Norway'], 'source': ['Norwegian_addresses'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['Iceland'], 'destination': ['Icelandic_addresses'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['service-http', 'service-https'], 'category': ['Icelandic_websites'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': {'group': ['best-practice']}, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('a001657f-06c7-4c5e-4321-74d85f286eb0')}
{'name': 'Allow-Norwegian-websites', 'disabled': False, 'description': 'Allow websites with Norwegian domain', 'tag': ['International'], 'from_': ['Iceland'], 'source': ['Icelandic_addresses'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['Norway'], 'destination': ['Norwegian_addresses'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['service-http', 'service-https'], 'category': ['Norwegian_websites'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': {'group': ['best-practice']}, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('1b909438-c3f8-428d-4321-515024acfc7c')}
{'name': 'Deny-Keflavik-to-Akureyri', 'disabled': False, 'description': 'Deny all traffic from Keflavik to Akureyri', 'tag': ['Domestic'], 'from_': ['Iceland'], 'source': ['Keflavik'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['Iceland'], 'destination': ['Akureyri'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.deny: 'deny'>, 'profile_setting': None, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('ad9c79ad-7cd1-4ac7-4321-91095670a652')}
{'name': 'Deny-ssl-from-Bergen-to-Tromso', 'disabled': False, 'description': 'Deny ssl traffic from Bergen to Tromso', 'tag': ['Domestic'], 'from_': ['Norway'], 'source': ['Bergen'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['Norway'], 'destination': ['Tromso'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['ssl'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.deny: 'deny'>, 'profile_setting': None, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('772ce007-456f-4d03-4321-96c0bef8b466')}
{'name': 'Allow-Oslo-to-Reykjavik', 'disabled': False, 'description': 'Allow traffic from Oslo to Reykjavik', 'tag': ['International'], 'from_': ['Norway'], 'source': ['Oslo'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['Iceland'], 'destination': ['Reykjavik'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': {'group': ['best-practice']}, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('19efa09f-9579-475c-4321-bd5174c09933')}
{'name': 'Allow-Reykjavik-to-Oslo', 'disabled': False, 'description': 'Allow traffic from Reykjavik to Oslo', 'tag': ['International'], 'from_': ['Iceland'], 'source': ['Reykjavik'], 'negate_source': False, 'source_user': ['any'], 'source_hip': ['any'], 'to_': ['Norway'], 'destination': ['Oslo'], 'negate_destination': False, 'destination_hip': ['any'], 'application': ['any'], 'service': ['any'], 'category': ['any'], 'action': <SecurityRuleAction.allow: 'allow'>, 'profile_setting': {'group': ['best-practice']}, 'log_setting': None, 'schedule': None, 'log_start': None, 'log_end': None, 'folder': 'All', 'snippet': None, 'device': None, 'id': UUID('0c3dc167-59e6-4a14-4321-d9a6dffffe1b')}

The output of the print loop is as follows.

All security rules from the "pre" rulebase:
Number of security rules - 9
Name - default
Name - Web-Security-Default
Name - hip-default
Name - Allow-Icelandic-websites
Name - Allow-Norwegian-websites
Name - Allow-Oslo-to-Reykjavik
Name - Deny-Keflavik-to-Akureyri
Name - Deny-ssl-from-Bergen-to-Tromso
Name - Allow-Reykjavik-to-Oslo

If we just want to list all the rules, that’s it, but there is also an option to already filter fetched rules.

In the first example, we want to collect only rules with the tag International. We’re saving this filter into a filters dictionary, and then it’s passed to the list method.

The effect is as follows.

Filtered security rules with tag "International":
Number of security rules - 4
Name - Allow-Icelandic-websites
Name - Allow-Norwegian-websites
Name - Allow-Oslo-to-Reykjavik
Name - Allow-Reykjavik-to-Oslo

We can also add more conditions to the filters. In the second example, we want only rules with the tag International and source set to Oslo. Both conditions are present in the filters dictionary.

Filtered security rules with tag "International" and source "Oslo":
Number of security rules - 1
Name - Allow-Oslo-to-Reykjavik

The last example is about fetching rules with service set to service-http. This time we’re directly passing the service value into the list method.

Filtered security rules with service set to "service-http":
Number of security rules - 2
Name - Allow-Icelandic-websites
Name - Allow-Norwegian-websites
Share

Leave a Reply

Your email address will not be published. Required fields are marked *