본문 바로가기
IT Security/LINUX Basic

29. Linux - 리눅스 방화벽 4, 기타 방화벽 설정

by Rosmary 2020. 8. 16.
728x90
반응형





리눅스 방화벽의 정책(Chain), 규칙(rule) 설정을 통해 기본적인 통신 패킷을 허용 / 차단하는 방법에 대해 지난 3 개의 포스팅을 통해 알아보았다. 앞의 세 포스팅 내용을 조금 정리하자면,

- 리눅스의 방화벽 통신 방향에 대한 규칙은 각 통신 방향을 정의하는 정책(Chain) 내에 작성되며
- 리눅스 방화벽의 기본 정책은 INPUT, OUTPUT, FORWARD 세 가지가 있다.
- 각 정책은 Blacklist(모든 통신을 허용하되, 일부 통신은 차단 규칙으로 작성) 또는 Whitelist(모든 통신을 불허하되, 일부 통신을 허용 규칙으로 작성) 둘 중 하나의 방식으로 정의한다.
- 각 규칙은 통신의 출발지, 목적지, 출발지 포트, 목적지 포트, 프로토콜 등의 인자 등을 이용하여 작성할 수 있다.

로 요약할 수 있다.


이번 포스팅에서는 지금까지 봐왔던 리눅스 방화벽의 내용 외에, 리눅스 방화벽 운영에 필요한 추가 설정 방법에 대해 알아보려 한다.



1. 특정 사용자를 위한 정책(Chain)의 추가

리눅스 방화벽의 기본 정책 / 규칙을 보면, 기본 Chain인 INPUT, OUTPUT, FORWARD 외에도 다른 Chain이 존재하고 있는 것을 확인할 수 있다.


분명, 리눅스 방화벽의 정책(Chain)은 INPUT, OUTPUT, FORWARD 세 개만 존재하면 되는데, 이들은 무엇일까? 아래와 같은 상황을 한 번 가정해보자.

현재 운영하는 리눅스에 접속할 수 있는 권한을 가진 사용자가 2명이 있다. 편의상 A와 B라고 하자. A는 리눅스에서 제공하는 웹 서비스에 대해 기획하는 사람이고, B는 웹 개발자이다. B는 자신이 만든 html 파일을 sftp 서비스를 통해 리눅스의 특정 파일에 옮겨야되고, A는 http 서비스에만 접속할 수 있도록 만들려고 한다.


앞선 포스팅에서 설명한 내용만을 참고하면, 위의 상황은 다음과 같은 명령어로 방화벽 정책과 규칙을 구성할 수 있다.

< 사용자 B에 대한 방화벽 정책 구성 >
# iptables -A INPUT -s 172.30.1.230 --dport 80 -j ACCEPT
# iptables -A OUTPUT -d 172.30.1.230 --sport 80 -j ACCEPT

<사용자 A에 대한 방화벽 정책 구성 >
# iptables -A INPUT -s 172.30.1.200 --dport 22 -j ACCEPT
# iptables -A OUTPUT -d 172.30.1.200 --sport 22 -j ACCEPT

그런데, 위와 같이 방화벽 정책을 구성하면 추후 A나 B의 PC IP가 변경될 경우, INPUT 및 OUTPUT Chain 내의 IP를 일일히 iptables -R 명령어로 수정해야하는 불편함이 발생하게 된다. 따라서, 각 사용자마다 방화벽 정책(Chain)을 만들어 규칙을 지정하면, 추후 사용자 PC의 IP 변경이 일어나더라도 단 하나의 규칙에 작성된 IP만 수정함으로써 훨씬 효율적으로 리눅스 방화벽을 운영할 수 있게 된다. 필자는 본 포스팅을 위해 리눅스 방화벽을 다음과 같이 초기화했다.

# iptables -P INPUT ACCEPT
# iptables -P OUTPUT ACCEPT
# iptables -F
# iptables -X
** 실제 설정에서는 기본 Chain의 정책 설정을 blacklist로 했지만, whitelist로 설정되었다고 가정하고 아래의 내용을 읽어주시기 바란다.

위와 같이 명령어를 입력하면, 기본 Chain인 INPUT, OUTPUT, FORWARD만 존재하게 된다. 정책이 없더라도 INPUT과 OUTPUT Chain이 모두 허용을 기본 정책으로 설정되어 있기 때문에, 통신에는 문제가 없다.


이제 필자는 사용자 A와 B에 대한 정책 Chain을 생성하려 한다. 각 사용자로부터 들어오는 통신, 그리고 나가는 통신 규칙에 대해 정의해 주어야하기 때문에, 각 사용자 당 2개의 Chain이 생성되게 된다.


