RSS
보안

서버 침해의 폭발 반경 줄이기: VLAN, 출구 방화벽, VM 분리 비교

작성자
듀오랩스 대표·10분 읽기

웹 서비스 하나가 도커 컨테이너로 떠 있다고 해 보겠습니다. 포트는 리버스 프록시 뒤에 있고, 관리 화면은 막혀 있고, 비밀번호는 길고 무작위입니다. 입구는 잘 잠겨 있습니다.

이 서비스가 쓰는 라이브러리에서 원격 코드 실행 취약점이 나오면, 공격자는 컨테이너 안에서 명령을 실행하게 됩니다. 그때부터 질문이 바뀝니다. 어떻게 막을지가 아니라, 여기서 어디까지 닿을 수 있는지입니다. 이것을 폭발 반경(blast radius)이라고 부릅니다.

입구를 잠근 다음에 남는 질문

보안 점검은 대개 입구에서 시작합니다. 어떤 포트가 열려 있고, 어떤 경로가 인증 없이 응답하는지를 봅니다. 중요한 일이지만, 입구 점검은 뚫리지 않을 확률을 다룹니다. 폭발 반경은 뚫렸을 때의 피해를 다룹니다. 둘은 서로를 대신하지 못합니다.

흔한 오해는 컨테이너에 넣었으니 이미 격리됐다는 생각입니다. 컨테이너는 실제로 무언가를 가둡니다. 다만 가두는 것과 열어 두는 것이 따로 있고, 기본값으로 열려 있는 쪽이 폭발 반경을 정합니다.

컨테이너가 가두는 것과 열어 두는 것

컨테이너는 리눅스의 네임스페이스와 cgroup으로 프로세스, 파일 시스템, 자원을 나눕니다(Docker 보안 문서). 컨테이너 안의 프로세스는 호스트의 다른 프로세스를 보지 못하고, 마운트하지 않은 호스트 파일에 손대지 못합니다.

네트워크는 다릅니다. 기본 bridge 네트워크의 컨테이너는 호스트를 거쳐 NAT로 밖에 나갑니다. 호스트가 닿을 수 있는 곳이면 컨테이너도 대부분 닿습니다. 인터넷뿐 아니라 같은 사내망의 다른 서버, 데이터베이스, 라우터 관리 화면도 포함됩니다. 공격자가 컨테이너 벽을 넘지 못해도 네트워크로는 옆 서버에 접속을 시도할 수 있습니다.

그리고 컨테이너는 호스트와 커널을 함께 씁니다. 커널 취약점은 컨테이너 밖으로 나가는 대표적인 경로라, 호스트 커널이 오래됐다면 프로세스를 가두는 벽도 그만큼 얇아집니다.

출구 방화벽: 가장 적은 비용으로 줄이는 범위

컨테이너가 나갈 수 있는 곳을 줄이는 규칙입니다. 리눅스의 Docker는 사용자가 규칙을 넣을 자리로 DOCKER-USER 체인을 둡니다. 이 체인은 Docker가 만드는 규칙보다 먼저 평가됩니다(Docker with iptables). 예를 들어 특정 Docker 네트워크에서 사설 대역으로 새로 나가는 연결만 막으려면 이런 모양이 됩니다.

# 1. 이미 맺어진 연결의 응답은 통과 (사내망에서 들어온 요청에 대한 답장)
iptables -I DOCKER-USER 1 -i br-app -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
# 2~4. 컨테이너가 먼저 여는 사설 대역 연결은 차단
iptables -I DOCKER-USER 2 -i br-app -d 10.0.0.0/8     -j DROP
iptables -I DOCKER-USER 3 -i br-app -d 172.16.0.0/12  -j DROP
iptables -I DOCKER-USER 4 -i br-app -d 192.168.0.0/16 -j DROP

첫 줄을 빠뜨리면 사내망 사용자가 이 서비스에 접속했을 때 돌아가는 응답까지 막힙니다. -A(뒤에 붙이기) 대신 위치를 지정한 -I를 쓰는 데도 이유가 있습니다. Docker 버전에 따라 DOCKER-USER 끝에 RETURN 규칙이 들어 있어서, 그 뒤에 붙인 규칙은 평가되지 않습니다. 적용한 뒤에는 iptables -S DOCKER-USER로 실제 순서를 확인합니다. 이 규칙은 재부팅하면 사라지므로 부팅 때 다시 넣는 설정도 함께 둡니다.

DOCKER-USER는 호스트를 지나 다른 곳으로 가는 트래픽만 봅니다. 컨테이너가 호스트 자신의 주소로 접속하는 것은 INPUT 체인이 맡으므로 따로 막아야 합니다. 같은 호스트에 인증 없는 관리 도구가 떠 있다면 이 부분이 더 중요합니다. 외부 통신이 아예 필요 없는 컨테이너라면 규칙 대신 docker network create --internal로 만든 네트워크에 두는 방법도 있습니다(docker network create).

인터넷 출구는 대개 열어 둬야 합니다. 메일 발송, OAuth, 외부 API, 패키지 업데이트가 거기로 나갑니다. 그래서 출구 방화벽은 인터넷은 열고 사설 대역은 닫는 모양이 기본입니다. NIST SP 800-41 Rev. 1이 나가는 트래픽도 허용한 것 외에는 막으라고 권하는 것과 같은 방향입니다.

