Cloud Modernization 21

네트워크 ACL과 보안 그룹을 계층형 방화벽으로 구분하기

둘 다 트래픽을 허용하거나 막는 규칙이라서 어느 계층에서 어떤 방식으로 적용되는지 헷갈린다.

근거 · 교안 p85-p91

네트워크 ACL과 보안 그룹을 계층형 방화벽으로 구분하기 ?? ???

1장: 계층형 보안의 첫걸음: 왜 방화벽이 두 개일까?

솔라는 노트북 화면에 떠 있는 네트워크 구성도를 보며 미간을 찌푸렸다. ‘VPC’라는 이름의 커다란 상자, 그 안에 놓인 여러 개의 ‘서브넷’ 상자, 그리고 그보다 더 작은 ‘인스턴스’ 아이콘들. 외부 인터넷에서 들어오는 화살표와 인스턴스에서 나가는 화살표가 제각기 다른 필터를 거치고 있었다. 하나는 ‘네트워크 ACL’, 다른 하나는 ‘보안 그룹’.

솔라는 마우스를 허공에 둔 채 중얼거렸다. “둘 다 트래픽을 걸러내는 방화벽이잖아. 그런데 왜 똑같은 일을 하는 것처럼 보이는 장치가 두 개나 필요하지? 그냥 더 강력한 거 하나만 쓰면 되는 거 아니야?” 비슷한 기능을 하는 두 개의 장벽이 있다는 사실은 깔끔한 설계를 방해하는 불필요한 중복처럼 느껴졌다.

그때, 솔라의 혼잣말을 들은 언니 루나가 조용히 다가와 솔라의 어깨에 손을 얹었다.

“아직도 그거 보고 있었어?”

“응. 네트워크 ACL이랑 보안 그룹 말이야. 아무리 봐도 모르겠어. 둘 다 허용하거나 차단하는 규칙을 만드는 건데, 왜 두 단계로 나눠놨을까? 괜히 복잡하기만 한 것 같아.”

솔라의 불평에 루나는 대답 대신, 솔라의 책상 위에 놓인 작은 블록 상자를 가리켰다.

“이걸로 우리가 지을 가상의 데이터 센터 건물을 한번 만들어볼까?”

루나는 파란색 블록으로 널찍한 사각형 울타리를 만들었다. 그리고 그 안에 노란색 블록과 초록색 블록으로 작은 공간 두 개를 구분했다.

“이 파란 울타리가 우리 클라우드 네트워크(VPC)의 전체 경계라고 생각해 봐. 그리고 이 울타리 안의 공간들은 각각 다른 목적으로 사용되는 구역, 즉 ‘서브넷’인 셈이지.”

솔라는 루나의 손끝을 따라 블록 구조물을 내려다보았다.

“자, 이제 외부에서 방문객이 이 단지에 들어오려고 해. 가장 먼저 어디를 통과해야 할까?”

“음… 단지 입구에 있는 정문?”

“맞아. 그 정문 역할을 하는 게 바로 **네트워크 ACL(Network ACL)**이야. 일단 우리 단지 전체에 들어올 자격이 있는지 없는지를 가장 먼저, 가장 넓은 범위에서 검문하는 거지.”

루나는 울타리 한쪽에 작은 틈을 만들며 말했다.

“그럼 방문객이 정문을 통과해서 단지 안으로 들어왔다고 치자. 그렇다고 해서 이 안에 있는 모든 건물, 모든 방에 마음대로 들어갈 수 있을까?”

“아니.” 솔라는 즉시 대답했다. “회사 건물에 출입증이 있다고 해서, 서버실이나 대표님 방까지 그냥 들어갈 순 없잖아.”

“바로 그거야.” 루나는 노란색 블록으로 만든 공간 앞에 작은 블록 하나를 더 놓았다. “각각의 중요한 방, 즉 개별 서버(인스턴스)마다 별도의 문과 잠금장치가 달려 있어. 이 방 문 앞의 경비원이 바로 **보안 그룹(Security Group)**이야.”

솔라는 잠시 생각에 잠겼다. 정문과 방 문. 비유는 간단했지만, 그녀의 근본적인 의문은 아직 해결되지 않았다.