두 번째로 진행해야 할 작업은, 각 사용자에게 부여된 통신 규칙을 생성하는 작업이다. A는 SFTP 사용이 가능하도록 리눅스의 22번 포트를 통한 통신을 오픈시켜야하고, B는 http 서비스 사용을 위해 리눅스 80번 포트를 오픈시켜야 한다. 각각의 규칙을 정의한 결과는 다음과 같이 나타난다.


위의 작업 내용과 결과에 의문을 가지신 분들은 이런 생각이 들 것이다. "각 규칙을 정의하면서 사용자 A와 B의 IP를 출발지나 목적지 IP로 지정하지 않았는데 통신이 될까?"

맞다. 아직은 통신이 될 수 없다. 리눅스 방화벽은 어차피 INPUT, OUTPUT, FORWARD의 내용만 참조하기 때문인데, 이를 위해 우리가 만든 Chain을 이 INPUT, OUTPUT, FORWARD에서 인지할 수 있도록 추가 작업을 진행해주어야 한다.

규칙 생성 시, 통신의 허용, 차단을 결정하는 iptables 명령어의 옵션은 -j이다. 지금까지 이 -j 옵션 뒤에 ACCEPT, DROP, REJECT의 기본 사항만 작성이 되는 것으로 설명했는데, 사실 이 -j 옵션은 우리가 추가해준 Chain 이름을 인자로 설정할 수 있다. 다음과 같이.


사용자 A를 예시로 보자면, 사용자 A가 22번 포트로의 접속을 시도하면, 해당 통신 패킷이 INPUT Chain에 정의된 규칙을 하나씩 대조하게 된다. A는 IP가 172.30.1.200이므로, INPUT Chain의 1번 규칙에 걸리게 되는데, 이 1번 규칙의 target이 user_A_INPUT Chain이므로, 22번 통신 패킷은 user_A_INPUT Chain의 규칙을 대조하게 된다. user_A_INPUT 1번 규칙은 22번 포트에 대해 통신을 허용하였기 때문에, 22번 포트로의 통신 요청 패킷은 리눅스 방화벽에 막히지 않고 제대로 전달되게 된다.

다음으로 리눅스에서 통신을 허용한다는 패킷이 사용자 A에게 전달되어야 A가 SFTP를 사용할 수 있게 되는데, 이 때 나가는 통신 패킷은 OUTPUT Chain을 참조하게 된다. 마찬가지로 나가는 통신 역시 목적지 IP가 172.30.1.200이므로, OUTPUT의 1번 규칙과 일치하여 해당 규칙의 target Chain인 user_A_OUTPUT에 정의된 규칙을 참조하게 된다.

따라서 사용자 A가 22번 포트가 아닌 80번 포트로의 통신을 시도하면 당연히 방화벽에 막혀 통신이 진행되지 않는다. 실제 통신이 막히는 것을 확인해보고 싶으신 분들은, 새로 생성한 4개 Chain의 기본 규칙을 DROP이나 REJECT로 설정하고 확인해보시기 바란다.


이제, 사용자 A가 사용하는 PC의 IP가 200번에서 250번으로 바뀌었다고 가정해보자. PC의 IP가 변경되었기 때문에, 변경된 PC에서 사용자 A는 기존에 사용하던 SFTP를 사용할 수 없게 된다. 따라서 리눅스 방화벽의 INPUT과 OUTPUT Chain에서 사용자 A와 관련된 IP를 수정해주는 작업을 진행해야 한다. 아래와 같이.


만약, 기본 Chain만 사용하여 규칙을 작성하였을 경우, 사용자 A와 관련된 모든 규칙의 출발지 / 목적지 IP를 모조리 수정해주어야 하는 번거로움이 필연적일 수 밖에 없다. 하지만 위와 같이 특정 사용자에게 적용할 정책 Chain을 별도로 생성함으로써, 네트워크 구성이 변경되더라도 노가다 작업 없이 빠르게 방화벽 변경 내용을 적용할 수 있다는 장점이 있다.

사실 이 방법은, 사용자 개개인 뿐만 아니라, 네트워크 대역대를 대상으로도 사용할 수 있는 방법이다. CentOS 7의 기본 리눅스 방화벽에서 보았던 IN_public이나 FWDO_public과 같은 Chain들 역시 특정 네트워크 대역대에서 사용하기 위해 미리 기본값으로 설정된 Chain들이다. 사실상 개인 네트워크에서는 쓸 일이 크지 않기 때문에 필자의 포스팅에서는 다루지 않았다.



