DEV Community

Cover image for Update existing security list ingress rules in OCI with the python SDK
Azeez Lukman
Azeez Lukman

Posted on

Update existing security list ingress rules in OCI with the python SDK

Prerequisites

  • Some knowledge about python programming language
  • OCI SDK for python. please check here to install it, if you do not have it.

💡 Feel free to follow along with from this GitHub repository

Introduction

Security lists are components of your VCN that are responsible for allowing traffic in and out of the VCN, they act like firewalls and are applied to the VNICs of your subnets or VCN. You specify the types of traffic allowed in and out with ingress and egress rules respectively.

As your VCN grows in complexity, there could be a need to update the security rules of your security list, this is fairly easy from the console but comes with a gotcha when using the API or SDK as stated in the documentation that egressSecurityRulesor ingressSecurityRules objects you provide replace the entire existing objects. This means you risk replacing the entire rules in an existing security list when you are making an update to an existing security list.

In this article, you would learn how to use the python SDK to update the rules of an existing security list in OCI without losing the existing rules of course.

Import oracle SDK

Let’s get started by preparing our environment and ensuring we have all that’s required to follow along this article.

The oracle python SDK provides the tools you need to interact with the Oracle Cloud Infrastructure using python, so let’s import the SDK module on the command line.

Run the command below in your terminal to install the oracle SDK:

pip3 install oci
Enter fullscreen mode Exit fullscreen mode

Next, create the file to write the python script using the command below:

touch oci-ingress-sl-update.py
Enter fullscreen mode Exit fullscreen mode