“그래도 이상해. 정문 경비를 아주 철저하게 해서 허가된 사람만 딱 들여보내면, 방마다 문을 잠글 필요가 없는 거 아닐까? 아니면 반대로, 각 방 문만 튼튼하게 잠가두면 정문은 그냥 열어둬도 되는 거 아니냐는 말이지.” 솔라의 목소리에는 여전히 ‘하나면 충분하다’는 생각이 묻어났다.

루나는 솔라의 질문을 기다렸다는 듯이 고개를 끄덕였다.

“좋은 지적이야. 그럼 이렇게 생각해 보자. 만약 어떤 해커가 정문 출입증을 위조해서 어떻게든 단지 안으로 들어왔다면? 그때 각 서버마다 보안 그룹이라는 개별 잠금장치가 없다면 어떻게 될까?”

“아…” 솔라의 입에서 짧은 탄식이 흘러나왔다. “단지 안을 마음대로 돌아다니면서 모든 방의 문을 열려고 시도하겠네. 취약한 방 하나만 있어도 바로 뚫리는 거고.”

“이번엔 반대로 생각해 볼까? 특정 국가에서 오는 모든 방문 요청이 악의적인 공격으로 판단됐어. 우리 단지 안에는 수백 개의 방이 있고. 이럴 때 수백 개의 방 문 잠금장치 설정을 하나하나 바꾸는 게 빠를까, 아니면 그냥 단지 정문에서 ‘그 나라에서 온 방문객은 모두 출입 금지’라고 막는 게 빠를까?”

순간 솔라의 눈이 반짝였다. 머릿속에 흩어져 있던 두 개의 방화벽이 각자의 자리를 찾아가는 느낌이었다.

“알겠다! 정문(네트워크 ACL)은 ‘단지(서브넷)’ 전체에 대한 크고 넓은 규칙을 적용해서 1차 방어를 하는 거고, 각 방의 문(보안 그룹)은 그 안에 있는 ‘개별 방(인스턴스)‘을 세밀하게 보호하는 2차 방어선이구나. 둘은 중복이 아니라, 지키는 대상의 ‘수준’과 역할이 완전히 다른 거였어!”

솔라는 비로소 왜 방화벽이 두 개여야만 하는지 납득했다. 하나는 동네 입구의 방범 초소, 다른 하나는 우리 집 현관문 도어록이었다. 둘 다 필요했다.

흥분해서 떠들던 솔라는 문득 손가락으로 블록들을 톡톡 건드리며 새로운 질문을 던졌다.

“그런데 언니, 궁금한 게 또 생겼어. 정문의 경비원과 방 앞의 경비원은 일하는 방식도 다를 것 같아. 정문 경비원은 들어오는 사람, 나가는 사람 명단을 일일이 대조하면서 확인할까? 방 문은 한번 열어주면 나갈 때는 그냥 보내주지 않을까? 이 둘은 구체적으로 어떻게 다르게 작동하는 거지?“

2장: NACL 탐구: 서브넷 경계의 비저장 방어막

솔라의 질문에 루나는 대답 대신 책상 위 블록들을 한쪽으로 밀어내고, 깨끗한 A4 용지 한 장을 펼쳤다. 중앙에 굵은 세로선을 긋고 왼쪽에는 ‘들어오는 규칙 (인바운드)’, 오른쪽에는 ‘나가는 규칙 (아웃바운드)’이라고 적었다. 어제 가지고 놀던 블록 건물 대신, 이제는 경비원의 규칙 수첩처럼 보이는 표가 둘의 시선을 사로잡았다.

이 새로운 판은 솔라가 던진 질문, ‘정문 경비원은 일하는 방식도 다를까?’에 대한 루나의 대답이었다. 루나는 ‘정문’, 즉 네트워크 ACL이 바로 이 규칙표를 사용한다고 설명하며 펜을 들었다.

“솔라 네가 웹서버를 운영한다고 생각해 보자. 외부 사용자들이 네 웹사이트에 접속하려면, 우리 ‘단지(서브넷)’의 정문을 통과해야 해. 그럼 정문 경비원의 ‘들어오는 규칙’ 수첩에 뭐라고 적어둬야 할까?”

