필자는 iptables보다 firewalld와 ufw와 친하다.
firewalld나 ufw는 ip 화이트리스트 설정이 쉽기에 특정 도커 컨테이너로의 접근 제한도 쉽겠거니 했다.
하지만 도커는 ufw 설정과 별개라는 걸 알게 되었다.
인터넷을 찾아보니 도커가 iptables을 사용하지 않도록 iptables를 비활성화하는 방법이 있지만 아무래도 껄끄러운 부분이 많다.
이에 iptables를 이용해 도커의 방화벽을 설정해보았다.
iptables 설정
도커의 iptables는 DOCKER와 DOCKER-USER 체인에 설정된다.
Docs를 보면 DOCKER 체인보다 DOCKER-USER 체인을 사용할 것을 권장한다.
“All of Docker’s iptables
rules are added to the DOCKER
chain. Do not manipulate this chain manually. If you need to add rules which load before Docker’s rules, add them to the DOCKER-USER
chain. These rules are applied before any rules Docker creates automatically.” – from Docker
실제로 iptables의 FORWARD 체인을 확인해보면 DOCKER-USER 체인이 가장 먼저, 그리고 나중에 DOCKER 체인이 호출되는 것을 볼 수 있다.
$ iptables -nL FORWARD Chain FORWARD (policy DROP) target prot opt source destination DOCKER-USER all -- 0.0.0.0/0 0.0.0.0/0 DOCKER-ISOLATION-STAGE-1 all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ...
그러므로 DOCKER-USER 체인에 설정을 추가하기만 하면 되는 일이다.
안타깝게도 DOCKER-USER 체인은 기본(built-in) 체인이 아니기에 정책(policy)을 설정할 순 없다.
그래서 필자는 다음과 같이 iptables를 설정하였다.
$ sudo iptables -I DOCKER-USER -p tcp -i enp3s0 ! -s localhost -d localhost --match multiport --dport 3000,5432,8000,8080 -j DROP $ sudo iptables -I DOCKER-USER -p tcp -i enp3s0 -s 123.123.123.123,234.234.234.234 -d localhost --match multiport --dport 3000,5432,8000,8080 -j ACCEPT
iptables는 순서에 민감하다.
-I 옵션으로 추가했기에 둘째줄이 먼저 적용되고 그 다음으로 첫째줄이 적용된다.
둘째줄은 enp3s0 인터페이스를 통해 123.123.123.123과 234.234.234.234에서 포트 3000, 5432, 8000, 8080로 오는 트래픽을 모두 허용한다는 의미이다.
첫째줄은 enp3s0 인터페이스를 통해 외부에서 내부로 오는 포트 3000, 5432, 8000, 8080에 대한 모든 트래픽을 모두 버린다는 의미이다.
localhost를 이용하여 규칙을 지정했기에 인터페이스 지정은 필요하지 않을 수 있으나 혹시 몰라 내용을 넣어주었다.
이로서 특정 포트에 대해 ip 화이트리스트를 적용한 것이 된다.
그 결과 DOCKER-USER 체인에 대한 규칙은 다음과 같다.
$ sudo iptables -nL DOCKER-USER Chain DOCKER-USER (1 references) target prot opt source destination ACCEPT tcp -- 234.234.234.234 127.0.0.1 multiport dports 3000,5432,8000,8080 ACCEPT tcp -- 123.123.123.123 127.0.0.1 multiport dports 3000,5432,8000,8080 DROP tcp -- !127.0.0.1 127.0.0.1 multiport dports 3000,5432,8000,8080 RETURN all -- 0.0.0.0/0 0.0.0.0/0
ufw로 설정하면 몇 분 안 걸리는 일인데 익숙하지 않은 iptables에 도커 내부 네트워킹 문제가 같이 끼니 디버깅에 수시간을 허비했다.
필자가 iptables 설정에 인터페이스나 localhost를 지정한 이유가 있다.
만약 이들이 지정되지 않으면 도커 내부 트래픽 또한 방화벽에 걸려 네트워킹이 안될 수도 있다.
예를 들어 포트만으로 방화벽을 설정하게되면 WAS와 DB는 외부에서 잘 접근되는데 서로 통신은 불가능한 상황이 생긴다.
이는 도커 내부 네트워킹이 ip 화이트리스트에 막혔기 때문에 발생한다.
한편, FORWARD 체인의 끝자락에는 ufw 체인이 있다.
이는 DOCKER 체인이 ufw 체인을 덮어씌운다는 것을 의미한다.
ufw 체인을 FORWARD 체인의 첫 번째로 설정한다면 굳이 iptables를 건드릴 필요 없이 ufw만으로 도커에 ip 화이트리스트를 적용할 수 있지 않을까 생각이 든다.
테스트해보기에는 오늘의 삽질이 너무 고됐기에 추후를 기약해본다.