본문 바로가기

지식/Network

리눅스 브릿지로 방화벽 구성하기

2. 브릿지 방화벽 구축하기

기업과 기관들은 점차적으로 적당한 네트워크 보안의 필요성을 인식하고 있다. 네트워크를 안전하게 하는 첫 번째 단계중의 하나는 해로운 데이터 전송을 막는 방화벽을 설치하는 것이다. 그러나, 많은 관리자들은 더 많은 IT장비들에 수백만 달러를 투자하기를 매우 망설인다(새로운 장비를 관리하기 위해 담당자를 교육할 필요는 말할 것도 없다). 관리자들은 공개소스 소프트웨어에서 대규모의 비용없이 효과적인 대규모의 방화벽 솔루션을 찾을수 있다.

넷필터 프로젝트는 리눅스 커널용의 패킷필터링 모듈이다. 이는 리눅스 커널에 Network Address Translation(NAT)를 위한 패킷처리와 더불어 stateful packet filtering 기능을 제공한다. 이들은 고가의 상용 솔루션에서 공통적으로 보이는 두가지 특징이다.

stateful packet filtering은 내부로부터 시작되지 않은 모든 외부로부터의 전송를 차단할수 있게 한다. 이는 당신이 외부로부터 내부 네트워크로의 접속을 거부하고 싶을 때 유용하다. 만약 단순히 당신이 외부로부터오는 모든 전송을 거부한다면, 내부의 모든 컴퓨터들도 외부로의 항해를 할수 없을 것이다. TCP/IP 접속은 3단계 상호접속이다. stateful packet filtering을 설명하기위해 전형적인 인터넷 접속을 살펴보자. 호스트A는 내부 네트워크에 있고 인터넷에 있는 호스트 B의 웹서버에 있는 웹 페이지를 보고자 한다. 웹 서버는 일반적으로 서버의 80번 포트에서 작동한다. 호스트 A는 호스트 B의 80번 포트를 향해 패킷을 보낼 것이다. 이 패킷은 또한 소스 포트 번호를 포함하고 있다. 이 소스 포트 번호는 일반적으로 1024보다 크다. 1024 이상의 포트 번호는 흔히 임시 포트로 일컬어진다. 서버에서 작동하는 대부분의 서비스는 1024이하의 포트 번호를 이용한다. 이는 규정은 아니고 단지 두 종류의 구분을 돕기위한 일반적인 관행이다. 호스트 A의 시작 패킷은 호스트 B에게 연결을 원한다는 신호를 위해 SYN 플래그가 설정되어 보내진다. 그러면 호스트 B는 접속을 허가한다는 것을 알리기위해 SYN와 ACK 플래그를 설정하여 호스트 A에게 패킷을 전달한다. 이 패킷의 소스 포트는 80번이고 목적지 포트는 호스트 A의 시작 패킷의 소스 포트 번호이다. 문제는 패킷이 방화벽에 도착했을 때 있다. 만약 방화벽이 stateful filtering 기능이 없다면, 방화벽은 이 패킷을 막을 것이다. 만약 방화벽이 stateful filtering 기능이 있으면 방화벽은 접속을 요청한 호스트 A로부터의 시작 패킷을 큐(현재의 연결을 저장하고 있다)에서 확인하고 패킷을 통과시킨다.

그림1. 브릿지 방화벽의 물리적 위치

브릿지 방화벽은 네트워크에서 보이지 않는 방화벽이다. 물리적으로는 네트워크에 연결되어있지만 라우터나 게이트웨이와는 달리 TCP/IP에서는 존재하지 않는다(그림 1참조). 내부 네트워크로부터의 모든 패킷은 브릿지를 지나서 전달된다. 브릿지는 패킷을 검사해서 패킷을 외부로 전달할 것인지 막을것인지 결정한다. 출발지과 목적지의 호스트의 관점에서는 패킷에는 아무런 변화도 없이, 호스트는 상대편의 호스트에게 직접 패킷을 주고 받는다(그림2 참조). 최근까지 리눅스 시스템에서는 브릿지 방화벽을 사용할수 없었다. 하지만, Lennert Buytenhek의 고마움덕으로 리눅스용의 브릿지가 이제는 가능하다. 이 소프트웨어는 계속적으로 개발되고 수정되고 있으며, 현재는 개발의 베타 단계에 있다. 그러나 시험을 통해 Lennert의 코드가 기능만 구현된 수준이 아니라 제품화 수준으로 안정적이라는 것을 확인했다.

