한번에 모든 보안 그룹에 규칙 추가하기

한번에 모든 보안 그룹에 규칙 추가하기

복수의 AWS 보안 그룹에 한번에 규칙을 추가하는 코드에 대해 기재한 글입니다.
2025.08.26

안녕하세요 클래스메소드의 이수재입니다.

Client VPN을 도입해서 모든 보안 그룹에 일정한 규칙을 추가하는 등 가끔 모든 보안 그룹에 일정한 규칙을 추가하는 작업이 발생할 때가 있습니다.

보안 그룹이 몇 개 되지 않는다면 문제가 없지만 몇십 몇백 개의 보안 그룹이 있다면 하나하나 손으로 추가하기에는 여러모로 비효율적입니다.

이런 경우를 위해서 파이썬 코드를 만들어보았습니다.

코드부터

코드
#!/usr/bin/env python3

import csv
import boto3
import botocore
import sys

def add_security_group_rules(sg_file, rules_file):
    """
    보안 그룹 추가

    Args:
        sg_file: 보안 그룹 목록 csv 파일
        rules_file: 추가하려는 규칙 csv 파일
    """

    # AWS EC2 클라이언트 초기화
    try:
        ec2 = boto3.client("ec2")
    except Exception as e:
        print(f"AWS 에러 : {e}")
        return False

    # 보안 그룹 목록 읽기
    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"보안 그룹 {len(sg_dict)} 개를 확인")
    except Exception as e:
        print(f"보안 그룹 읽기 실패 : {e}")
        return False

    # 규칙 읽기 추가
    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", "")

                # 보안 그룹 ID 확인
                if sg_name not in sg_dict:
                    print(f"다음 보안 그룹 이름의 확인 실패 : {sg_name}")
                    error_count += 1
                    continue

                sg_id = sg_dict[sg_name]

                # 규칙 추가
                if add_rule(
                    ec2,
                    sg_id,
                    direction,
                    protocol,
                    from_port,
                    to_port,
                    cidr,
                    description,
                ):
                    print(
                        f"규칙 추가 성공 : {sg_name} ({direction}) {protocol}:{from_port}-{to_port} {cidr}"
                    )
                    success_count += 1
                else:
                    error_count += 1

    except Exception as e:
        print(f"규칙 파일 읽기 실패 : {e}")
        return False

    print(f"\n결과: 성공 {success_count} 개, 에러 {error_count} 개")
    return error_count == 0

def add_rule(ec2, sg_id, direction, protocol, from_port, to_port, cidr, description):
    """
    개별 규칙을 추가
    """
    try:
        # IP
        ip_permission = {
            "IpProtocol": protocol,
            "IpRanges": [{"CidrIp": cidr, "Description": description}],
        }

        # 포트 지정이 있는 경우
        if from_port is not None:
            ip_permission["FromPort"] = from_port
        if to_port is not None:
            ip_permission["ToPort"] = to_port

        # 인바운드 혹은 아웃바운드 규칙 추가
        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"잘못된 설정 : {direction}")
            return False

        return True

    except botocore.exceptions.ClientError as e:
        error_code = e.response["Error"]["Code"]
        if error_code == "InvalidPermission.Duplicate":
            print(f"다음 그룹에 이미 동일한 규칙이 있습니다 : {sg_id}")
            return True  # 동일한 기존 규칙이 있다면 성공으로 간주
        else:
            print(f"규칙 추가 에러 ({sg_id}): {e}")
            return False
    except Exception as e:
        print(f"이 외의 에러 ({sg_id}): {e}")
        return False

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

    print("AWS 보안 그룹에 규칙 추가 개시")
    success = add_security_group_rules(sg_file, rules_file)

    if success:
        print("모든 규칙이 추가 성공")
    else:
        print("일부 규칙이 추가 되지 않았음")
        sys.exit(1)

if __name__ == "__main__":
    main()

사용 방법

실행하기 위해서는 대상 보안 그룹을 정리한 보안 그룹 csv 파일과 추가할 규칙이 적힌 csv 파일이 필요합니다.

보안 그룹 csv

샘플은 아래와 같습니다.

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

보안 그룹을 csv로 정리하는 방법은 간단합니다.

우선 aws 콘솔에서 보안 그룹 페이지에 액세스합니다.
그리고 다음과 같이 필요한 보안 그룹을 체크하고 「보안 그룹을 CSV로 내보내기」 로 한번에 csv로 출력할 수 있습니다.
출력된 csv의 그룹 이름, id 의 열을 그대로 별도의 csv 파일로 복사하여 사용하면 됩니다.

규칙 csv

샘플은 아래와 같습니다.

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

이 csv 파일은 직접 작성해야합니다.
하나의 csv 파일에 여러 개의 그룹을 대상으로 실행할 수도 있고, 인바운드나 아웃바운드 양쪽을 추가할 수도 있습니다.

실행하기

csv 파일이 준비되었다면 다음 명령어로 코드를 실행합니다.

# python {코드 파일 이름}.py {보안 그룹 csv} {규칙 csv}
$ python test.py sg.csv rules.csv

문제 없이 실행되면 아래와 같이 출력됩니다.

python3 test.py sg.csv sgrules.csv
AWS 보안 그룹에 규칙 추가 개시
보안 그룹 2 개를 확인
규칙 추가 성공 : clientvpntestsg (inbound) tcp:80-80 219.255.147.112/32
규칙 추가 성공 : testsg (inbound) tcp:443-443 219.255.147.112/32

결과: 성공 2 개, 에러 0 개
모든 규칙이 추가 성공

마무리

실제로 사용할 일이 있어서 만들어보았는데 이 글을 읽는 분들에게 도움이 되면 좋겠네요.

긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 must01940 지메일로 보내주시면 감사합니다.

문의 사항은 클래스메소드코리아로!

클래스메소드코리아에서는 다양한 세미나 및 이벤트를 진행하고 있습니다.
진행중인 이벤트에 대해 아래 페이지를 참고해주세요.

https://classmethod.kr/board/library

AWS에 대한 상담 및 클래스메소드 멤버스에 관한 문의사항은 아래 메일로 연락주시면 감사드립니다!
Info@classmethod.kr

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.