본문 바로가기
카테고리 없음

리눅스 설치 후 반드시 해야 할 보안설정(2): 리눅스 방화벽, SElinux 규칙 검토

by 기본기를 다지는 블로그 2025. 3. 12.

1. 리눅스 방화벽 설정 검토

사실 현업에서는 서버 앞 단의 L3/L4 방화벽 (IP, TCP, UDP 필터링), L4/L7 (api세션 트래픽, HTTP/HTTPS 웹공격 차단), 접근제한 솔루션 등을 이용하여 서버 접속을 차단하기 때문에 OS수준의 방화벽이 필요할까? 생각되지만, 서버 내부의 트래픽 제어(특정 포트, IP 차단, outbound 트래픽 관리)를 위해 여전히 유용합니다.  

 

특히, 클라우드 환경에서는 보안 그룹과 함께 OS 방화벽을 추가적인 보안 계층으로 활용하는 경우가 많습니다.

 

1. firewalld

firewalld는 iptables의 후속 기술로 등장했고, 더 유연하고 동적인 방화벽 관리를 제공합니다.

Zone 기반 영역 관리: 네트워크 인터페이스 마다 서로 다른 보안 정책을 커스텀하게 적용할 수 있습니다.

[root@navix95 ~]# firewall-cmd --get-zones
block dmz drop external home internal nm-shared public trusted work

 

예를 들어 기본적으로 적용되는 zone인 public(default)은 필요한 경우 선택적으로 들어오는 연결을 허용합니다.

drop zone은 가장 낮은 신뢰 수준을 규정하여 모든 들어오는 연결을 응답 없이 삭제하고, 나가는 연결만 허용합니다.

 

 

이로써 각각 zone들의 자체 성질에 따라 현업 상황에 맞게 ip 또는 services/port 를 규정할 수 있습니다.

아래에 firewalld에 관한 설명이 자세하게 나와 있네요.

 

https://docs.rockylinux.org/ko/guides/security/firewalld-beginners/

 

초보자를 위한 firewalld - Documentation

초보자를 위한 firewalld소개오래 전에 나는 작고 새내기 컴퓨터 사용자로서 방화벽을 가지는 것이 아주 좋다는 얘기를 들었습니다. 내 컴퓨터로 무엇이 들어오고 무엇이 나가는지 내가 결정할 수

docs.rockylinux.org

 

위 링크는 기본적인 firewalld에 대한 설명이 매우 훌륭하므로 저는 현업에서 사용 가능할 몇몇 기능에 대해 다뤄보도록 하겠습니다.

 

* 테스트 환경은 네이버리눅스 navix9.5이며 firewall-cmd 명령을 사용하였습니다.

 

1.1. firewalld-cmd의 IPset 기능

ipset이란 ip주소 세트를 그룹화하여 접근을 제한할 수 있는 기능입니다.

저는 해당 서버에 접근할 수 있는 게이트웨이 서버와 테스트 서버를 허용(allow)하고 나머지는 모두 차단(drop)시키는 정책을 사용하고자 합니다. 

 

사전 요구사항:

firewalld 프로세스가 실행 중이어야 합니다.

iptable기반의 ipset은 rhel9부터 사용되지 않습니다. 반드시 firewall-cmd 기반의 ipset을 사용하세요.

 

절차:

1. 의미 있는 이름으로 IP 세트를 생성합니다.

firewall-cmd --permanent --new-ipset=allowlist --type=hash:ip

allowlist 라는 새 IP 세트에는 방화벽에서 허용할 IP 주소가 포함되어 있습니다.

 

2. IP 세트에 동적 업데이트를 추가합니다. 저는 ip를 나열한 파일을 제작하여 firewalld에 등록하였습니다.

[root@navix95-test ~]# cat > /root/entryfile.txt <<EOL
172.30.1.97
172.30.1.196
1.1.1.1
2.2.2.2
EOL

[root@navix95-test ~]# firewall-cmd --permanent --ipset=allowlist --add-entries-from-file=/root/entryfile.txt

 

등록한 IP 정보를 아래와 같이 확인합니다. 

ip를 등록할 때 주의할 점은 firewalld의 ipset 기능은 서브넷의 범위나  IP중복에 대해 매우 엄격하므로 정확히 기입해야 합니다. 정확하지 않을 경우 오류가 발생합니다.

[root@navix95-test ~]# firewall-cmd --permanent --ipset=allowlist --get-entries
172.30.1.196
172.30.1.97
1.1.1.1
2.2.2.2

OR