솔라는 잠시 고민하다가 대답했다. “음… ‘모든 방문객의 웹사이트 방문(HTTP, 포트 80)을 허용한다’라고 적어야겠지?”

“맞아.” 루나는 ‘들어오는 규칙’ 칸에 다음과 같이 적었다.

규칙 번호유형출발지목적지 포트허용/거부
100HTTP (80)0.0.0.0/0 (모두)80허용
*모든 트래픽**거부

“규칙 번호 100번은 낮은 숫자라 먼저 확인돼. 그래서 ‘모든 곳에서 오는 HTTP(80번 포트) 요청은 허용’하고, 그 외 나머지는 기본 규칙(*)에 따라 모두 거부하는 거지.”

루나는 작은 화살표 모양 포스트잇에 ‘사용자 요청’이라고 적어 ‘들어오는 규칙’ 쪽으로 움직였다. 포스트잇은 100번 규칙과 대조된 후, 문제없이 선을 통과했다. 솔라는 이 모습이 너무나 당연하게 느껴졌다.

“좋아. 그럼 이제 서버가 요청을 처리했고, 사용자에게 웹페이지 내용을 다시 보내줘야 해. 응답해야지.”

루나는 또 다른 포스트잇에 ‘서버 응답’이라고 적었다. 그리고 이번에는 그 포스트잇을 중앙선 오른쪽에서 왼쪽으로, 즉 서버가 있는 안쪽에서 바깥쪽으로 움직이기 시작했다.

“자, 이 ‘서버 응답’ 패킷이 단지를 빠져나가려고 해. 나가는 문을 지키는 경비원은 ‘나가는 규칙’ 수첩을 확인하겠지. 이 패킷은 통과할 수 있을까?”

“응? 당연히 통과해야지.” 솔라는 망설임 없이 대답했다. “방금 허락받고 들어온 요청에 대한 응답이잖아. 경비원이 그걸 모를 리가 없지.”

솔라의 대답에 루나는 아무 말 없이 펜으로 용지 오른쪽, ‘나가는 규칙’이라고 쓰인 텅 빈 칸을 톡톡 두드렸다. 그곳에는 아무런 규칙도 적혀 있지 않았다. 오직 눈에 보이지 않는 기본 규칙, ‘모든 것을 거부(*)’만 존재할 뿐이었다.

순간 정적이 흘렀다. 솔라는 자기가 놓친 것을 깨달았다. 그녀의 시선은 ‘서버 응답’ 포스트잇과 텅 비어있는 ‘나가는 규칙’ 칸 사이를 다급하게 오갔다.

“잠깐만… 나가는 규칙에 아무것도 안 적혀 있으면… 기본 규칙에 따라서 거부되는 거야? 들어온 요청에 대한 응답인데도?”

“바로 그거야.” 루나가 말했다. “정문 경비원, 즉 네트워크 ACL은 방금 무슨 일이 있었는지 전혀 기억하지 못해. 들어온 요청이 있었는지, 그게 허용되었는지에 대한 ‘상태’ 정보가 없어. 그저 자기 눈앞을 지나가는 패킷이 ‘나가는 규칙’ 목록과 일치하는지만 기계적으로 확인할 뿐이지.”

솔라는 머리를 한 대 맞은 듯한 표정을 지었다. “아! 그래서 ‘상태 비저장(Stateless)’이라고 하는구나. 들어올 때의 상황을 전혀 기억 못 하니까, 나가는 트래픽도 별개의 사건으로 취급해서 규칙을 일일이 검사하는 거였어. 그럼 통신이 되려면…”

솔라는 루나의 펜을 가져가 ‘나가는 규칙’ 칸에 직접 규칙을 채워 넣기 시작했다.

규칙 번호유형목적지출발지 포트허용/거부
100모든 트래픽0.0.0.0/0 (모두)1024-65535허용
*모든 트래픽**거부

“이렇게… 사용자의 임시 포트(1024-65535)로 나가는 응답 트래픽을 ‘허용’하는 규칙을 명시적으로 추가해 줘야만, 비로소 웹사이트가 제대로 보이는 거구나!”