DNS는 확인이 필요합니다. 컨테이너가 사내 DNS 서버를 쓰도록 설정돼 있으면, 사설 대역 차단이 이름 풀이까지 막을 수 있습니다. 그 경우 DNS 서버 주소와 포트만 예외로 열어야 하는데, 어느 쪽에서 질의가 나가는지는 Docker 버전과 네트워크 종류에 따라 다르니 적용 뒤에 실제로 확인하는 편이 확실합니다.

VM 분리: 커널을 따로 쓰는 경계

컨테이너가 호스트 커널을 함께 쓰는 문제를 없애려면 가상 머신에 올립니다. VM은 자기 커널을 갖고, 하이퍼바이저가 호스트와의 경계를 맡습니다. 컨테이너 탈출에 쓰이는 커널 취약점이 VM 안에서 터져도 피해는 그 VM의 커널에서 멈춥니다(NIST SP 800-125는 이 경계를 지키기 위한 하이퍼바이저 관리 기준을 다룹니다).

다만 VM 분리 자체는 네트워크를 줄여 주지 않습니다. VM을 사내망에 브리지로 붙이면 VM은 사내망의 다른 장비와 같은 위치에 서게 됩니다. 커널 경계와 네트워크 경계는 따로 만들어야 합니다.

VLAN 분리: 서버 바깥에서 거는 차단

출구 방화벽은 그 서버 위에서 돕니다. 서버의 관리자 권한을 공격자가 얻으면 규칙을 지울 수 있습니다. 서버 바깥, 네트워크 장비에서 거는 경계가 필요한 이유입니다. 공개 서비스가 도는 서버를 별도 VLAN에 두고, 그 VLAN에서 사내망으로 가는 연결을 라우터에서 막으면, 서버가 통째로 넘어가도 사내망으로 가는 길은 남지 않습니다.

여기에는 조건이 하나 붙습니다. VLAN을 나누는 것만으로는 막히지 않고, VLAN 사이의 라우팅 규칙이 있어야 막힙니다. 이 부분은 VLAN만으로 망이 격리될까?에서 따로 다뤘습니다. CISA의 망 분리 안내가 VLAN을 ACL·방화벽·DMZ와 함께 쓰는 층으로 설명하는 것도 같은 이유입니다.

막는 층이 서로 다른 세 방법

출구 방화벽 VM 분리 VLAN 분리
막는 것 컨테이너에서 사내망·호스트로 새로 여는 연결 커널 취약점을 통한 호스트 장악 서버 전체가 넘어간 뒤의 사내망 이동
못 막는 것 호스트 관리자 권한을 얻은 공격자 네트워크 이동 같은 VLAN 안의 이동, 커널 탈출
필요한 것 호스트 방화벽 규칙과 재부팅 뒤 유지 하이퍼바이저, 서비스 이전 VLAN을 지원하는 라우터·스위치, VLAN 간 규칙
손이 가는 정도 작음 큼 장비에 따라 작음에서 큼

셋은 서로를 대신하지 않고 겹으로 쌓입니다. 출구 방화벽이 없으면 공격자는 서버 권한을 얻지 않아도 옆으로 갑니다. VLAN이 없으면 서버 권한을 얻은 공격자를 막을 것이 없습니다.

셋 다 지키지 못하는 것

격리는 뚫린 곳에서 다른 곳으로 번지는 것을 막습니다. 뚫린 곳 자체는 지키지 못합니다. 침해된 서비스가 쓰던 데이터베이스의 데이터, 그 서비스의 환경 변수에 들어 있던 API 키와 비밀번호는 공격자 손에 그대로 남습니다. 그래서 서비스마다 필요한 권한만 가진 DB 계정과 키를 따로 쓰는 것이 격리만큼 중요합니다. 하나가 새도 그 하나로 끝나게 하기 위해서입니다.

백업도 격리와 별개입니다. 공격자가 데이터를 지우거나 암호화하면, 다른 망에 무사히 남은 서버는 그 데이터를 되살려 주지 못합니다. 침해된 서버에서 닿지 않는 곳에 백업이 있어야 합니다.

장비가 VLAN을 지원하지 않을 때의 순서

작은 회사가 쓰는 라우터나 스위치 중에는 VLAN을 지원하지 않는 모델이 있습니다. 그렇다고 손 놓을 일은 아닙니다. 저라면 출구 방화벽부터 걸겠습니다. 장비를 사지 않아도 되고, 컨테이너가 사내망으로 새로 여는 연결이라는 가장 흔한 이동 경로를 바로 줄이기 때문입니다. 그다음 호스트 커널과 컨테이너 이미지를 최신으로 유지해 커널 경계를 두껍게 하고, 장비를 바꿀 때 VLAN과 VLAN 간 규칙을 갖춥니다.

순서가 이렇게 되는 이유는 비용 때문만은 아닙니다. 출구 방화벽은 지금 있는 서버에서 효과를 바로 확인할 수 있습니다. 컨테이너 안에서 사내망 주소로 접속을 시도해 보고, 연결이 실패하면 규칙이 동작하는 것입니다. 확인할 수 있는 것부터 쌓는 편이, 확인하기 어려운 큰 공사를 먼저 계획하는 것보다 실제로 끝까지 갑니다.

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.