Update existing security list ingress rules in OCI with the python SDK
Azeez Lukman
Posted on August 19, 2022
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 egressSecurityRules
or 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
Next, create the file to write the python script using the command below:
touch oci-ingress-sl-update.py
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
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)
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"
-
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
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
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))
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)
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
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)
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'])
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]
))
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
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.
Posted on August 19, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.