그림2. 브릿지는 tracert에서 보이지 않는다.

테스트용에는 1.3GHz의 듀얼 프로세서와 1GB의 메모리를 가진 컴팩 프로리언트 DL360 서버를 사용했다. 브릿지 기능을 위해서는 2개의 네트워크 카드가 필요하다. 하나는 인터넷으로 연결되고 다른 하나는 내부 네트워크에 연결된다. 평균적으로 70Mbits의 전송속도를 가지는 네트워크에서 Lennert의 브릿지 코드를 사용하여 패킷 손실이 없었다.

브릿지 방화벽을 설치하기 위해서는 우선, 방화벽으로 사용될 컴퓨터 시스템에 레드햇 리죽스 7.2를 다운받아서 설치해야 한다. 그런후에 소프트웨어의 모듈을 최신 버전으로 업그레이드하고 패치되도록해서 이전 버전의 문제점들을 제거하는 것이 좋다. 여러분은 가능한 시스템이 안전하기를 원할 것이다. 그러기위해서는 서비스하지 않을 어떠한 서비스를 위한 모듈도 설치하지 않는 것이 좋다. 방화벽에서는 다른 서비스는 지원하지 않아야 한다. 유닉스를 안전하게 관리하는 것에 대한 추가적인 정보는 참고 문헌 부분에 나와있는 CERT의 안전한 유닉스를 위한 가이드를 참고하면 된다.

그런후에 브릿지를 위한 유틸리티와 커널 패치를 Lennert의 홈페이지에서 다운받는다(역자주:번역 시점에는 bridge-nf-0.0.6-against-2.4.18.diff이 최신 버전의 커널 패치이었다.). 또한 최신의 버전의 넷필터를 http://netfilter.samba.org에서 다운받으면 된다. 끝으로 최신 버전의 리눅스 커널을 ftp://ftp.kernel.org에서 다운 받아야 하는데, 현재는 2.4.14이 최신이다(역자주:번역 시점에는 2.4.18이 안정된 최신 버전이었다). 다운받은 커널을 /usr/src 디렉토리에 복사하고 아래와 같이 실행하여 압축을 푼다.

# tar -xzvf linux-2.4.14.tar.gz

그러면, /usr/src/linux 디렉토리에 커널이 설치된다. 다운받은 브릿지-넷필터 커널 패치를 이 디렉토리에 복사한후, 다음을 실행시켜 패치를 적용한다(그림3 참조).

# cd /usr/src/linux
# patch -p1 < bridge-nf-0.0.3-against-2.4.13.-ac7.diff

그림3. 커널에 브릿지 패치를 적용하는 모습.

커널 설정을 시작하기위해 /usr/src/linux 디렉토리에서 make menuconfig를 실행한다.

# cd /usr/src/linux
# make menuconfig 
이제 커널에 어떤 옵션이 포함되어 컴파일될지를 선택한다. 보안을 위한 예방조치로 필요한 구성요소들만 설치할 것을 권장한다. (역자주: 브릿지와 넷필터를 같이 사용하기 위해서는 먼저, 개발중인 기능(EXPERIMENTAL)을 활성화 시켜야 한다. "Code maturity level options" 메뉴를 선택한후, "Promopt for development and/or incomplete code/drivers" 항목을 활성화 시킨다. 이것을 활성화 시켜야 브릿지와 넷필터를 함께 사용하도록 하는 메뉴가 나타난다.) 브릿지 방화벽을 위해서 필요한 옵션은 "Network Options"부분에서 발견된다. "Network Packet filtering(replaces ipchains)" 선택해야한다(그림 4 참조). 이것은 "IP:Netfilter Configuration -->" 보조 메뉴를 활성화시킨다 (그림 5 참조). 이메뉴에서 당신은 방화벽이 포함할 다양한 기능을 선택할수 있다. 저자는 모든 항목이 다 유용하다고 생각하기 때문에 일반적으로 모든 항을 선택한다(그림 6 참조). 이제 "Network Options" 부분으로 돌아가서 "802.1d Ethernet Bridging"항과 "netfilter (firewalling) support (NEW)"를 선택한다(그림 7참조). 이제 커널 설정은 끝났다.

