AWS 방화벽 보안그룹 이해하기
모바일개발을 오래하다보니 생각보다 인프라 지식이 부족한편이다. 인프라 지식이 부족해서 AWS에 대해서 공부하면서 '보안그룹'에 대해서 읽어볼때 단순하게 '방화벽'이구나 하고 이해하고 넘어갔다. 예전에 회사서버가 해킹당해서 '코인'을 열씸히 채굴한적이 있었는데 해킹당한 사실을 발견하기 전에는 운영중인 서버가 항상 문제가 없다고 생각했다. 하지만 보안 컨설팅을 받고나서 하루에서 수백번 이상 해킹시도가 있었던 로그기록을 확인하고나서야 서버는 항상 외부의 침입에 노출되어 있다는걸 알게 되었다. 각설하고 '보안그룹'은 방화벽이 맞는것같다. 몇일전에 AWS 인프라를 담당하는 회사 직원에서 '보안그룹'에 대해서 질문을 했는데 '방화벽'이 맞다고 했다. 그리고 우리회사 인프라는 모두 private으로 구성되어 있고 모든 인바운드, 아웃바운드는 보안그룹에 의해서 관리되고 있다고 말했다. 조금 어렵기는 했지만 방화벽으로 모둔 입출력이 관리되고 있다고 이해했다. 그만큼 중요한 거겠지 생각했다.
중요한거니 조금더 힘을내고, 공부하면서 정리한 AWS 보안그룹 개념을 학습 기록 형태로 남긴다.
보안그룹 기본: 내가 이해한 “인스턴스 단위 상태기반 방화벽”
내가 처음 정리한 한 문장은 이거다. “보안그룹은 EC2(정확히는 ENI)에 붙는 상태 기반(Stateful) 방화벽이다.” 여기서 ‘상태 기반’이라는 말이 처음엔 어려웠는데, 나는 이렇게 이해했다. 인바운드로 들어오는 트래픽을 허용하면, 그 응답 트래픽은 자동으로 허용된다. 반대로 아웃바운드로 나가는 트래픽을 허용하면, 그 응답도 자동으로 돌아올 수 있다. 즉, 들어오고 나가는 왕복을 사람이 일일이 다 뚫어주지 않아도 되는 구조라서, 초보자인 내가 만지기엔 NACL보다 SG가 덜 무섭게 느껴졌다.
그리고 보안그룹은 ‘허용(Allow) 규칙만 있다’는 점도 중요했다. 나는 처음에 “막는 규칙(Deny)도 있겠지”라고 생각했는데, SG는 기본적으로 허용한 것만 통과시키는 방식이다. 그래서 어떤 트래픽이 안 들어오면, “허용 규칙이 없다”거나 “소스가 잘못됐다”를 먼저 보게 됐다. 반대로 “특정 IP를 아예 차단” 같은 요구가 있으면 NACL이나 WAF 같은 다른 수단을 고려해야 한다는 것도 같이 적어두었다.
SG에서 내가 제일 헷갈렸던 건 “어디에 붙는가”였다. 보안그룹은 서브넷에 붙는 게 아니라 인스턴스/ENI에 붙는다. 그래서 같은 서브넷에 있어도 인스턴스마다 SG가 다를 수 있다. 이게 처음엔 혼란이었지만, 생각해보면 합리적이다. 같은 동네(서브넷)에 있어도 집(인스턴스)마다 출입 규칙이 다른 것처럼, 자원별로 필요한 포트만 열 수 있기 때문이다.
마지막으로 기본 동작도 기록해뒀다. 보통 SG는 인바운드는 기본 거부, 아웃바운드는 기본 허용으로 시작한다. 그래서 초보자 실습에서는 “인바운드를 뭘 열어야 접속이 되지?”에서 막히는 경우가 많다. 나도 SSH(22)를 열고도 안 돼서 한참 헤맨 적이 있는데, 나중에 보니 퍼블릭 IP가 없거나 라우팅이 안 되어 있거나, 키 페어를 잘못 선택한 경우도 있었다. 그래서 나는 이제 “SG만 보면 안 되고 네트워크(서브넷/라우팅)와 공인 IP까지 같이 본다”를 원칙으로 세웠다.
인바운드/아웃바운드 규칙: 내가 실무처럼 설정하려고 만든 패턴
보안그룹을 공부하면서 내가 제일 크게 바꾼 습관은 “0.0.0.0/0로 다 열지 않기”였다. 개발자로서 빨리 확인하고 싶을 때는 전체 오픈이 유혹적이지만, 그게 습관이 되면 진짜 위험해진다. 그래서 나는 “최소 권한(Least Privilege)”을 보안그룹에서도 그대로 적용하려고 한다. 솔직히 이게 생각보다 쉽지 않았다. 책을 한권 구매해서 공부하고 있는데 책에서 실습은 편의성을 위해서 "0.0.0.0/0"으로 설정하고 진행한다. 초보자 입장에서 따라하기식으로 공부하는데 다른선택을 할 엄두가 나지않고 그렇다보니 맞게 설정하는것이 생각보다 쉽지가 않다.
인바운드 규칙은 “누가(소스) 어떤 포트로 들어오나”를 정의한다. 내 머릿속 기본 패턴은 이렇다.
- 웹 공개 서비스: 80/443은 필요하면 열되, 가능한 443 중심으로(운영 기준)
- SSH: 내 IP만 허용하거나(가능하면), 아예 SSH 대신 SSM으로 접근
- 앱 서버: 외부에서 직접 접근 금지, 로드밸런서(ALB) SG에서 오는 트래픽만 허용
- DB: 앱 서버 SG에서 오는 DB 포트만 허용
이 패턴을 “ALB → App → DB”로 외웠다. 특히 앱 서버와 DB는 0.0.0.0/0로 열지 않는 게 핵심이다. 앱 서버는 ALB 뒤에 숨기고, DB는 앱 서버 뒤에 숨긴다. 이렇게 하면 공격 표면이 확 줄어든다.
아웃바운드는 “어디로 나가나”를 정의한다. 많은 실습에서는 기본 허용(모든 트래픽)으로 둔 채 진행하지만, 나는 언젠가는 여기까지도 줄여보고 싶다. 다만 초보자인 나는 아웃바운드를 너무 엄격하게 막아버리면, 패키지 다운로드나 외부 API 호출이 막혀서 원인을 찾기 어려워질 수 있다. 그래서 학습 단계에서는 아웃바운드는 넓게 두되, 운영/서비스 단계로 가면 “필요한 목적지(예: DB, 내부 서비스, 특정 외부 API)만 허용” 쪽으로 개선하는 로드맵을 적어두었다.
또 중요한 건 소스를 IP로만 제한할 수 있는 게 아니라, “다른 보안그룹을 소스로 지정할 수 있다”는 점이다. 이게 AWS에서 진짜 강력한 방식이라고 느꼈다. 예를 들어 EC2 SG 인바운드를 “ALB SG에서 오는 80만 허용”으로 잡아두면, IP가 바뀌어도 구조가 유지된다. 나는 이걸 ‘SG 간 연결’이라고 부르면서, 앞으로 설계할 때는 IP보다 SG 참조를 우선으로 생각해보려고 한다.
내가 자주 겪는 실수: “열었는데 왜 안 되지?” 체크리스트
보안그룹은 자주 만지다 보니 실수 패턴도 생겼다. 나는 “포트를 열었는데도 접속이 안 된다” 상황에서 시간을 많이 버렸기 때문에, 내가 자주 쓰는 체크리스트를 기록해둔다.
첫째, 인바운드를 열 때 소스를 0.0.0.0/0로 열었는지, 아니면 내 IP로 열었는지 확인한다. 회사/집/카페처럼 네트워크가 바뀌면 내 공인 IP도 바뀌어서, 어제는 됐는데 오늘은 안 되는 상황이 생긴다.
둘째, 대상 인스턴스가 퍼블릭 IP를 가지고 있는지(또는 ALB 뒤에 있는지)를 본다. Private Subnet의 EC2는 애초에 외부에서 직접 SSH가 안 되는 게 정상일 수 있다.
셋째, 라우팅과 게이트웨이를 확인한다. Public Subnet이면 라우트 테이블에 0.0.0.0/0 -> IGW가 있어야 하고, 보안그룹만 열어서는 해결이 안 된다.
넷째, NACL이 따로 막고 있지는 않은지 확인한다(특히 응답 트래픽). 나는 아직 NACL을 자주 쓰진 않지만, 팀 환경이나 예제 구성에 따라 NACL이 걸려 있으면 SG만 봐서는 원인을 못 찾을 수 있다.
다섯째, 애플리케이션 자체가 포트를 리슨하고 있는지 확인한다. 나는 SG만 열어두고 서버에서 서비스가 안 떠 있어서 안 되는 경우도 있었다. 즉, 보안그룹은 “통로”일 뿐이고, 서버가 그 포트를 실제로 열고 있어야 한다.
여섯째, 로드밸런서를 쓴다면 타겟 그룹 헬스체크가 통과하는지도 본다. ALB에서 EC2로 트래픽이 넘어가려면, EC2 SG가 ALB SG를 소스로 허용해야 하고, 헬스체크 경로/포트가 맞아야 한다.
이 체크리스트를 만들어두니, 보안그룹이 예전처럼 공포의 대상은 아니게 됐다. 여전히 어렵지만, “막힐 수 있는 지점”을 순서대로 보는 습관이 생겼다. 비전공자인 내게는 이 습관 자체가 실력이라고 믿고 싶다.
보안그룹은 EC2/ENI에 붙는 상태 기반 방화벽이고, 최소 권한 원칙으로 인바운드를 좁게(특히 앱/DB는 SG 참조로) 설정하는 게 핵심이다. 나는 “ALB→EC2→RDS” 흐름을 기준으로 SG를 설계하면 실수가 줄어든다는 걸 체감했다. 앞으로는 실습할 때마다 어떤 포트를 왜 열었는지, 소스는 왜 그렇게 제한했는지까지 기록하면서 나만의 SG 패턴을 굳혀보려고 한다.
공부는 생각보다 쉽지 않다. 하지만 진입장벽이 높기때문에 공부한 이후의 가치는 더 클거라고 생각하고 꾸준히 진행해볼 생각이다.

댓글
댓글 쓰기