ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [AWS 자동화] 임시 등록 보안 규칙 IP 자동으로 삭제하기
    Infra 2025. 2. 21. 23:37

     

    배경

    1.  DEV 환경 서버 접속을 화이트리스트로 관리함

    2. 임시 등록된 IP 들이 점점 쌓이면서, 이를 수동으로 관리하는데 불편함을 느낌

     

    해결 전략

    임시 등록 IP 보안 규칙에 태그를 붙이고 이를 일괄 삭제할 수 있는 스크립트를 만들어야 겠다고 생각 함

     

    그러나 Boto3 Doc 를 찾아보니 아쉽게도 보안 그룹(DescribeSecurityGroups 객체)는 tag 를 제공하지만 내부 값으로 존재하는 보안 규칙(IpPermissions)에는 tag 값이 없었다.

     

    DescribeSecurityGroups 내부의 tag 필드

    그래도 다행히 IpPermissions 에서 Describtion 필드는 제공하고 있었기 때문에 규칙 추가시 Describtion 에 삭제할 날짜를 명시하는 것으로 전략 수정

     


     

    1. Lamda 를 통한 스크립트 배포

    - 보안 규칙은 AWS 내부 요소 이므로 접근성과 보안을 고려했을때 람다가이 좋겠다고 판단했다.

    - 스크립트 언어는 다양하게 지원하지만 비컴파일 언어만을 내부 에디터를 지원하고 있어 python 을 선택했다 (개인적으로 중간중간 로그도 찍어봐야해서 파이썬이나 js 를 추천한다 )

     

    배포 버튼 누르기는 필수!

     

    - 스크립트 작성완료 후 배포 하기 

    • 스크립트 배포 후 실제 적용까지 2-3 초 가량에 딜레이가 있는 듯 했다. (곧바로 테스트 진행할 경우 이전 스크립트로 실행됨을 목격)
    • 한동안 리액트 개발을 하며 핫 리로딩에 익숙해져 있었던 나머지 배포 버튼을 누르지 않는 실수를 몇번했다.....
    • 스크립트는 별 내용이 없지만 혹시나 필요한 사람을 위해 아래 첨부합니다
    더보기
    import boto3
    from datetime import datetime
    import re

     

    ec2 = boto3.client('ec2')

     

    def lambda_handler(event, context):
    print("Lambda function started")

     

    today = datetime.utcnow().date()
    print(f"Today's date: {today}")
     
    try:
    response = ec2.describe_security_groups()
    print(f"Found {len(response['SecurityGroups'])} security groups")

     

    for sg in response['SecurityGroups']:
    sg_id = sg['GroupId']
    print(f"Checking security group: {sg_id}")
     
    if sg.get('IpPermissions'):
    for permission in sg['IpPermissions']:
    print("---- Entering Security Rule ----")
    print(f"Permission details: {permission}")
     
    for ip_range in permission.get('IpRanges', []):
    description = ip_range.get('Description', '')
    print(f"Found rule description: {description}")
     
    match = re.search(r'exp:(\d{4}-\d{2}-\d{2})', description)
    if match:
    exp_date_str = match.group(1)
    print(f"Extracted exp date: {exp_date_str}")
     
    try:
    exp_date = datetime.strptime(exp_date_str, '%Y-%m-%d').date()
    print(f"Parsed exp date: {exp_date}")
     
    if exp_date < today:
    print(f"Deleting expired inbound rule in SG: {sg_id}")
    ec2.revoke_security_group_ingress(
    GroupId=sg_id,
    IpPermissions=[permission]
    )
    except ValueError as ve:
    print(f"Invalid date format in 'exp' tag for rule in SG: {sg_id} - {str(ve)}")
    else:
    print("No valid exp date found in description")

     

    except Exception as e:
    print(f"Error occurred: {str(e)}")

     

    2. Lambda IAM 접근 설정

    작성한 람다함수가 AWS 의 보안설정에 접근할 수 있도록 IAM 설정을 진행해주어야한다

     

    - IAM > Roles > Create role > Permissions policies 에 열어줄 요소들을 추가한다

    - Tip. AWS 에서 이미 제공하는 정책 안에서 찾아 넣어도 되겠지만 너무 많기도 하고 필요한 것만 넣기 어려워 직접 입력하는 것을 추천한다 + 규칙을 생성하는 시점에 입력 오류가 발생해서 모두 입력하고 수정할때 규칙 내용(.Json) 을 넣어줬다. 

    - (아웃바운드 관련 내용은 필요 없다면 빼고 사용하는 것을 권장)

    더보기

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeSecurityGroups", "ec2:RevokeSecurityGroupIngress", "ec2:RevokeSecurityGroupEgress" ] } ] }

    여기까지 작업후 Lamda 에서 test 를 돌리면 보안 규칙중 Describtion 에 이미 지난 날짜의 'exp:0000-00-00' 형식의 데이터를 갖고 있다면 삭제되는 것을 확인할 수 있다.

     

    3.  삭제 스케줄링 

    한 김에 수동 뿐만 아니라 주기적으로 삭제가 되면 좋을 것 같아 AWS 의 Event Bridge 를 연결 시키기로 했다. 

     

    Event Bridge > Schedules > create Schedule  을 통해 스케줄을 생성 할 수 있고

    스케줄 생성 마지막에 Target 설정에서 위에 제작한 람다를 설정해주면 된다. 

     

    사실 별거 아닌 작업이지만 그래도 서비스가 붐비지 않고 배치가 돌지 않을 만한 시간으로 설정하여 모든 작업을 마쳤다.

     

    과금 요소

    - 사용된 AWS 서비스는 EventBridge, Lamda, CloudeWatch(람다 로그를 제공 함) 이고 프리티어 무료 기준은 넉넉하다.

    • EventBridge: 매월 1,400만 건(스케줄 기주)
    • Lamda: 월별 무료 요청 1,000,000건, 월별 최대 320만 초
    • CloudWatch: 매월 10개 Metric, 3개의 대시보드, 5GB 

     

     

     

     

    댓글

Designed by Tistory.