[root@navix95-test ~]# cat /etc/firewalld/ipsets/allowlist.xml
<?xml version="1.0" encoding="utf-8"?>
<ipset type="hash:ip">
  <entry>172.30.1.196</entry>
  <entry>172.30.1.97</entry>
  <entry>1.1.1.1</entry>
  <entry>2.2.2.2</entry>
</ipset>

만약 python 구문 오류가 발생한다면 위의 allowlist.xml 파일을 수정하면서 트러블슈팅할 수 있습니다.

구문의 오류가 있으면 오류가 발생합니다.

 

firewalld의 rich rule을 이용하여 자세한 정책을 추가합니다.

 - "allowlist"에 포함된 ip가 아닌 (NOT),  source 및 대상 주소는 "drop"  시킨다.

# firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source not ipset="allowlist" drop'
# firewall-cmd --runtime-to-permanent
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens192
  sources: ipset:allowlist
  services: cockpit dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
rule family="ipv4" source NOT ipset="allowlist" drop

 

firewalld 의 IPset 기능에 대해 확인해 보았는데요, 대량의 IP나 대역을 지정하여 넓은 범위의 접근 제한 규칙을 설정할 수 있습니다. 예를들어 "국내 대역은 허용하고 해외 대역은 모두 차단" 같은 정책을 지정할 수도 있습니다.

 

2. nftable 

nftables 프레임워크는 패킷을 분류하고 iptables,ip6tables,arptables,ebtables, ipset 유틸리티의 후속 조치입니다.

이전의 패킷 필터링 툴에 비해 편의성, 기능 및 성능이 크게 향상되었습니다.

사용해보니 iptables 보다 규칙 구성이나 설정이 수월한거 같습니다.

 

예로 172,30.1.196 ip의 22, 443 포트를 차단하는 룰을 지정해 보겠습니다.

 

nft 정책 확인

아래는 위의 정책을 기입한 후 INPUT 체인의 규칙을 출력한 내용입니다.

[root@navix95-test ~]# nft add rule inet nftables_svc INPUT ip saddr 172.30.1.196 tcp dport { 22, 443 } drop
[root@navix95-test ~]# nft -a list table inet nftables_svc
table inet nftables_svc { # handle 40
chain INPUT { # handle 1
type filter hook input priority filter; policy accept;
tcp dport 22 accept # handle 2
tcp dport 443 accept # handle 3
tcp dport 80 accept # handle 4
ip saddr 172.30.1.196 tcp dport { 22, 443 } drop # handle 5
}
}

 

기본 체인 규칙이 accept이므로 drop 정책을 맨 마지막에 설정하면 규칙이 동작하지 않습니다.

 

따라서 drop할 규칙을 제일 먼저 위치시켜야 하는데요, 이럴때 체인 시작 부분에 규칙을 추가하려면 nft add 대신 nft insert 명령을 사용하면 됩니다.

