I love to create new objects with the automation scripts. It makes me feel productive, because with a short amount of time, I’m able to create a large amount of objects, and it’s so rewarding to see them appear in the UI.
In this article, we will go through the process of creating a different types of objects in the Strata Cloud Manager, but of course with the help of automation! Python is a great programming language for the automation, so we will go with it today.
This article has also a theme – Scandinavia, so prepare for a trip to the beautiful regions of Iceland and Norway!
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!
Automatic object creation with Python
What we want to achieve today is to create a few security rules, but before we dive into it, we need to create other objects, that will be attached later on to the security rules.
The plan for today is to create the following objects:
- Tags
- URL Categories
- Addresses
- Address Groups
- Security Rules
Each object in SCM is placed in a folder. For this article, I decided to put all of the created objects in the Global folder.
Before we start our objects factory, let’s take a look at the way we can interact with the Strata Cloud Manager.
Strata Cloud Manager connector
To interact with the Strata Cloud Manager, we need to create a Scm type object. The constructor of this class requires those arguments:
- Client ID
- Client Secret
- Tenant ID
If you don’t know how you can get those, make sure to check my article on how to prepare your SCM for automation.
Putting it all together looks as follows.
from scm.client import Scm
from scm.config.objects import Tag
FOLDER = 'All'
CLIENT_ID = 'ServiceAccountClientIDGoesHere'
CLIENT_SECRET = 'ServiceAccountClientSecretGoesHere'
TSG_ID = 'TenantIDGoesHere'
api_client = Scm(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
tsg_id=TSG_ID,
)
It’s our base for all object-creating scripts that we will use. Let’s start then!
Tags
Let’s create two tags:
- Domestic – Blue
- International – Red
We will use them to mark security rules.
Let’s take a look at the code.
from scm.client import Scm
from scm.config.objects import Tag
FOLDER = 'All'
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_data = [
{
'name': 'Domestic',
'color': 'Blue',
'comments': 'Tag for domestic traffic',
'folder': FOLDER,
},
{
'name': 'International',
'color': 'Red',
'comments': 'Tag for international traffic',
'folder': FOLDER,
},
]
for tag_data in tags_data:
response = tag_instance.create(tag_data)
print(f'Created tag {response.name}, UUID {response.id}')
All code snippets from this article are pushed to the scm-automation-examples repository.
First of all, after imports we have a FOLDER variable. I’ve mentioned earlier, that all objects will be created in a Global folder, but you may wonder why in the code the folder has value of All.
The answer is simple – there are special folders in the SCM that have different names in the Web UI and in the back-end API. Global is a name that we can see in the Web UI, but the SCM API recognizes it under value of All.
After the folder definition we have a code snipped with the creation of SCM connector, which was described earlier.
To perform any operation with tag objects, we need to create a Tag class object. It’s present in the code under the tag_instance variable. During the creation, we’re passing a Scm connector object as an argument. After the creation, we’re ready to perform actions on tags.
Now, to create tags, we need to place data about those tags in the script. Variable tags_data is a list of dictionaries. Each dictionary is a definition of one tag. We can define multiple attributes, in this case, we’re defining four of them:
- Name
- Color
- Comment
- Folder
You may ask – How do I know what parameters can I define?
That’s a valid question! Sometimes we have documentation that we can look into, but not in this case. No documentation means that we need to look directly into the library code. If you’re curious about what other parameters you can define, take a look at the TagBaseModel class definition in this file.
The last piece of code iterates through the list of defined tags, and for each, the create method from the tags_instance is called.
As a result of running the script, we’re getting information about created tags, and the created objects UUID. In the SCM, freshly created tags look like this.
And that’s it for tags, let’s move on to the URL categories!
URL Categories
When it comes to URL Categories, we want two of them:
- Icelandic_websites – matching .is domains
- Norwegian_websites – matching .no domains
Let’s dive into the code.
from scm.client import Scm
from scm.config.security import URLCategories
from scm.models.security.url_categories import URLCategoriesListTypeEnum
FOLDER = 'All'
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_data = [
{
'name': 'Icelandic_websites',
'description': 'Websites with Icelandic domains',
'type': URLCategoriesListTypeEnum.url_list,
'list': ['*.is'],
'folder': FOLDER,
},
{
'name': 'Norwegian_websites',
'description': 'Websites with Norwegian domains',
'type': URLCategoriesListTypeEnum.url_list,
'list': ['*.no'],
'folder': FOLDER,
},
]
for url_category_data in url_categories_data:
response = url_category_instance.create(url_category_data)
print(f'Created URL category {response.name}, UUID {response.id}')
The majority is very similar to the Tags. Main difference is with the url_category_instance, this time we’re using different class to create an instance object.
Before we execute the create method, we need to have data for it. Once again we have a list of dictionaries. If you’re curious what parameters you can pass for URL Categories, take a look at the URLCategoriesBaseModel here.
After the execution, we can see the two custom URL Categories.
Addresses
For the addresses, we need more than just two objects as it was with tags and URL Categories. In the topology, we’re covering two countries – Iceland and Norway. For each country, we will have three cities. Iceland will have Reykjavik, Keflavik and Akureyri. Norway on the other hand, Oslo, Bergen, and Tromso. Each city will have a unique IP address.
from scm.client import Scm
from scm.config.objects import Address
FOLDER = 'All'
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_data = [
{
'name': 'Reykjavik',
'description': 'Reykjavik IP address',
'ip_netmask': '10.0.0.1/24',
'folder': FOLDER,
},
{
'name': 'Keflavik',
'description': 'Keflavik IP address',
'ip_netmask': '10.0.1.1/24',
'folder': FOLDER,
},
{
'name': 'Akureyri',
'description': 'Akureyri IP address',
'ip_netmask': '10.0.2.1/24',
'folder': FOLDER,
},
{
'name': 'Oslo',
'description': 'Oslo IP address',
'ip_netmask': '10.1.0.1/24',
'folder': FOLDER,
},
{
'name': 'Bergen',
'description': 'Bergen IP address',
'ip_netmask': '10.1.1.1/24',
'folder': FOLDER,
},
{
'name': 'Tromso',
'description': 'Tromso IP address',
'ip_netmask': '10.1.2.1/24',
'folder': FOLDER,
},
]
for address_data in addresses_data:
response = address_instance.create(address_data)
print(f'Created address {response.name}, UUID {response.id}')
As you can see, the code is very similar to the previous examples. Here is the definition of AddressBaseModel.
The result looks like this.
Address Groups
Let’s create two address groups, one for Icelandic addresses, and the second for Norwegian addresses. In each, we will have addresses from the cities of the specified country.
from scm.client import Scm
from scm.config.objects import AddressGroup
FOLDER = 'All'
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_data = [
{
'name': 'Icelandic_addresses',
'description': 'Addresses from Iceland',
'static': ['Reykjavik', 'Keflavik', 'Akureyri'],
'folder': FOLDER,
},
{
'name': 'Norwegian_addresses',
'description': 'Addresses from Norway',
'static': ['Oslo', 'Bergen', 'Tromso'],
'folder': FOLDER,
},
]
for address_group_data in address_groups_data:
response = address_group_instance.create(address_group_data)
print(f'Created address group {response.name}, UUID {response.id}')
AddressGroupBaseModel definition is available here.
Groups present themselves in SCM in the following way.
It’s time for the grand finale, the security rules!
Security Policies
Since we have two countries, let’s create some rules so we can allow and block some traffic. Here’s a brief description of the created rules:
- Allow Norwegian/Icelandic websites – in those rules, we will use our address groups and URL categories
- Deny-Akureyri-to-Keflavik – basic deny rule between two sites
- Deny-ssl-from-Bergen-to-Tromso – here we’re specifying that we’re blocking just an ssl application
- Allow traffic between Reykjavik and Oslo – basic permit rule between two sites
For each allow rule we’re adding a best-practice security profile.
Let’s take a glance at the code.
from scm.client import Scm
from scm.config.security import SecurityRule
from scm.models.security.security_rules import SecurityRuleAction, SecurityRuleProfileSetting
FOLDER = 'All'
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)
security_rules_data = [
{
'name': 'Allow-Icelandic-websites',
'disabled': False,
'tag': 'International',
'from_': 'Norway',
'source': ['Norwegian_addresses'],
'source_user': ['any'],
'to_': 'Iceland',
'destination': ['Icelandic_addresses'],
'application': ['any'],
'service': ['service-http', 'service-https'],
'category': ['Icelandic_websites'],
'action': SecurityRuleAction.allow,
'profile_setting': SecurityRuleProfileSetting(group=['best-practice']),
'description': 'Allow websites with Icelandic domain',
'rulebase': 'pre',
'folder': FOLDER,
},
{
'name': 'Allow-Norwegian-websites',
'disabled': False,
'tag': 'International',
'from_': 'Iceland',
'source': ['Icelandic_addresses'],
'source_user': ['any'],
'to_': 'Norway',
'destination': ['Norwegian_addresses'],
'application': ['any'],
'service': ['service-http', 'service-https'],
'category': ['Norwegian_websites'],
'action': SecurityRuleAction.allow,
'profile_setting': SecurityRuleProfileSetting(group=['best-practice']),
'description': 'Allow websites with Norwegian domain',
'rulebase': 'pre',
'folder': FOLDER,
},
{
'name': 'Deny-Keflavik-to-Akureyri',
'disabled': False,
'tag': 'Domestic',
'from_': 'Iceland',
'source': ['Keflavik'],
'source_user': ['any'],
'to_': 'Iceland',
'destination': ['Akureyri'],
'application': ['any'],
'service': ['any'],
'category': ['any'],
'action': SecurityRuleAction.deny,
'description': 'Deny all traffic from Keflavik to Akureyri',
'rulebase': 'pre',
'folder': FOLDER,
},
{
'name': 'Deny-ssl-from-Bergen-to-Tromso',
'disabled': False,
'tag': 'Domestic',
'from_': 'Norway',
'source': ['Bergen'],
'source_user': ['any'],
'to_': 'Norway',
'destination': ['Tromso'],
'application': ['ssl'],
'service': ['any'],
'category': ['any'],
'action': SecurityRuleAction.deny,
'description': 'Deny ssl traffic from Bergen to Tromso',
'rulebase': 'pre',
'folder': FOLDER,
},
{
'name': 'Allow-Oslo-to-Reykjavik',
'disabled': False,
'tag': 'International',
'from_': 'Norway',
'source': ['Oslo'],
'source_user': ['any'],
'to_': 'Iceland',
'destination': ['Reykjavik'],
'application': ['any'],
'service': ['any'],
'category': ['any'],
'action': SecurityRuleAction.allow,
'profile_setting': SecurityRuleProfileSetting(group=['best-practice']),
'description': 'Allow traffic from Oslo to Reykjavik',
'rulebase': 'pre',
'folder': FOLDER,
},
{
'name': 'Allow-Reykjavik-to-Oslo',
'disabled': False,
'tag': 'International',
'from_': 'Iceland',
'source': ['Reykjavik'],
'source_user': ['any'],
'to_': 'Norway',
'destination': ['Oslo'],
'application': ['any'],
'service': ['any'],
'category': ['any'],
'action': SecurityRuleAction.allow,
'profile_setting': SecurityRuleProfileSetting(group=['best-practice']),
'description': 'Allow traffic from Reykjavik to Oslo',
'rulebase': 'pre',
'folder': FOLDER,
},
]
for security_rule_data in security_rules_data:
response = security_rule_instance.create(security_rule_data)
print(f'Created security rule {response.name}, UUID {response.id}')
While the logic remains similar, we have a huge list with definitions of our security policies. What’s worth mentioning here is the rulebase. Each rule will be placed in the pre rulebase, but that can be modified to post by changing the value for the key rulebase. Also, the action key contains a special enum imported from the security rules module.
Here’s the definition of SecurityRuleBaseModel.
After execution, the SCM has the following security rules.
The complex structure of security rules
As you can see, to build a security rule, we first have to create some other objects inside Strata Cloud Manager. Only after that we can refer them in our policies. It may seem a bit overwhelming at first, but I’m sure you’ll be able to create your own code referring to the snippets attached to this article!