Adding rules to all security groups at once

Adding rules to all security groups at once

This is a post about code for adding rules to multiple AWS security groups at once.
2025.08.26

Hello, I'm Lee Sujae from Classmethod.

Sometimes there are cases when you need to add certain rules to all security groups, such as when implementing Client VPN.

If you only have a few security groups, this isn't a problem, but if you have dozens or hundreds of security groups, adding rules to each one manually becomes inefficient in many ways.

For these cases, I've created a Python code.

AI: I've translated the text while maintaining the original Markdown formatting. The translation preserves the exact structure and paragraph breaks of the original Korean text.## Code first

Code
			
			#!/usr/bin/env python3

import csv
import boto3
import botocore
import sys

def add_security_group_rules(sg_file, rules_file):
    """
    Add security group

    Args:
        sg_file: Security group list csv file
        rules_file: Rules to add csv file
    """

    # Initialize AWS EC2 client
    try:
        ec2 = boto3.client("ec2")
    except Exception as e:
        print(f"AWS error : {e}")
        return False

    # Read security group list
    sg_dict = {}
    try:
        with open(sg_file, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                sg_dict[row["GroupName"]] = row["GroupId"]
        print(f"Confirmed {len(sg_dict)} security groups")
    except Exception as e:
        print(f"Failed to read security groups : {e}")
        return False

    # Read and add rules
    success_count = 0
    error_count = 0

    try:
        with open(rules_file, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                sg_name = row["sg_name"]
                direction = row["direction"]
                protocol = row["protocol"]
                from_port = int(row["from_port"]) if row["from_port"] else None
                to_port = int(row["to_port"]) if row["to_port"] else None
                cidr = row["cidr"]
                description = row.get("description", "")

                # Check security group ID
                if sg_name not in sg_dict:
                    print(f"Failed to find security group with name : {sg_name}")
                    error_count += 1
                    continue

                sg_id = sg_dict[sg_name]

                # Add rule
                if add_rule(
                    ec2,
                    sg_id,
                    direction,
                    protocol,
                    from_port,
                    to_port,
                    cidr,
                    description,
                ):
                    print(
                        f"Rule added successfully : {sg_name} ({direction}) {protocol}:{from_port}-{to_port} {cidr}"
                    )
                    success_count += 1
                else:
                    error_count += 1

    except Exception as e:
        print(f"Failed to read rules file : {e}")
        return False

    print(f"\nResults: {success_count} successful, {error_count} errors")
    return error_count == 0

def add_rule(ec2, sg_id, direction, protocol, from_port, to_port, cidr, description):
    """
    Add individual rule
    """
    try:
        # IP
        ip_permission = {
            "IpProtocol": protocol,
            "IpRanges": [{"CidrIp": cidr, "Description": description}],
        }

        # If port specification exists
        if from_port is not None:
            ip_permission["FromPort"] = from_port
        if to_port is not None:
            ip_permission["ToPort"] = to_port

        # Add inbound or outbound rule
        if direction.lower() == "inbound":
            ec2.authorize_security_group_ingress(
                GroupId=sg_id, IpPermissions=[ip_permission]
            )
        elif direction.lower() == "outbound":
            ec2.authorize_security_group_egress(
                GroupId=sg_id, IpPermissions=[ip_permission]
            )
        else:
            print(f"Invalid setting : {direction}")
            return False

        return True

    except botocore.exceptions.ClientError as e:
        error_code = e.response["Error"]["Code"]
        if error_code == "InvalidPermission.Duplicate":
            print(f"The same rule already exists in this group : {sg_id}")
            return True  # Consider it successful if identical rule already exists
        else:
            print(f"Error adding rule ({sg_id}): {e}")
            return False
    except Exception as e:
        print(f"Other error ({sg_id}): {e}")
        return False

def main():
    sg_file = sys.argv[1]
    rules_file = sys.argv[2]

    print("Starting addition of rules to AWS security groups")
    success = add_security_group_rules(sg_file, rules_file)

    if success:
        print("All rules added successfully")
    else:
        print("Some rules were not added")
        sys.exit(1)

if __name__ == "__main__":
    main()
```## How to Use
To run this, you need a security group CSV file that lists the target security groups and a CSV file containing the rules to be added.

### Security Group CSV
The sample is as follows:

```csv
GroupId,GroupName
sg-0d499fcd31e37bb14,clientvpntestsg
sg-0094e1017a3411dd6,testsg

		

Creating a CSV of security groups is simple.

First, access the security group page in the AWS console.
Then, check the necessary security groups as shown and click "Export security groups to CSV" to output them all at once.
You can use the group name and ID columns from the exported CSV by copying them directly into a separate CSV file.

Rules CSV

The sample is as follows:

			
			sg_name,direction,protocol,from_port,to_port,cidr,description
clientvpntestsg,inbound,tcp,80,80,219.255.147.112/32,HTTP access
testsg,inbound,tcp,443,443,219.255.147.112/32,HTTPS access

		

You need to create this CSV file yourself.
You can target multiple groups in a single CSV file, and add both inbound and outbound rules.

Execution

Once the CSV files are ready, run the code with the following command:

			
			# python {code file name}.py {security group csv} {rules csv}
$ python test.py sg.csv rules.csv

		

If it runs without issues, you'll see output like this:

			
			python3 test.py sg.csv sgrules.csv
AWS security group rule addition started
2 security groups confirmed
Rule addition successful: clientvpntestsg (inbound) tcp:80-80 219.255.147.112/32
Rule addition successful: testsg (inbound) tcp:443-443 219.255.147.112/32

Results: 2 successful, 0 errors
All rules added successfully

		

Conclusion

I created this because I needed it for actual use, and I hope it helps those reading this article.

Thank you for reading this long post.
Please send any typos or content feedback to must01940 gmail.

For inquiries, contact Classmethod Korea!

Classmethod Korea conducts various seminars and events.
Please refer to the page below for ongoing events.

https://classmethod.kr/board/library

For AWS consultations and inquiries about Classmethod Members, please contact us at:
Info@classmethod.kr

Share this article

FacebookHatena blogX

Related articles