이제야 솔라는 ‘상태 비저장’이라는 단어가 가진 무게를 실감했다. 그것은 단순히 ‘기억 못 함’이 아니라, 들어오는 길과 나가는 길 모두에 대해 명확한 허가증을 따로 발급해야 한다는 의미였다. 하나의 통신을 위해 두 개의 규칙이 필요했다.

규칙표를 완성하고 만족스러워하는 솔라를 보던 루나가 조용히 입을 열었다.

“정문 경비원은 그렇게 깐깐하게, 그리고 모든 걸 잊어버리면서 일해. 그런데 솔라 네가 아까 짐작했던 것처럼, 한번 들여보내 준 손님은 나갈 때 얼굴만 보고 보내주는 경비원도 있지 않을까?”

솔라는 고개를 들었다. 그녀의 머릿속은 자연스럽게 다음 질문으로 향하고 있었다.

“그럼… 각 방의 문(보안 그룹)을 지키는 경비원은 다른 거야? 그 경비원은 자기가 들여보낸 요청을 기억했다가, 그에 대한 응답이 나갈 땐 규칙 확인 없이 그냥 보내주는, 그런 ‘기억력 좋은’ 방식으로 작동하는 건가?”

3장: 보안 그룹 탐구: 인스턴스 수준의 저장 방어막

솔라의 머릿속은 온통 ‘기억력 좋은 경비원’에 대한 생각으로 가득 차 있었다. 네트워크 ACL(정문 경비원)이 들어오고 나가는 모든 것을 따로따로 검사하는 ‘상태 비저장’ 방식이라면, 보안 그룹(방 문 경비원)은 분명 다를 것이었다.

솔라는 어젯밤 루나와 함께 채웠던 A4 용지를 책상 위에 다시 펼쳤다. 인바운드와 아웃바운드 규칙이 빽빽하게 적힌 네트워크 ACL 규칙표. 솔라는 그 옆에 새로운 A4 용지를 놓고, ‘방 문 경비원 (보안 그룹) 규칙’이라고 큼지막하게 썼다. 그리고 잠시 고민하더니, ‘들어오는 규칙 (인바운드)’이라는 제목 아래에만 단 한 줄을 적었다.

유형출발지허용/거부
HTTP (80)0.0.0.0/0 (모두)허용

그게 전부였다. ‘나가는 규칙 (아웃바운드)’ 칸은 텅 비워두었다. 그녀는 ‘기억력이 좋다면, 나가는 건 알아서 해주지 않을까?’라고 생각했다. 들어오는 요청만 허용하면, 그에 대한 응답은 당연히 나갈 수 있어야 했다. 이 단순함이야말로 두 번째 방화벽의 존재 이유일 거라는 확신이 들었다.

그때, 솔라의 새로운 규칙표를 본 루나가 조용히 다가왔다. 루나는 텅 비어있는 ‘나가는 규칙’ 칸을 손가락으로 가리켰다.

“방 문 경비원은 이렇게 일할 거라고 생각하는구나? 나가는 규칙은 아예 필요 없다고?”

“응. 언니가 말했잖아. 한번 들여보내 준 손님은 그냥 보내주는 경비원도 있을 거라고. 들어오는 요청을 허락했으니까, 그 응답이 나가는 건 당연히 기억하고 그냥 통과시켜 줘야지. 이게 ‘상태 저장’ 아니야?” 솔라는 자신의 추리가 완벽하다고 믿었다.

루나는 고개를 끄덕이며 어제 사용했던 ‘사용자 요청’과 ‘서버 응답’ 포스트잇을 다시 가져왔다.

“좋아. 그럼 네가 만든 이 규칙표로 시뮬레이션을 해보자.”

루나는 먼저 ‘사용자 요청’ 포스트잇을 솔라의 규칙표 위로 움직였다. 포스트잇은 ‘HTTP (80) 허용’ 규칙에 따라 문제없이 ‘방(인스턴스)’ 안으로 들어갔다. 여기까지는 솔라의 예상대로였다.

“자, 이제 서버가 웹페이지를 준비해서 ‘서버 응답’을 내보낼 차례야.”

루나는 ‘서버 응답’ 포스트잇을 들고 방 안쪽에서 바깥쪽으로 움직였다. 포스트잇은 솔라가 텅 비워둔 ‘나가는 규칙’ 영역에 멈춰 섰다.

