티스토리 뷰

IT/Linux

[Linux][CentOS7] firewalld ipset을 활용하여 whitelist 만들기

주인장 진빼이

무언가를 배우는 것도 좋지만 알아야하는 정보도 많다.

이 글은 배우는 것 + 알아야할 정보를 취합했다.

특히 도커를 사용 중이라서 더 복잡한 느낌이 들었다.

firewall보다는 iptables을 사용하자

firewalld는 리눅스 방화벽인 iptables을 쉽게 관리해줄 수 있는 래퍼 패키지이다.

우선 여러가지 특징이 있지만 잊지 말아야할 몇가지 firewalld 특징에 대해 알아보자

 

firewalld가 실행(start) 중이면 firewalld에 적용된 규칙들이 iptables에 덮어진다.

firewalld가 종료(stop) 상태일 때 iptables -nvL로 적용된 규칙을 확인해 보면 적용된 규칙이 하나도 없다.

-> iptables는 firewalld가 적용된 규칙에 따라 전체적으로 변한다.

-> firewalld에 규칙이 추가 되면 iptables도 일치된 규칙이 추가된다.

-> iptables 규칙을 따로 추가하는 경우 firewalld에서 적용된 규칙들에게 변화를 줄 수 없다.

 

firewalld 실행 중에 iptables 규칙을 추가 및 삭제하면 적용은 되지만 재시작할 경우 모두 firewalld 기준으로 적용된 규칙으로 변한다.

firewalld에서 체인을 추가하는 경우 iptables에 nat 테이블에도 변화를 줄 수 있다.

 

firewalld를 다루면서 가장 크게 느낀건 iptables을 쉽게 관리하는 것이지

디테일하게 관리하려면 결코 iptables을 사용할 수 밖에 없다는 것이다.

 

firewalld에서 --ipset을 지원하는데 이는 찾아봤더니 iptables에서도 사용할 수 있었다. (ipset --help)

 

 

docker-compose를 이용하여 컨테이너를 도커에 올려 사용하는 경우 DOCKER는 FORWARD 규칙에서 관리하여 필터링해야하는데

firewalld를 이용하면 규칙의 우선순위를 바꾸기도 힘들 뿐더러 nat 테이블에 관련된 규칙들도 다루기 힘들어 매우 힘겨웠다.

반대로 iptables는 iptables-restore < /etc/sysconfig/iptables로 vim으로 규칙의 우선순위를 수정한 뒤 편집한 규칙들을 적용할 수 있다.

 

/etc/firewalld에 포함된 파일을 모두 확인해봤지만 firewalld 관련해서 우선순위를 쉽게 제어할 수 있는 룰은 찾아보기 힘들었다.

iptables에 규칙을 추가하더라도 리눅스 머신이 재시작되면 모두 물거품되어 버리기 때문에 더더욱 firewalld를 사용하기 힘들었다.

반드시 DOCKER를 사용하는 경우라면 무조건 iptables을 사용하도록 하자.

firewalld --direct를 이용한 규칙 추가

firewalld에서 --direct 옵션은 iptables와 유사한 관련 규칙을 추가할 수 있다. (filter 테이블 이용)

규칙을 추가하게 된다면 iptables -nvL에서 확인해보면 <chain이름 또는 zone이름>_direct 체인에 규칙이 추가되는 것을 볼 수 있다.

만약 INPUT 규칙에 다음과 같은 규칙을 추가한다고 하자.

$ firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp -m geoip ! --src-cc KR -j DROP

 

INPUT 체인 안에 INPUT_direct로 점프하는 규칙이 추가되었고, 패킷이 들어오는 경우 INPUT_direct 체인으로 jump하게 된다.

하지만 INPUT_direct 규칙보다 더 우선순위가 높은 ACCEPT 관련 규칙이 있다면 INPUT_direct 규칙에서 필터링 작업을 할 수 없다.

 

이때, INPUT_direct 규칙의 우선순위를 firewalld에서 변경할 수 있어야 하는데 그럴 수 없었다.

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 2052,3306 -m geoip ! --source-country KR
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:2052 -m geoip ! --source-country KR
 4225  861K ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
   24   996 INPUT_direct  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   24   996 INPUT_ZONES  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   18   720 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

다음 규칙을 보자.

 

docker-compose에서 웹서버가 실행 중인 상황이다.