그림4. 패킷 필터링 설정 메뉴.

그림5. 넷필터 설정 메뉴.

그림6. 넷필터 옵션 설정 메뉴.

그림7. 브릿지 방화벽 설정 메뉴.

커널 설정 메뉴를 끝냈으면, 커널을 컴파일해서 커널 이미지를 만든다.

# make dep
# make bzImage
커널 이미지가 만들어지면, 만들어진 커널 이미지를 부트 디렉토리에 복사한다.
# cp /usr/src/linux/arch/i386/bzImage /boot/bzImage.bridge
(역자주: /usr/src/linux/arch/i386/bzImage가 존재하지 않으면, 아래를 대신 실행한다. 역자의 경우, 화일이 아래의 디렉토리에 생성되었다.)
# cp /usr/src/linux/arch/i386/boot/bzImage /boot/bzImage.bridge
부트 관리자가 새로은 커널 이미지를 인식하고 이것으로 부팅하기 위해서는 설정이 필요하다. 만약 당신이 LILO를 사용한다면, /etc/lilo.conf 파일에 아래와 같이 추가한다.
image=/boot/bzImage.bridge
        label=bridge
        read-only
        root=/dev/hda1
이제 LILO를 다시 실행해서 변경된 설정이 적용되게 한다.
# lilo
컴퓨터를 리부팅하고 부트 메뉴에서 "bridge"를 선택한다. 모든 것이 정확하게 설정되었다면, 컴퓨터는 부팅될 것이고 이제 메뉴 설정에서 선택한 모듈들을 설치한다. /usr/src/linux 디렉토리로 이동해서 다음을 실행한다.
# cd /usr/src/linux
# make modules
# make modules_install
만약 컴퓨터가 부팅을 하지 않으면, 리부팅한후, 이전의 부트 옵션을 선택해서 이전의 상태로 부팅한후, /usr/src/linux 디렉토리로 이동해서 make menuconfig를 다시 실행해서 커널 설정부터 다시 시도해 본다.

컴퓨터가 정상적으로 부팅되고 모듈들이 설치되면, 이제 브릿지의 설정을 시작할수 있다. 먼저 브릿지 유틸리티의 압축을 푼다.

# tar -xzvf bridge-utils-0.9.5.tar.gz.
다음 순서대로 실행해서 유틸리티를 컴파일하고, 설치한다.
# cd ./bridge-utils-0.9.5
# make
# cp ./brctl/brctl /usr/bin
# cp ./brctl/brctld /usr/bin
이제 유틸리티가 컴파일되었고, 브릿지를 만들 준비가 되었다. 먼저 brctl addbr mybridge룰 실행해서 새로운 브릿지를 만든다. 이 명령어는 "mybridge"라는 이름의 브릿지를 만든다. ifconfig -a를 실행해서 네트워크 인터페이스로 "mybridge"가 만들어진 것을 볼수 있다. 이제 여러분은 브릿지로 사용할 네트워크 카드를 브릿지의 일부로 추가해야 한다. 브릿지를 위해서는 최소한 2개의 네트워크 카드가 필요하며, redundancy를 위해 추가의 네트워크 카드를 추가하는 것도 가능하다. 이 부분은 후에 다시 설명한다. 네트워크 카드를 브릿지에 붙이기위해 다음을 실행한다.
# brctl addif mybridge eth0
# brctl addif mybridge eth1
그러면, 이더넷0번과 1번이 브릿지에 붙게된다. 이 명령어는 brctl addif bridgename interface-name의 형식으로 사용한다. 언제든지 brctl --help를 실행하면, 브릿지를 설정하기위한 유용한 명령어들의 리스트를 볼수 있다.

다음으로, 이더넷 카드가 IP주소가 없고, promiscuous 모드로 작동하도록 설정하기 위해 다음을 실행한다.