솔라는 자신만만하게 말했다. “이제 경비원이 기억력을 발휘할 차례지! 아까 들어온 요청에 대한 응답이라는 걸 기억하고 그냥 보내줄 거야.”

루나는 대답 대신, ‘사용자 요청’ 포스트잇이 규칙표를 통과하던 순간을 재연했다. 그리고는 요청이 통과하자마자, 규칙표의 ‘HTTP (80) 허용’ 규칙 옆에 작은 별 스티커를 하나 붙였다.

“보안 그룹, 즉 방 문 경비원은 네 말대로 기억력이 좋아. 하지만 모든 걸 기억하는 게 아니야. ‘허용’된 규칙을 통해 들어온 ‘연결’을 기억하는 거지. 이 별 스티커가 바로 그 ‘연결 기록’이야.”

루나는 ‘서버 응답’ 포스트잇을 가리켰다.

“그래서 이 응답 패킷이 나가려고 할 때, 경비원은 나가는 규칙표를 뒤적이는 대신 자기가 붙여놓은 이 별 스티커만 확인해. ‘아, 이 응답은 방금 내가 허락한 80번 포트 연결에 대한 답장이구나.’라고 확인되면, 규칙과 상관없이 그냥 통과시켜 주는 거야. 이게 바로 상태 저장(Stateful) 방식의 핵심이야.”

순간 솔라의 눈이 동그래졌다. 그녀가 막연하게 상상했던 ‘기억력’의 실체가 눈앞에 그려졌다.

“아! 그냥 막연히 기억하는 게 아니라, 허용된 ‘연결’의 상태를 기록해두는 거였구나! 그래서 들어올 때 사용된 연결 정보와 일치하는 응답 트래픽은 나가는 규칙을 검사할 필요 없이 자동으로 허용되는 거였어.”

솔라는 비로소 왜 보안 그룹의 규칙이 그토록 단순할 수 있는지 깨달았다. 들어오는 규칙만 명확히 허용해 주면, 그에 대한 복잡한 응답 경로는 보안 그룹이 ‘알아서’ 처리해 주니 관리자는 나가는 규칙에 대해 크게 신경 쓸 필요가 없었다. 이것은 들어가는 규칙과 나가는 규칙을 모두 명시해야 했던 네트워크 ACL과는 근본적으로 다른 작동 방식이었다.

흥분한 솔라는 책상 위 블록들을 다시 가져와 ‘정문(네트워크 ACL)’과 ‘방 문(보안 그룹)’을 나란히 놓았다. 이제 그녀는 외부에서 온 하나의 요청이 이 두 개의 방화벽을 거쳐 어떻게 처리되는지 완벽하게 설명할 수 있었다.

“자, 이제 완벽히 알겠어! 외부에서 온 웹사이트 접속 요청은…”

솔라는 손가락으로 가상의 패킷을 움직이며 설명하기 시작했다.

“첫째, ‘정문’에서 네트워크 ACL의 인바운드 규칙을 통과해야 해. 기억력은 없지만 엄격한 경비원이지. (HTTP 80번 포트 허용!)”

“둘째, ‘방 문’에서 보안 그룹의 인바운드 규칙을 또 통과해야 해. 기억력 좋은 경비원이 손님 명단을 확인하는 거야. (HTTP 80번 포트 허용!)”

“셋째, 서버의 응답이 나갈 땐, 방 문 경비원이 아까의 연결을 기억하고 자동으로 통과시켜 줘. 나가는 규칙 검사는 생략!”

“마지막으로, 정문에 도착한 응답은 네트워크 ACL의 까다로운 아웃바운드 규칙을 통과해야만 단지 밖으로 나갈 수 있어. (임시 포트로 나가는 응답 허용!)”

솔라는 두 개의 방화벽, 두 명의 경비원이 어떻게 각자의 다른 방식으로 협력하여 빈틈없는 계층형 방어 시스템을 만드는지 명확하게 그려냈다. 더 이상 둘은 중복되거나 복잡하기만 한 존재가 아니었다. 각자의 자리에서, 각자의 방식으로, 서로를 보완하는 완벽한 파트너였다.