Infra

[AWS 자동화] 임시 등록 보안 규칙 IP 자동으로 삭제하기

쉽코기 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