docker사용시 centos의 firewall를 bypass하는 문제

문제라기보다는 docker 자체에서 iptables에 체인을 별도로 만들어 운영합니다. ㅠ.ㅠ
반나절동안 삽질하다가 알게되어 공유차원에서 올립니다.
생각해보니 클라우드환경에서는 방화벽이 별도로 운영되어 별다른 문제는 없을 듯합니다.

centos 7 부터는 iptables를 wrapper한 firewall-cmd를 이용합니다. 그래서, firewall-cmd만 들여다보고 있다보면 해결이 어렵게됩니다.

[문제]

  1. 로컬 테스트서버에 centos7 & docker-ce설치
  2. firewall-cmd가 정상작동중임을 확인함.
  3. portainer container를 생성후 아웃바운드에서 들어오는 포트를 portainer 포트로 포워딩함.
  4. 혹시나 하는 마음에 외부에서 portainer로 접속함.
  5. 접속이 이루어짐…ㅠ.ㅠ

[확인]

  1. centos나 ubuntu도 같은 현상이 발생하는 것 같습니다.
  2. docker가 iptables에 별도의 체인을 만들어 운영합니다.
  3. docker홈페이지에는 DOCKER-USER 체인을 핸들링하라고 나옵니다. iptables를 이용한 방법만 제시되어 있습니다.
  4. 검색결과 firewall-cmd에서는 direct 옵션으로 iptables를 직접 핸들링 하는 방법으로 처리하면 된다고합니다.

[해결]
다음 내용을 스크립트로 만들어 실행하면 되겠습니다.

# Removing DOCKER-USER CHAIN (it won't exist at first)
firewall-cmd --permanent --direct --remove-chain ipv4 filter DOCKER-USER

# Flush rules from DOCKER-USER chain (again, these won't exist at first; firewalld seems to remember these even if the chain is gone)
firewall-cmd --permanent --direct --remove-rules ipv4 filter DOCKER-USER

# Add the DOCKER-USER chain to firewalld
firewall-cmd --permanent --direct --add-chain ipv4 filter DOCKER-USER

# Add rules (see comments for details)

#  "This allows docker containers to connect to the outside world"
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#  "allow internal docker communication"
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -j RETURN -s 172.17.0.0/16

#  "my allowed ip address to http and https ports"
#firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -p tcp -m multiport --dports https -s 123.456.7.89/32 -j ACCEPT

#Add as many ip or other rules and then run this command to block all other traffic
# "reject all other traffic"
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -j DROP

# restart the services 
systemctl stop docker
systemctl stop firewalld
systemctl start firewalld
systemctl start docker

[추가내용]
테스트해보니 DOCKER-USER 체인은 docker network driver중 bridge에 해당합니다.
network mode가 host인 경우에는 firewall-cmd public 존으로 처리가 됩니다.

5개의 좋아요

이 글은 질문이 아니라 경험공유 글에 더 가깝지 않을까요…?

5개의 좋아요

@level120 님 감사합니다. 제가 글을 잘못 파악한 것 같습니다.

@_jeonghwan 님 죄송합니다. 글의 요지를 잘못 파악해서 질문 답변 게시판으로 옮겼는데, 정보 공유 게시판으로 다시 옮기겠습니다. 불편을 드려 죄송합니다. :pray:

3개의 좋아요

저도 어디에 써야할지 잘몰라서 그냥 자게에 썼습니다.~~^^

4개의 좋아요

어제 오늘 리눅스 서버를 셋팅하면서 이전의 대충 알았던 내용들과 부분들을 알게되어 글을 남겨봅니다.

아래 내용들은 서버 앞단에 방화벽이 있다면 별반 중요하지 않은 내용이기도 합니다. 클라우드에서도 필요없겠네요. 아래 내용들은 single서버에 docker가 돌아가고 접근 허용 및 차단시 필요합니다.

1. 리눅스에는 NIC CARD를 통해 들어오는 네트워크 패킷을 처리하는 netfilter가 있습니다.

2. iptables는 netfiler가 제공하는 훅에 룰을 제공 관리합니다.

3. 우리는 이 iptables를 수정하여 특정 ip를 deny하거 allow하게 됩니다.

4. 리눅스 서버 배포판에 따라 iptable를 wrapper한 firewall-cmd(redhat계열), ufw(debian계열)를 방화벽 관리도구로 사용하게 됩니다.

redhat계열(centos, rocky…) 리눅스서버를 설치한후 docker를 설치하면 일반적인 서비스 사용이 가능하게 됩니다.

mysql db가 서비스 되는 container를 올린후 서비스 port(3306)를 firewall-cmd로 특정 ip 대역만 접근되게 한후 다른 ip 대역에서 접근하면 접근이 이루어집니다. firewall-cmd로 설정하더라도… :fearful:

이유는 아래 링크에 해당 내용이 있습니다. 대략 내용은 서비스 관리를 위해 fireall-cmd로 작성된 설정보다 docker에서 자동설정하는게 우선이다라는 말입니다. 기본적으로 DOCKER-USER 체인에는 모두 허용되어 있습니다.

docker에서는 iptables에 DOCKER 체인과 DOCKER-USER체인을 추가하는데 수정할려면 DOCKER-USER체인을 이용하라고 적혀있습니다. iptables 체인 출력은 아래와 같은 명령어로 가능합니다. iptables는 위쪽에 있는 것이 우선순위로 처리됩니다.

[root@101 ~]# iptables -nL

firewall-cmd로 처리한 부분은 DOCKER-USER 체인보다 밑에 있는 것을 확인하였습니다.
즉, docker에서 운영되는 container는 firewall-cmd로 DOCKER-USER 체인을 direct로 관리하고
sshd와 같은 서비스는 firewall-cmd로 public zone에 설정 처리 합니다.

다음과 같은 요구사항이 있을때 이렇게 처리하면 되겠습니다.

ssh(22 port)는 192.168.100.100 ip만 허용한다. mysql container(3306 port)는 192.168.100.200만 접근하게 한다.

[ssh 접근허용]

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.100.100" port port="22" protocol="tcp" accept'
firewall-cmd --reload

[mysql container 접근허용]

firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -p tcp -m multiport --dports 3306 -s 192.168.100.200 -j ACCEPT
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 0 -j DROP
firewall-cmd --reload

그럼 이만…

4개의 좋아요