정말 화가 나는 상황이 아니던가 ?

 

firewalld에서 --direct 옵션으로 규칙을 추가했지만 DOCKER 관련 규칙은 필터링 할 수 없었다.

그 이유는 FORWARD_direct로 jump되는 규칙에 우선순위가 낮았기 때문이다. (DOCKER-ISOLATION > FORWARD_direct)

 

PREROUTING을 제어하거나 iptables에서 규칙을 추가(-I)하는 경우 충분히 해결될 문제였지만

firewalld를 재시작 또는 리눅스 머신을 재시작하는 경우 다시 원상복구 된다는 것이다.

(도커에서 사용 중인 브릿지 네트워크 인터페이스는 br-*로 시작된다)

 

만약 도커에 접근하는 모든 아이피를 차단하고 싶다면 FORWARD chain이나 DOCKER-ISOLATION 최우선순위로 모든 아이피를 차단하는 규칙을 추가해보길 바란다.

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 DOCKER     all  --  *      br-c7830344d364  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      br-c7830344d364  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  br-c7830344d364 !br-c7830344d364  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-c7830344d364 br-c7830344d364  0.0.0.0/0            0.0.0.0/0
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 docker0  0.0.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
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
    
    0     0 FORWARD_direct  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 FORWARD_IN_ZONES  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 FORWARD_OUT_ZONES  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
    
    Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
    4   176 ACCEPT     tcp  --  !br-883c785a6a56 br-883c785a6a56  0.0.0.0/0            172.18.0.2           tcp dpt:3306
    0     0 ACCEPT     tcp  --  !br-883c785a6a56 br-883c785a6a56  0.0.0.0/0            172.18.0.4           tcp dpt:80
    0     0 ACCEPT     tcp  --  !br-883c785a6a56 br-883c785a6a56  0.0.0.0/0            172.18.0.5           tcp dpt:443
    5   216 ACCEPT     tcp  --  !br-883c785a6a56 br-883c785a6a56  0.0.0.0/0            172.18.0.5           tcp dpt:80

Chain DOCKER-ISOLATION (1 references)
 pkts bytes target     prot opt in     out     source               destination
   63  2768 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

 

 

이때 2가지 해결 방법이 존재한다.

1. 재부팅 될때마다 특정 shell 을 실행하게 만들어서 iptables 명령어를 이용하여 규칙을 추가하는 것

2. firewalld를 버리고 nat, filter 테이블을 쉽게 제어할 수 있는 iptables을 사용하는 것

 

2번을 택했다.


작업 흐름

이번 작업은 모든 접근을 차단하고 허용한 IP 주소를 가진 호스트에 한해서 접근을 허용하게 하는 작업이다.

 

firewalld에서 Whitelist를 만들고 접속 승인을 처리하려면 차단 작업(block, drop) 보다 접속 승인이 우선적으로 처리되야 한다.

그러기 위해서는 새로운 영역(zone)을 만들고 접속 승인을 처리하게 설정한다.

중요한건 접속 승인이 처리 된 후 차단 작업(block, drop)을 진행하게 만들어야 한다.

여러 개의 IP 주소를 승인하기 위해서는 ipset을 이용한다. 이 ipset이 Whitelist를 의미하는 것이다.

새롭게 만든 접속 승인 규칙들을 처리하는 영역에는 Whitelist4 이름을 가진 ipset을 적용한다.

그외 나머지 접근은 모두 차단한다.

 

firewalld에서 zone을 생성 및 설정, 규칙을 추가하다보면 iptables에 등록된 라우팅 규칙을 담당하는 테이블(nat)에도 영향을 끼칠 수 있다. 이로 인해 iptables을 따로 작업하지 않고도 firewalld에서 쉽게 필터링할 수 있다.

firewalld zone 우선순위

firewalld에서 영역(zone)의 우선순위는 알파벳 순서이다. ( 0 > 9 > a > z )

0에 가까운 이름을 가진 영역이 가장 우선시 처리되며, a부터 z까지 알파벳 순서로 처리한다.

접근 승인을 담당하는 새로운 Zone만들기

접근 승인이 우선 시 되려면 접근 승인을 처리할 새로운 zone을 생성해야 한다.

이름 앞에 000- 을 붙여 우선순위를 높게 만든다.

새로운 zone의 이름은 000-allow-zone으로 설정했다.