2. 패킷 state: NEW, ESTABLISHED, RELATED

systemctl restart firewalld를 사용하여 방화벽 정책/규칙을 기본값으로 되돌려보자. 그럼, 규칙의 Description 중에 NEW, ESTABLISHED, RELATED와 같은 단어들이 작성된 규칙들이 보일 것이다.


컴퓨터의 통신은 아주 간략하게 나누어보면, 통신 요청과 통신 요청에 대한 응답으로 나뉠 수 있다. 먼저 서버의 서비스를 사용하려는 사용자(클라이언트)는 서비스 사용을 위해 서버에 특정 포트와의 통신을 요청하는 패킷을 먼저 보낸다. 만약 정상적으로 서비스가 진행되고 있고, 방화벽도 제대로 열려 있다면, 서버는 클라이언트에게 통신 요청에 대한 허용을 응답으로 돌려주게 된다. 통신을 허가받은 클라이언트는 그때부터 서버의 특정 포트와 지속적인 통신이 가능해진다.

이제 위의 상황을 전문 용어를 아빠숟갈 반 숟갈만 섞어 살펴보자. 우선 처음에 클라이언트가 서버로의 접속을 요청하는 패킷은 통신 시작 패킷이다. 리눅스에서는 이러한 패킷을 통신을 새로 시작하는 패킷이라고 하여 NEW 패킷이라고 칭한다. 만약 서버에서 NEW 패킷에 대해 통신 허용 패킷을 돌려주게 된다면, 그 때부터 서버와 클라이언트는 "통신 세션"이 맺어졌다(Establish)고 말하며, NEW 패킷 이후, 통신을 요청한 포트로 드나드는 모든 통신 패킷은 ESTABLISHED로 간주된다.

CentOS 7의 기본 방화벽 정책/규칙 내용을 잘 보면, INPUT에 ESTABLISHED 패킷에 대한 허용 규칙이 존재하는 것을 알 수 있다(INPUT 5번). 이는 리눅스에서 웹 브라우저를 통해 특정 사이트에 접속할 때, DNS 서버에 문의한 질의에 대한 응답을 받기 위한 용도로 들어가 있다. 만약, 모든 기본 Chain이 whitelist로 설정되어 있고 그 상태에서 5번 정책을 지운다면, 리눅스에서 웹 브라우저를 통해 다음이나 기타 사이트로의 접속이 불가능해지는 것을 확인할 수 있다.

방화벽의 규칙을 NEW, ESTABLISHED와 같은 state로 작성하는 이유는 방화벽을 효율적으로 운영할 수 있기 때문이다. 가령, 특정 사용자에게 22, 53, 80번 세 개의 포트로 통신을 허용하는 규칙을 넣는다고 하면, INPUT과 OUTPUT Chain 모두 각 3개의 통신에 대한 규칙을 정의해야 한다. 하지만 state 모듈을 사용하면 INPUT에만 3개의 규칙을 정의하고 OUTPUT에는 별도의 규칙을 작성하지 않아도 된다. 아래의 명령어로 모든 규칙을 다시 다 지우고, 이를 확인해보자.

설정과 달리, 모든 Chain의 기본 정책은 whitelist라고 가정하고 설명한다.


필자는 모든 사용자에 대해 별도의 Chain 형성없이 SSH, HTTP, DNS 통신을 허용하는 정책을 작성할 것이다. 먼저 INPUT Chain에 들어갈 규칙은 아래와 같이 작성한다.


iptables 명령어 옵션으로 -m과 --state가 보인다. -m 옵션은 별도의 모듈을 사용하겠다는 의미이며, 인자로는 state를 입력해주었다. --state는 통신 패킷에 대한 인자를 설정하는 옵션이며, 외부로부터 통신을 시작하는 패킷을 받기 위해 NEW를 인자로 입력해주었다. 따라서, 필자가 만든 INPUT Chain의 규칙은, SSH, HTTP, DNS 통신을 시작하겠다는 내용을 담은 패킷의 유입을 허가한다는 의미이다.

이제 OUTPUT Chain을 살펴보자. 현재 OUTPUT에는 어떠한 허용 정책도 추가되어 있지 않기 때문에 서버에서 클라이언트에게 통신 허용 패킷을 날려보낼 수 없다. 이를 위해 각 서비스 포트를 출발지 포트로 규칙을 넣어주어야 하지만, state 모듈을 사용하여 단 한 줄로 SSH, HTTP, DNS 통신에 대한 OUTPUT 규칙을 생성할 수 있다.