[root@navix95-test ~]# nft insert rule inet nftables_svc INPUT ip saddr 172.30.1.196 tcp dport { 22, 443 } drop
[root@navix95-test ~# nft -a list table inet nftables_svc
table inet nftables_svc { # handle 40
chain INPUT { # handle 1
type filter hook input priority filter; policy accept;
ip saddr 172.30.1.196 tcp dport { 22, 443 } drop # handle 5
tcp dport 22 accept # handle 2
tcp dport 443 accept # handle 3
tcp dport 80 accept # handle 4
}
}


이로써 예상된 동작을 확인할 수 있습니다.

과거 iptables와 기능면에서 매우 흡사하고 기존 iptables의 정책도 마이그레이션이 가능하며,  기능 개선과 성능 향상이 이루어졌다고 하니 꼭 알아가야 할 훌륭한 툴입니다.

 

3. SElinux 검토

SElinux의 문제점:

SElinux의 가장 큰 문제점은 무엇일까요? 바로 우리가 SElinux를 귀찮아 하고 어려워하기 때문입니다.

SElinux를 친숙하게 다룰 수 있는 방법을 찾아보겠습니다.

 

SELinux는 프로그램 또는 데몬의 위험성을 제거하거나 권한을 제한하여 프로그램이 불법적으로 접근하는 것을 방지합니다. 원래 리눅스는 파일이나 프로그램을 "소유자/그룹/기타" 개념으로 권한을 관리하는데, 이 방식만으로는 보안이 취약할 수 있습니다. (DAC 규칙)

 

SElinux는 여기에 추가로 "이 프로그램이 이 파일을 건드려도 되는지?" 세밀하게 체크하는 시스템입니다.(RBAC 규칙)

 

SElinux의 기본적인 설명은 아래 링크에 자세히 나와 있으니 참고 하시면 좋을거 같습니다.

https://docs.rockylinux.org/ko/guides/security/learning_selinux/

 

SELinux 보안 - Documentation

SELinux securitySELinux 보안2.6 버전의 커널이 도입되면서, 액세스 제어 보안 정책을 지원하기 위한 보안 메커니즘이 도입되었습니다.이 시스템은 SELinux(Security Enhanced Linux - 보안 강화 리눅스)라고 하

docs.rockylinux.org

 

위 개념을 바탕으로 응용한 예를 들어 보겠습니다.


1. 사용자가 실수로 이상한 프로그램을 실행했다면?

SElinux는 "이 프로그램이 이 파일을 만질 권한이 있어?"라고 따져보고, 이상하면 차단합니다.

  • "이 프로그램이 원래 이 파일을 만질 수 있는 프로세스 유형인가?"
  • "이 파일의 보안 컨텍스트와 일치하는가?"

 

또는

 

2. 아파치 웹 서버가 해킹당했다면?

SElinux가 없을경우: 공격자가 웹 서버를 통해 시스템 전체를 공격할 수도 있음.

SElinux가 있을경우: "아파치(httpd 프로세스)는 웹 폴더만(/var/www/html/*) 접근 가능해!"라고 제한을 걸어둬서 시스템 보호 가능.


 

아래는 위 전제를 바탕으로 SElinux가 구동중일 경우 보안 측면에서 특정 프로세스를 제한하고, 권한을 부여하는지 확인할 수 있는 응용 예시 입니다.

 

SElinux에 정의 된 정책 중 httpd 프로세스가 디렉토리에 접근할 경우 권한과 관련된 보안 컨텍스트에 할당되어 있는지 확인하는 명령입니다.

# semanage fcontext -l | grep httpd # SELinux에서 파일 유형을 미리 정의해 둔 목록을 확인할 수 있습니다.
/var/www(/.*)?                     all files          system_u:object_r:httpd_sys_content_t:s0
/var/www/html(/.*)?                 all files          system_u:object_r:httpd_sys_content_t:s0

 

/var/www/html/testfile 파일의 도메인과 컨텍스트를 확인합니다.

# ls -Z /var/www/html # 파일이나 디렉터리에 어떤 SELinux 컨텍스트가 적용되어 있는지 직접 확인할 수도 있습니다.
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 testfile

 

/var/www/html/testfile의 컨텍스트를 확인해보면 "파일을 httpd_sys_content_t 타입으로 설정하면, 해당 파일을 HTTPD 시스템 콘텐츠로 처리할 수 있습니다." 라고 명시합니다. 

 httpd_sys_content_t 타입은 /var/www/html/testfile을 읽고 쓰고 변경할 수 있는 권한이 있는 것입니다.

# man httpd_selinux # selinux-policy-doc selinux 문서 패키지 설치
...
httpd_sys_content_t

       - Set files with the httpd_sys_content_t type, if you want to treat the files as httpd sys content.

 

추가적인 실습을 통해 유형(Type)이 다른경우 httpd 프로세스가 액세스 할 수 있는지 확인 해보겠습니다.

 

root 로 httpd 데몬을 시작합니다.

~]# systemctl start httpd.service

 

서비스가 실행 중인지 확인합니다. 출력에는 아래 정보가 포함되어야 합니다.

~]$ systemctl status httpd.service
httpd.service - The Apache HTTP Server
	  Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
	  Active: active (running) since Mon 2013-08-05 14:00:55 CEST; 8s ago

 

Linux 사용자가 액세스에 대한 쓰기 권한이 있는 디렉터리로 변경하고 다음 명령을 입력합니다. 기본 구성을 변경하지 않는 한 이 명령은 성공합니다.

~]$ wget http://localhost/testfile
--2009-11-06 17:43:01--  http://localhost/testfile
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 0 [text/plain]
Saving to: `testfile'

[ <=>                              ] 0     --.-K/s   in 0s

2009-11-06 17:43:01 (0.00 B/s) - `testfile' saved [0/0]

 

 root로 다음 명령을 입력하여 유형을 Samba에서 사용하는 유형으로 변경합니다. chcon 명령은 파일의 레이블을 다시 지정하지만 파일 시스템의 레이블을 다시 지정할 때 이러한 레이블 변경 사항은 유지되지 않습니다. (영구적용은 semanage 명령 사용)

~]# chcon -t samba_share_t /var/www/html/testfile

 

변경 사항을 보려면 다음 명령을 입력합니다.

