
백엔드 API를 배포 서버(NGINX)에서만 사용하도록 하기
- 개발 환경에서는 백엔드 API를 외부에서 호출하고, 동작을 검증하는 것이 편리할 수 있다. 하지만 프로덕션 환경에서는 외부에서 백엔드 API를 호출하는 것을 막아 서버 자원을 보호하고, 보안 측면을 강화하는 것이 권장된다.
- 따라서 실제 프로덕션 환경을 대비해서 외부에서 백엔드 서버 API를 호출할 수 없도록 먼저 UFW를 이용해 백엔드 API 서버 접근을 제한 하려고 했다.
1. UFW 적용 - Docker Network를 차단하지 못하는 문제 발생

- 이렇게 8080 포트를 막아두면, 외부에서 백엔드 API를 직접 호출하는 경우에 대해 차단이 될 거라고 생각을 했다.
http://PUBLIC_IP:8080/api/v1/test
- 그런데, 예상과 달리 호출이 된다. ufw를 재시작하고 설정을 다시 확인해 봤지만 ufw 자체에는 문제가 없었다.
왜 UFW는 Docker로 실행 중인 PORT를 차단하지 못할까?
- 간단히 방화벽의 동작 원리를 살펴보면 리눅스에서 패킷 필터(방화벽 역할)를 하는 iptable은 네트워크 계층에서 구현된다. UFW는 해당 iptable을 조작할 수 있는 사용자 인터페이스라고 볼 수 있다.
- Linux에서 Docker는
iptables
규칙을 조작하여 도커 네트워크를 지원한다. 즉, 발생하는 문제를 보면 UFW가 관리하는 iptable과 별도로 docker는 자체 iptable로 네트워크를 구성하므로 ufw로 도커 네트워크를 차단할 수 없는 것이다.
- 그림으로 살펴보면 아래와 같다.

해결책
1. 도커 이미지를 로컬에서만 접근할 수 있도록 포트 지정
-p 127.0.0.1:8080:8080
- 127.0.0.1 루프백 인터페이스를 사용하면, Docker 컨테이너의 포트가 호스트의 로컬 네트워크 인터페이스에 바인딩되어 호스트에서만 접근이 가능하다.
2. IPTABLES 수정
- Docker의 IPTABLE을 비활성화하는 옵션을 주고 실행하거나, IPTABLE에 직접 수정하여 외부에서 8080 포트에 접근하는 것을 차단하고, 내부에서 8080 포트에 접근하는 방법을 허용할 수 있다.
- 해당 방식의 문제점은 도커 네트워크를 자유롭게 사용할 수 있는 것을 제한한다. 또한 사용자 설정, 도커 네트워크 설정, ufw iptable 설정 다 별도로 존재하기 때문에 설정이 추가될수록 원치 않는 동작이 발생할 가능성이 높아진다.
3. UFW 설정을 수정하여 Docker Network와 통합
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0] # UFW에서 사용자의 포워딩 규칙 제어하는 체인
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0] # Docker 컨테이너의 네트워크 트래픽을 제어하는 체인
# DOCKER-USER 체인에 규칙을 추가하여 모든 트래픽을 ufw-user-forward 체인으로 전달
# Docker 컨테이너의 네트워크 트래픽이 UFW의 사용자 정의 포워딩 규칙을 따름.
-A DOCKER-USER -j ufw-user-forward
# 개인 네트워크가 서로를 방문할 수 있도록 허용
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
# DNS는 매우 일반적인 서비스이기 때문에 더 큰 포트 범위에서 DNS 패키지를 수신하도록 허용하는 방화벽 규칙
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
# 모든 공용 네트워크에서 시작된 연결 요청을 차단하지만, 내부 네트워크가 외부 네트워크에 액세스하도록 허용
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP
COMMIT
# END UFW AND DOCKER
sudo ufw allow 8080 VS sudo ufw route allow proto tcp from any to any port 8080
- 전자는 단순히 호스트 머신의 포트 80으로 들어오는 모든 TCP 트래픽을 허용한다.
- 8080 포트를 사용하는 앱이 도커 컨테이너로 실행 중이라면, 공용 네트워크로 도커 컨테이너에 접근하기 위해서는 해당 네트워크 요청이 호스트를 통해 라우팅되어 도커 네트워크로 전달될 수 있어야 한다.즉, ufw allow 8080/tcp를 했다고 해서 공용 네트워크로 도커 네트워크에 접근이 되지 않는다.


참고 자료
