리눅스 보안 취약점을 적용할 때 항상 나오는 부분 중 하나가 “접속 IP 및 포트 제한”입니다. 불법적인 접근을 애초에 차단하기 위해 방화벽(Firewall)을 사용하여 접근 가능한 IP를 추가하고 등록된 호스트만 접근하도록 하는 것이 목적입니다. 주로 ssh, telnet 그리고 ftp와 같은 서비스가 대상이며, 이런 서비스들은 정보 노출 시 시스템 정보가 탈취될 수 있는 위험이 있습니다. RHEL(Red Hat Enterprise Linux) 7 버전까지는 이러한 보안 조치를 TCP Wrapper 기능을 이용해 설정했습니다. 그러나 RHEL 8 버전부터는 이러한 설정을 방화벽(Firewall)을 통해 수행합니다. 아래와 같은 방법을 통해 원하는 IP 또는 IP 대역의 접근을 제한할 수 있습니다.
- 이전 TCP Wrapper를 사용해 sshd 데몬 접근 IP를 제한하던 방법 <RHEL7 이하>
# cat /etc/hosts.deny
sshd : 59.63.166.102
sshd : 141.
sshd : 50.
위와 같이 설정하면 sshd를 이용한 접근이 방화벽에서 허용되어 있더라도 59.63.166.102 서버와 141. 그리고 50. 대역의 클라이언트만 접근이 허용됩니다.
Deprecate TCP wrappers
RHEL8 버전부터 TCP wrapper의 연결을 통제하던 hosts.allow, hosts.deny 기능이 사라졌습니다. 레드햇의 업스트림(Upstream) 프로젝트인 페도라에서 TCP Wrapper에 대해 아래와 같이 안내하고 있습니다.
TCP wrappers is a simple tool to block incoming connection on application level. This was very useful 20 years ago, when there were no firewalls in Linux. This is not the case for today and connection filtering should be done in network level or completely in application scope if it makes sense. After recent discussions I believe it is time to go for this package, if not completely, than at least as a dependency of modern daemons in system by default.
참고: <https://fedoraproject.org/wiki/Changes/Deprecate_TCP_wrappers>
사이트의 내용은 다음과 같이 요약해 볼 수 있습니다.
“TCP wrappers는 20년 전 리눅스 환경에서 중요한 보안 도구였습니다. 그러나 현대의 네트워크 환경에서는 그 효용성이 크게 감소했습니다. 현재는 iptables, nftables 등의 방화벽 도구나 애플리케이션 자체의 보안 기능으로 더 효과적인 네트워크 보안이 가능합니다. TCP wrappers는 20년간 큰 업데이트 없이 유지되어 왔으며, 새로운 보안 위협에 대응하기 어려운 상황입니다.
TCP wrapper 없이 IP 접근 제한
IP 접근 제한은 주로 리눅스 방화벽 서비스(firewalld)를 통해 구현할 수 있습니다. 그러나 방화벽을 사용하지 않는 경우, 다음과 같은 대안을 고려할 수 있습니다
- 서비스 자체의 접근 제한 기능 활성화
- 리눅스 방화벽 설정
- 외부 방화벽 설정
결론적으로, 서비스에 자체 접근 제한 기능이 있다면 이를 우선적으로 활용하고, 그렇지 않은 경우 방화벽 서비스를 통해 IP 접근을 제한하는 것이 바람직합니다.
SSH 자체 접근 제한 기능 활성화
환경
Red Hat Enterpriese Linux 7
Red Hat Enterpriese Linux 8
Red Hat Enterpriese Linux 9
ssh 데몬 에서 제공하는 기능을 통하여 특정 IP대역의 사용자에게만 ssh 서비스 연결을 허용해 줄 수 있습니다. 먼저 리눅스 man 페이지에서 설명서를 확인해 보면 “AllowUsers” 기능이 있는데 이 기능을 통해 IP를 제한할 수 있습니다.
# man sshd_config
...
AllowUsers
This keyword can be followed by a list of user name patterns, separated by spaces. If speci‐
fied, login is allowed only for user names that match one of the patterns. Only user names are
valid; a numerical user ID is not recognized. By default, login is allowed for all users. If
the pattern takes the form USER@HOST then USER and HOST are separately checked, restricting
logins to particular users from particular hosts. HOST criteria may additionally contain
addresses to match in CIDR address/masklen format. The allow/deny directives are processed in
the following order: DenyUsers, AllowUsers, DenyGroups, and finally AllowGroups.
요약해 보면 특정 사용자로 로그인을 제한할 수 있는 기능인데 “USER@HOST” 형식을 이용하면 유저가 접속한 IP대역을 확인해서 제한하는 방법도 가능합니다. 예를 들어, USER에 “*”을 사용하고 HOST 부분에 원하는 IP 대역을 넣으면, IP로만 제한하는 설정이 가능합니다.
기본적으로 /etc/ssh/sshd_config 파일에는 AllowUsers 항목이 없으므로 원하는 항목을 직접 추가하면 됩니다. 허용하고 싶은 IP 대역 또는 IP 주소를 새로운 줄에 계속 추가할 수 있습니다.
# vim /etc/ssh/sshd_config
...
AllowUsers *@192.168.180.*
AllowUsers *@192.168.155.92
AllowUsers *@192.168.155.88
# systemctl reload sshd
sshd의 경우 reload를 제공합니다. reload는 restart와 다르게 프로세스 종료 없이 설정을 불러오기 때문에 PID가 변경되지 않습니다. 따라서 연결되어 있는 다른 서비스와의 관계를 유지하게 해주는 유용한 기능입니다.
AllowUsers를 사용하게 되면 이제 지정된 IP 이외의 다른 곳으로부터의 접속은 차단되게 됩니다. 만약 차단된 대역에서 접근하면 아래와 같이 Permission denied로 표시되게 됩니다.
# ssh 192.168.155.76
root@192.168.155.76's password:
Permission denied, please try again.
Firewalld 를 이용한 SSH 접근 제한
리눅스 firewall은 사용자 요구에 맞는 거의 모든 설정이 가능할 만큼 다양한 기능이 있습니다. 때문에 IP를 제한하는 여러 가지 방법이 있을 수 있습니다.
가장 일반적으로 사용할 수 있는 두 가지 환경으로 분류해서 설명 드리도록 하겠습니다:
- 모든 서비스를 활성화하고 SSH만 IP를 제한하는 방법
- firewalld의 다른 서비스는 건드리지 않고 SSH만 제한하는 설정
[Firewall 방법-1] 모든 대역 허용하고 SSH만 제한하기
이 방법은 방화벽 사용을 원하지 않고 SSH만 접근 제어하고 싶은 경우에 사용할 수 있습니다. Firewalld를 안 쓰는 것이 아니라 Firewalld를 기동한 뒤에 모든 포트를 허용하는 방식입니다. 대부분의 기업들이 외부 방화벽을 사용 중이기 때문에 리눅스 방화벽은 꺼두는 그런 환경에서 유용합니다. 이렇게 리눅스에서 모든 포트를 오픈하면 외부 방화벽에 의해서만 제어가 가능합니다.
순서:
- 방화벽 활성화
- SSH를 제외한 모든 포트 허용
- SSH 포트 IP 제한
설정을 시작하기 전에 방화벽을 잘못 건드리면 SSH 접속이 안될 수 있으므로 콘솔에서 작업을 권장 드립니다.
- 방화벽 시작: 가장 처음 방화벽 서비스를 기동합니다.
[root@rhel8 ~]# systemctl enable firewalld --now Created symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service → /usr/lib/systemd/system/firewalld.service. Created symlink /etc/systemd/system/multi-user.target.wants/firewalld.service → /usr/lib/systemd/system/firewalld.service.
- SSH 서비스 차단SSH의 경우 기본으로 활성화되어 있을 수 있는데, 22번 포트는 나중에 특정 IP 대역에서만 오픈할 예정이므로 미리 차단합니다.
[root@rhel8 ~]# firewall-cmd --remove-service=ssh --permanent success [root@rhel8 ~]# firewall-cmd --reload success [root@rhel8 ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: cockpit dhcpv6-client dns ports: protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
–list-all 명령을 이용해 현재 설정 내역을 확인해 보면 “ssh”가 사라진 걸 보실 수 있습니다. 이제 리눅스 방화벽에 의해 22번의 접근은 모두 차단됩니다.
- ssh를 제외한 모든 포트 오픈
[root@rhel8 ~]# firewall-cmd --permanent --add-port=1-21/tcp success [root@rhel8 ~]# firewall-cmd --permanent --add-port=1-21/udp success [root@rhel8 ~]# firewall-cmd --permanent --add-port=23-65535/tcp success [root@rhel8 ~]# firewall-cmd --permanent --add-port=23-65535/udp success [root@rhel8 ~]# firewall-cmd --reload success
[root@rhel8 ~]# firewall-cmd --permanent --add-port=1-21/tcp success [root@rhel8 ~]# firewall-cmd --permanent --add-port=1-21/udp success [root@rhel8 ~]# firewall-cmd --permanent --add-port=23-65535/tcp success [root@rhel8 ~]# firewall-cmd --permanent --add-port=23-65535/udp success [root@rhel8 ~]# firewall-cmd --reload success
–permanent 옵션을 추가하면 설정 파일에만 룰이 적용되므로, 현재 런타임 환경에 적용하려면 firewall-cmd –reload 명령을 사용해야 합니다.
이제 다시 조회해보면 22번 포트를 제외한 전체 포트가 오픈되어 있는 것을 확인할 수 있습니다.
[root@rhel8 ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: cockpit dhcpv6-client dns ports: 1-21/tcp 1-21/udp 23-65535/tcp 23-65535/udp protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
- 특정 대역만 ssh허용 <rich Rule>firewalld는 리치 규칙(Rich Rule)을 이용해 기본 firewalld 구문으로 할 수 없는 유연한 사용자 지정 방화벽 규칙을 작성할 수 있습니다.
[root@rhel8 ~]# firewall-cmd --add-rich-rule='rule family=ipv4 source address=192.168.155.0/24 service name=ssh accept' --permanent success [root@rhel8 ~]# firewall-cmd --reload success
위 명령은 192.168.155.0/24 대역에서 접근하는 IP만 허용하는 리치 규칙을 설정하는 예제입니다.
<리치규칙 사용 방법>
- -add-rich-rule='<RULE>’: 지정된 영역 또는 기본 영역에 <RULE>을 추가합니다.
- -remove-rich-rule='<RULE>’: 지정된 영역 또는 기본 영역에서 <RULE>을 제거합니다.
리치 규칙 제거는 아래와 같이 생성 명령어에서 add를 remove로 변경하면 됩니다.
# firewall-cmd --remove-rich-rule='rule family=ipv4 source address=192.168.155.0/24 service name=ssh accept' --permanent
적용된 방화벽 규칙을 조회하면 맨 아래에 리치 규칙이 정상적으로 설정된 것을 확인할 수 있습니다. 이제 이 서버의 SSH는 192.168.155.0/24 소스를 가진 서버에서만 가능합니다.
[root@rhel8 ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: cockpit dhcpv6-client dns ftp ports: 1-21/tcp 1-21/udp 23-65535/tcp 23-65535/udp protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="192.168.155.0/24" service name="ssh" accept
[Firewall 방법-2] 기존 설정 그대로 두고 SSH 서비스만 규칙 적용
방화벽을 이미 사용 중인 경우, SSH만 제외하고 리치 규칙(Rich Rule)을 이용하여 SSH를 추가로 허용할 수 있습니다. 사실 모든 서비스를 허용하는 부분만 제외하면 1번 방법과 유사합니다.
순서:
- firewalld에서 SSH 포트 제거
- 리치 규칙을 이용해 SSH 포트에 접속할 IP 추가
- 기존 SSH 포트 제거
[root@rhel8 ~]# firewall-cmd --remove-service=ssh --permanent success [root@rhel8 ~]# firewall-cmd --reload success
- rich Rule 추가리치 규칙은 원하는 만큼 계속 추가할 수 있습니다. 접근 가능한 IP 대역은 물론 특정 IP를 지정해서도 추가할 수 있습니다.
[root@rhel8 ~]# firewall-cmd --add-rich-rule='rule family=ipv4 source address=192.168.155.92 service name=ssh accept' --permanent success [root@rhel8 ~]# firewall-cmd --add-rich-rule='rule family=ipv4 source address=192.168.155.76 service name=ssh accept' --permanent success [root@rhel8 ~]# firewall-cmd --reload success
아래는 두 개의 리치 규칙이 설정된 모습입니다.
[root@rhel8 ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: cockpit dhcpv6-client dns ftp ports: 1-21/tcp 1-21/udp 23-65535/tcp 23-65535/udp protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" source address="192.168.155.76" service name="ssh" accept rule family="ipv4" source address="192.168.155.92" service name="ssh" accept
방화벽에서 접근이 거부되는 경우 아래와 같은 오류가 발생합니다.
[root@rhel82 ~]# ssh 192.168.155.88 ssh: connect to host 192.168.155.88 port 22: No route to host
TCP wrappers 기능은 이제 firewalld로 대체되었지만, 대부분의 리눅스 시스템에서 firewalld를 사용하지 않아 보안 취약점 조치 시 처리 방안에 대한 고민이 생기기 마련입니다. sshd는 자체적으로 접속 제한 기능을 제공하지만, vsftpd와 같이 그런 기능이 없는 경우 리눅스 firewalld로 진행하거나 예외 처리를 고려해야 합니다. 다행히 많은 사람들이 사용하는 sshd는 IP 제한 기능을 제공하고 있습니다.
참고
https://fedoraproject.org/wiki/Changes/Deprecate_TCP_wrappers [fedora TCP Wrappers]