분명 OUTPUT Chain에는 22, 80, 53번 포트에 대한 내용이 직접적으로 명시되지 않았음에도, 서버로부터의 통신 허용 패킷이 클라이언트에게 도달하게 된다. 하지만 아직도 SSH나 http등으로 접속은 진행되지 않는 상황일 것이다. 왜냐하면, SSH 접속 허용 이후의 ESTABLISHED 패킷에 대해 INPUT Chain 규칙이 생성되지 않았기 때문이다. 통신 세션이 맺어진 이후에도 패킷이 서버로 들어가기 위해서 ESTABLISHED 패킷에 대한 규칙 역시 OUTPUT Chain과 마찬가지로 정의가 되어 있어야 한다. 아래와 같이.



NEW와 ESTABLISHED 외에, RELATED라는 단어도 간간히 보인다. 이 RELATED는 하나 이상의 포트를 쓰는 프로토콜 통신을 위한 state 단어다.

리눅스에서는 FTP라고, File Transfer Protocol이라고 불리는 파일 전달과 관련된 서비스를 제공할 수 있다. 이 FTP 프로토콜은 20번과 21번 포트를 사용하는데, 클라이언트가 FTP 통신 요청은 21번으로 진행하고, 리눅스 서버에서의 파일 다운로드나 서버로의 파일 업로드는 20번 포트를 통해 진행하게 된다.

그림 출처:&amp;nbsp;https://sites.google.com/site/hvanbelle/tech/ftp/active-ftp-vs--passive-ftp?overridemobile=true


먼저 클라이언트에서 NEW 패킷으로 21번으로의 통신을 요청하면, 서버는 자신의 21번 포트를 출발지로 통신 허용 패킷을 클라이언트에게 전달한다. 클라이언트는 이 응답을 받고, 20번 포트로 접속(다른 방법도 있지만 설명을 위해 이 예시를 든다)하여 파일을 업로드하거나 다운로드 하게 된다. 문제는 20번 포트로의 접속이 NEW 패킷으로 분류되지 않는데다가(21번에서 통신 허용 패킷이 날아간 후이기 때문에), 기존의 21번 포트와 맺어진 통신 세션을 사용하는 것도 아니기 때문에 NEW나 ESTABLISHED로 규칙을 만들 수 없게 된다. 이 20번 포트로의 통신은 기존 21번 포트와의 세션 수립 후 연관된(Related) 통신 포트이기 때문에, 20번 포트를 사용하는 통신 패킷은 RELATED 패킷으로 분류가 되며, 따라서 RELATED state로 방화벽 규칙을 생성해주어야 한다. 물론 INPUT과 OUTPUT 모두 규칙을 생성해주어야 한다.


이렇게 state 모듈을 사용하여 방화벽 정책과 규칙을 정의하면, 모듈 없이 작성할 때보다 방화벽 규칙의 수가 현저하게 줄어든다. 방화벽 규칙은 최대한 단순할수록 좋은데, 방화벽 운영자가 규칙을 관리하는 측면에서도 그렇고, 정책이 많으면 들어오는 패킷을 규칙 하나하나에 일일이 대조하는 과정에서 자원과 시간이 낭비되기 때문이다. 특히 다른 서비스도 함께 제공하는 리눅스인 경우, 자체 방화벽 규칙을 최소한으로 간편화하거나 아예 별도의 방화벽 장비를 네트워크 앞단에 달아 사용하기도 한다. 주요 서비스 제공에 무리가 없게 말이다.



지금까지 리눅스 방화벽이 무엇이고, 어떻게 설정하는지, 그리고 추가 설정에 대해 4개의 포스팅을 통해 알아보았다. 사실, 기업에서 서비스 제공을 위해 리눅스를 운용하는 경우, 위에서 언급했다시피 별도의 방화벽 장비를 달아 이 역할을 대신하게 하지만, 서버로 사용자 유입량은 많지 않다고 보안을 무시할 수도 없는 홈 네트워크에서는 리눅스 방화벽으로도 충분히 출처가 불분명한 통신을 제어할 수 있다. 리눅스 방화벽이 명령어로만 제어해야하는 부분이 있어, 익숙하지 않으면 처음에는 멋모르고 SSH 통신이 갑자기 끊기는 상황 등이 많이 발생하는데, 지속적으로 다루면서 익숙해지면 내가 직접 통신을 제어하는 재미에 푹 빠지게 된다.

다음 포스팅에서는, 이전에 공고했던대로 RPM을 통한 패키지 파일 설치에 대해 알아보려 한다.




FIN.




반응형

댓글