# ifconfig eth0 0.0.0.0 promisc
# ifconfig eth1 0.0.0.0 promisc
이렇게 이더넷 카드에 IP주소를 설정하지 않음으로서, TCP/IP를 통해 외부로부터 브릿지로 임의로 접속 하지 못하도록 확실하게 한다. 이것은 방화벽에게 매우 중요한 기반의 보안을 제공한다. 방화벽의 규칙은 오직 로컬에서만 설정이 가능하다. 이는 어떻게보면 관리자에게는 매우 불편한것처러 보이지만, 저자로서는 이렇게함으로써 얻을수 있는 보안성의 증가는 불편함을 감수할 가치가 있다고 생각한다. (역자 주: 만약 브릿지 방화벽에 IP를 할당하고 싶으면, 아래와 같이 추가로 실행한다.)
# ifconfig mybridge IP주소 netmask 서브넷마스트
이제 내부의 호스트로부터 외부 인터넷의 호스트로 ping을 테스트해 본다. 브릿지가 적절하게 설정되었다면, 응답 메시지를 받을수 있다.

이것으로 브릿지 설정이 끝났으니, 이제 방화벽을 설정하는 부분으로 옮겨가자. 먼저 이전에 다운받은 넷필터/iptable 유틸리티의 압축을 풀기위해 다음을 실행한다.

# tar -xzf iptables-1.2.4.tar.bz2
(역자 주: bz2 파일이 tar로 풀리지 않으면 다음과 같이 나누어서 실행한다.)
# bunzip2 iptables-1.2.4.tar.bz2
# tar -xvf iptables-1.2.4.tar
이제 다음을 순서대로 실행해서 유틸리티를 컴파일한다.
# cd ./iptables-1.2.4
# make
# make install

iptables가 설치된후에 가장 먼저 iptalbes -L을 수행해본다. 이명령어는 현재의 규칙을 나열한다. 여기서 관심을 가져야하는 체인은 Forward 체인이다. 브릿지 방화멱은 기본적으로 모든 traffic을 forwarding하기 때문에 다른 체인들은 사용하지 않는다. iptables의 기본적인 사용법은 iptables -A FORWARD pattern-to-match -j action의 형태이다. "pattern-to-match" 부분을 위한 기본적인 옵션은 아래와 같다.

-p, --protocol			tcp, udp, icmp가 공통적으로 사용된다.
-s, -d				출발지, 목적지 IP 주소
--dport, --destination-port	목적지의 포트 번호
--sport, --source-port		출발지의 포트 번호
"action"은 DROP, REJECT, ACCEPT, LOG중의 하나가 된다. 저자는 DROP을 선호하는데, 이것은 공격자일수도 있는 접속자에게 아무런 응답도 보내지 않기 때문이다. 호스트에 접근할수 없다는 에러를 받는것보다 패킷의 유효 시간 경과를 기다리게 함으로써 공격자의 정보 수집 기능을 현저히 떨어지게 한다. LOG를 사용함으로써 패킷의 헤더정보를 Syslog에 캡쳐하게 할수 있다. iptables에는 로그가 엄청난 양으로 쌓이지 않도록 하기위해 로그화일의 크기를 제한하도록 하는 모듈이 있다. 이는 호스트 스캔이 시도되는 경우와 같이 중복된 내용의 로그가 대량으로 기록될 때 유용한다. 방화벽 규칙을 설정하는 것에 대한 추가적인 정보는 첨부된 방화벽 설정 스크립트를 참고하도록 한다.

이 공개 소스 방화벽 솔루션은 비용을 대략 $26,505 절약시켜 줄 것이다. 전체 비용은 아래에 항목별로 기술되어 있다(그림8 참조). 상용 솔루션인 Checkpoint의 방화벽-1의 비용에 대해서도 기술되어 있다.

그림8. 비용 비교표.

브릿지 방화벽에 redundancy(장애에 대한 대비) 기능을 제공하기위해서 서버가 지원하는 만큼의 이더넷 카드를 추가로 설치할수 있다. 만약 하나의 이더넷 카드에 장애가 발생하면, 브릿지는 다른 이더넷 카드를 사용하게 되고, 내부의 호스트들은 연결이 끊기는 것을 인식하지 못할 것이다. Redundancy를 위해서는 한걸음 더 나아가 기존의 방화벽과 병렬로 또하나의 방화벽을 구축할수 있다(그림9 참조). 이렇게 하면, 하나의 브릿지가 다운되었을때 다른 브릿지가 대신해서 처리한다. 이런 구조는 더불어 약간의 작업 분배 기능을 제공한다.

그림9. 장애 대비를 위한 브릿지 이중화 구성 모습.