~]$ ls -Z /var/www/html/testfile
-rw-r--r--  root root unconfined_u:object_r:samba_share_t:s0 /var/www/html/testfile

 

현재 DAC 권한을 사용하면 httpd 프로세스에서 testfile 에 액세스할 수 있습니다.

사용자가 쓰기 액세스 권한이 있는 디렉터리로 변경하고 다음 명령을 입력합니다. 기본 구성을 변경하지 않는 한 이 명령은 실패합니다.

~]$ wget http://localhost/testfile
--2009-11-06 14:11:23--  http://localhost/testfile
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 403 Forbidden
2009-11-06 14:11:23 ERROR 403: Forbidden.

 

root 로서 testfile 제거 :

~]# rm -i /var/www/html/testfile
~]# systemctl stop httpd.service

 

이 예에서는 SELinux에서 추가된 추가 보안을 보여줍니다.

파일 권한으로만 본다면 DAC 규칙에 따라 testfile 에 대한 기본적인 액세스는 처리할 수 있습니다.

하지만 파일이 httpd 프로세스에 액세스할 수 없는 samba_share_t  유형으로 레이블이 지정되었기 때문에 SELinux는 액세스를 거부했습니다. (ERROR 403: Forbidden.)

 

따라서 파일의 유형을 정확히 지정하는것은 매우 중요합니다.

 

그러면 /var/www/html/testfile 라는 파일의 httpd_sys_content_t 레이블에 액세스할 수 있는 도메인은 무엇일까요?

해당 레이블의 도메인을 확인하려면, 이 파일을 접근하는 프로세스를 확인해야 합니다.

 

httpd_sys_content_t 컨텍스트 자체가 httpd 프로세스가 읽을 수 있는 컨텍스트 이기 때문에 httpd 프로세스를 ps -Z 명령으로 확인합니다.

# ps -Z | grep httpd
system_u:system_r:httpd_t:s0    1234 ?  00:00:00 httpd

 

여기서 "httpd_t"가 바로 /var/www/html/testfile 파일을 사용하는 httpd 프로세스의 도메인이군요!

 

SElinux 정책에서 httpd_t 도메인이 httpd_sys_content_t 유형(Type)의 파일에 어떤 접근(Access)을 할 수 있는지 확인하는 명령으로도 확인이 가능합니다. read, write, open,create, execute 등의 권한을 확인할 수 있습니다.

# sesearch -A -s httpd_t -t httpd_sys_content_t -c file
allow domain file_type:file map; [ domain_can_mmap_files ]:True
allow httpd_t httpd_content_type:file { getattr ioctl lock map open read };
allow httpd_t httpdcontent:file { append create getattr ioctl link lock open read rename setattr unlink watch watch_reads write }; [ ( httpd_builtin_scripting && httpd_unified && httpd_enable_cgi ) ]:True
allow httpd_t httpdcontent:file { execute execute_no_trans getattr ioctl map open read }; [ ( httpd_builtin_scripting

 


 

SElinux 사용 예시를 살펴보면서 확인한 중요한 내용은 일반 파일의 권한만으로는 프로세스 간의 세부적인 접근 통제를 할 수 없다는 점 입니다.

위 예시는 DAC 규칙에 따라 testfile에 대한 액세스를 처리할 수 있지만 "httpd_sys_content_t"와 같은 타입이 다를경우 액세스가 거부될 수 있습니다.

따라서 프로세스마다 정해진 정책의 범위 안에서 작동하도록 하는것이 SElinux의 기본적인 컨셉이라고 할 수 있습니다.

 


 

SElinux 모드(설정 방법)

SElinux는 크게 3가지 모드가 있습니다.
Enforcing(엄격 모드)  → 규칙 어기면 바로 차단
Permissive(허용 모드)  → 차단하지 않고 기록만 남김
Disabled(비활성화)  → SElinux 기능을 끔

 

모드 확인하는 명령어

getenforce  # 현재 모드 확인
setenforce 0  # Permissive(허용 모드)로 변경
setenforce 1  # Enforcing(엄격 모드)로 변경

 

SELinux 상태를 확인하는 방법

[root@navix95-test /tmp]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33

 

이번 글에서 firewalld, nftable, SElinux 등과 같은 보안 설정 요소들의 개념과 실제 응용에 대해 알아 보았는데요,

보안설정이라는 것 자체가 범위가 워낙 넓고 깊기 때문에 알아가야 할 것들이 많지만, 완벽하지는 않아도 관심을 가지고 기본 개념을 하나씩 파악하고 실천해 나간다면 우리의 서버 보안을 더욱 튼튼히 해줄 수 있을것이라 확신합니다.