$ firewall-cmd --new-zone 000-allow-zone --permanent
$ firewall-cmd --set-target=ACCEPT --zone=000-allow-zone --permanent

ipset whitelist 다루기

접속 승인 목록인 whitelist를 만들고 제어한다.

생성

여러 개의 IP 주소를 저장할 수 있는 Whitelist를 생성한다.

Whitelist 이름은 whitelist4로 설정했다. (옵션에서 사용된 inet은 ipv4를 의미한다)

$ firewall-cmd --new-ipset=whitelist4 --type=hash:net --option=family=inet --permanent
$ firewall-cmd --permanent --zone=000-allow-zone --add-source=ipset:whitelist4

ipset 생성 시 사용 가능한 ipset type은 다음 명령어를 통해 확인할 수 있다.

보기 편하게 ,, 를 구분자로 사용하여 출력 내용을 정리했다.

$ firewall-cmd --get-ipset-types
hash:ip ,, hash:ip,mark ,, hash:ip,port ,, hash:ip,port,ip ,, hash:ip,port,net ,, hash:mac
hash:net ,, hash:net,iface ,, hash:net,net ,, hash:net,port ,, hash:net,port,net

목록

생성된 ipset 목록은 다음 명령어를 사용하여 확인할 수 있다.

$ firewall-cmd --get-ipsets
whitelist4

삭제

혹시 ipset을 잘못 만들었다면 다음 명령어를 통해 삭제하고 다시 만들도록 하자.

$ firewall-cmd --delete-ipset=whitelist4 --permanent

정보

생성한 ipset 정보를 확인하고 싶으면 --info-ipset을 이용한다.

$ firewall-cmd --info-ipset=whitelist4  
whitelist4  
  type: hash:ip  
  options: hashsize=4096 family=inet  
  entries:

entry 추가하기

접속을 승인할 아이피 또는 ip대역 (127.0.0.1/24)를 추가한다.

ip 대역 관련해서는 cidr에 대하여 알아보자

$firewall-cmd firewall-cmd --ipset=whitelist4 --add-entry=<ip>

entry 삭제하기

접속을 승인 -> 거부로 변경할 아이피를 whitelist4 ipset에서 제거한다.

$firewall-cmd --ipset=whitelist4 --remove-entry=<ip>

drop zone 설정하기

네트워크 인터페이스 추가하기

ifconfig 명령어를 이용하여 현재 사용 중인 네트워크 인터페이스를 확인할 수 있다.

ens3이 리눅스 머신에서 사용되는 인터페이스이므로 ens3에 대한 인터페이스를 drop zone에 설정한다.

이제 drop zone은 인터페이스가 추가되었으므로 활성화(active)된 zone이 되었다.

firewall-cmd --permanent --add-interface=ens3

drop zone, default로 설정하기

default zone을 drop으로 설정하여 모든 접근을 차단하도록 한다.

$ firewall-cmd --permanent --zone=drop --set-default-zone=drop

생성한 000-allow-zone에 whitelist 등록하기

000-allow-zonewhitelist4 ipset을 등록하기 위해 다음 명령어를 사용한다.

이제 000-allow-zone의 기본 정책은 ACCEPT이므로 whitelist에 추가된 IP만 접근할 수 있다.

기본 zone이 drop이며, 모든 접근을 차단했기에 ACCEPT로 패킷이 우선적으로 통과되지 못한다면 모두 drop되는 것이다.

$ firewall-cmd --permanent --zone=000-allow-zone --add-source=ipset:whitelist4

결과 확인

whitelist zone 생성 및 설정, default zone 설정을 모두 마쳤으므로 

ens3 인터페이스로 들어오는 패킷들은 Whitelist에 등록된 source ip인 경우 ACCEPT하게 된다.

그외 모든 패킷은 DROP한다.

 

혹시 모르니 다시 한번 iptables -nvL 명령어를 사용하여 규칙의 우선순위를 확인하자 (우선순위가 틀리면 제대로 작동하지 않음)

 

필터링 통과 후 또 다른 ACCEPT 처리하는 관련 규칙을 추가하고 싶다면

INPUT chain에서 INPUT_ZONES로 jump되는 규칙보다 우선순위가 낮아야 한다.

$ firewall-cmd --get-active-zones

000-allow-zone  
  sources: ipset:whitelist4  
drop  
  interfaces: ens3

 

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함