This would create a file named [oci-ingress-sl-update.py](http://oci-ingress-sl-update.py), feel free to update the file name.

Next, open the file you created in your favourite code editor, and the code below to import the oci SDK package:

import oci
Enter fullscreen mode Exit fullscreen mode

Authentication

You need to grant access to your tenancy, i would be authenticating using the instance principal, you can use other authentication methods as well:

config = oci.config.from_file()
identity_client = oci.identity.IdentityClient(config)
core_client = oci.core.VirtualNetworkClient(config)
Enter fullscreen mode Exit fullscreen mode

This gets the credentials from the identity file and store in config, oci.config.from_file() takes as arguments, one is for the config file location and the other tells it it to use the default config profile. passing empty arguments falls back to default values with the config file at ~/.oci/identity_file and the profile would be default.

We then use the config to authenticate the identity_client as well as the core_client which we would be using in a minute.

Next, we define the constants:

network_compartment_name = "network_compartment"
vcn_cidr_range = "10.104.0.0/16"
vcn_subnet_cidr_range = "10.103.225.0/28"
Enter fullscreen mode Exit fullscreen mode
  • network_compartment_name : The compartment that holds your network resources
  • vcn_cidr_range: The virtual network’s CIDR range
  • vcn_subnet_cidr_range: The Subnet’s CIDR range

Get compartment data

We would be making use of the compartment id later on. In order to get this, we filter through the list of all compartments and match the compartment that matches the network compartment declared earlier.

Add the following code to get your compartment id:

list_compartments_response = identity_client.list_compartments(
    compartment_id=config['tenancy'],
    lifecycle_state="ACTIVE")

for i in range(len(list_compartments_response.data)):
   if list_compartments_response.data[i].name == network_compartment_name:
     network_compartment_id = list_compartments_response.data[i].id
     break
Enter fullscreen mode Exit fullscreen mode

Now we have the compartment id network_compartment_id, the next step is to identify the VCN we would be working with within the compartment.

Add the following code to get the VCN data below your script:

list_vcns_response = core_client.list_vcns(
    compartment_id=network_compartment_id)

for vcn in range(len(list_vcns_response.data)):
    if list_vcns_response.data[vcn].cidr_block == vcn_cidr_range[0]:
        vcn_id = list_vcns_response.data[vcn].id
        vcn_name = list_vcns_response.data[vcn].display_name
Enter fullscreen mode Exit fullscreen mode

Here, we get the VCN name and id by filtering through the list of VCNs with the CIDR range declared earlier. You can also filter using the VCN name just like we did for the compartment, but i would be doing this way.

Now we have the compartment id and the VCN id, we use those details to get the VCNs security list. You would also need to specify the name of the security list since it’s possible to have multiple security lists in a VCN.

Go ahead and update your script with the following code to get your security list details:

list_security_lists_response = core_client.list_security_lists(
    compartment_id=network_compartment_id,
    vcn_id=vcn_id,
    display_name=sl_name,
 )

vcn_sl_id = list_security_lists_response.data[0].id

get_security_list_response = core_client.get_security_list(
    security_list_id=vcn_sl_id)

# get the current security list data
current_vcn_sl=json.loads(str(get_security_list_response.data.ingress_security_rules))
Enter fullscreen mode Exit fullscreen mode

We simply get the first security list that matches the display name we specified to list_security_lists. Using the id we get the ingress rules for the security list and store it as a json object in current_vcn_sl. The reason we’re getting the existing rules is so that we are able to include the existing rules along with the updates and not replace them.

💡 Remember, the idea is to update the ingress security rules

It would also be nice to keep track of what the security rules are before making the update, the last thing you want to do is mess up the entire control plane without being able to revert the changes.

The following code would write the security rules to a file named vcn_ingress_list.json file. Again, feel free to change the file name to whatever suits your use case. The file would be available on the same directory as your script file as soon as you run the script.

with open('vcn_ingress_list.json', "w") as f:
   json.dump(current_vcn_sl, f, ensure_ascii=False, indent=4)
Enter fullscreen mode Exit fullscreen mode

Create the security list rules

We have declared all the data we need and we’re ready to start effecting the updates.

The first thing you want to do is to declare the ingress security rules you want to update as a python object. i only have two rules to update to the VCN’s ingress security rules, these would tcp and imp connections on the VCN from the subnet.

Update your file with the following code, replacing the rules with yours. You can create another file to hold the rules if you have a lot more.

sl_update_rules=[{
        'description': 'lcm_scan subnet cidr',
        'source': vcn_subnet_cidr_range,
        'source_type': 'CIDR_BLOCK',
        'icmp_options': None,
                'tcp_options': None,
        'is_stateless': False,
        'protocol': '6',
        'udp_options': None
      },{
        'description': 'lcm_scan subnet cidr',
        'source': vcn_subnet_cidr_range,
        'source_type': 'CIDR_BLOCK',
        'icmp_options': None,
                'tcp_options': None,
        'is_stateless': False,
        'protocol': '1',
        'udp_options': None
      }
]

sl_update_rules = current_vcn_sl_rules + sl_update_rules
Enter fullscreen mode Exit fullscreen mode

Notice how we concatenate the current security rules with the update, that way we include the existing rules with the rules to deploy.

We also write out the new security list rules in another file named sl_update_rules.json:

# write out the new security list data
with open('sl_update_rules.json', "w") as f:
   json.dump(sl_update_rules, f, ensure_ascii=False, indent=4)
Enter fullscreen mode Exit fullscreen mode

The API to update the security list doesn’t expect a JSON object, let’s create a function to update the rules into something the API expects using IngressSecurityRule, this function would be called for every one of the rules.

Add the makeIngressRules function below to your file:

def makeIngressRules(t):
    oci.core.models.IngressSecurityRule(
        source=t['source'],
        protocol=t['protocol'],
        source_type=t['source_type'],
        is_stateless=False,
        description=t['description'])
Enter fullscreen mode Exit fullscreen mode

Update Security Rules

Finally, we’re ready to deploy the new rules live. Update your code to reflect the method to make the call to update the security list:

print("Updating "+vcn_sl_id)
core_client.update_security_list(
    security_list_id=vcn_sl_id,
    update_security_list_details=oci.core.models.UpdateSecurityListDetails(
        display_name=sl_display_name,
        ingress_security_rules=[makeIngressRules(t) for t in sl_update_rules]
))
Enter fullscreen mode Exit fullscreen mode

Basically, this says; hey here’s my security list id, i would like to update it’s ingress security rules to now reflect the following rules. This would then convert the JSON security rules update the ingress security rules on the control plane.

Go ahead and run the scripts with the following command:

python3 oci-ingress-sl-update.py
Enter fullscreen mode Exit fullscreen mode

Don’t forget to replace oci-ingress-sl-update.py with your filename including the file path. If everything goes well, the script should now update your ingress security rules and produce two JSON files, one containing the previous rules and the other one containing both the previous rules and the updates.

💡 Remember, the script for this article is available here

Conclusion

Congratulations, you have learnt how to programatically update your ingress security rules without replacing the entire control plane. You can also update the egress rules using the same approach.

Thanks for reading, don’t forget to like and share this article. Follow me on twitter and everywhere else @robogeek95.

Top comments (2)

Collapse
 
tarcisiomiranda profile image
Tarcisio Miranda • Edited

Hey man, what is "network_compartment_id", I got an error when executing part of the code:

CORE CLIENT <oci.core.virtual_network_client.VirtualNetworkClient object at 0x7f023b8046a0>
Traceback (most recent call last):
File "lib/api_oci.py", line 31, in <module>
compartment_id=network_compartment_id)
NameError: name 'network_compartment_id' is not defined

Collapse
 
tarcisiomiranda profile image
Tarcisio Miranda • Edited

I found the var:

network_compartment_id = compartment_id=config['tenancy']
Enter fullscreen mode Exit fullscreen mode