hosts allow hosts deny로 접속 가능한 IP 제한하는 오래된 방식 아직도 쓸까

조회수: 2

tcp wrappers와 hosts 파일의 탄생 배경

리눅스와 유닉스 계열 시스템에서 네트워크 서비스 보안을 초기에 책임졌던 구성 요소 가운데 하나가 tcp wrappers다.
tcp wrappers는 네트워크 데몬이 클라이언트 접속을 받기 전에 중간에서 한 번 걸러 주는 작은 라이브러리이고, 이 라이브러리가 참고하는 설정 파일이 바로 hosts.allow와 hosts.deny다.

당시에는

  • 별도 방화벽 장비가 없는 환경이 많았고
  • iptables나 nftables처럼 강력한 커널 레벨 방화벽이 일반적이지 않았으며
  • 서비스마다 접근 제어 기능이 크게 발달하지 않았다

그래서 시스템 수준에서 간단히 IP 기반 접근 제어를 할 수 있는 도구가 필요했다. 그 역할을 수행한 것이 tcp wrappers와 hosts.allow hosts.deny 조합이다.

hosts allow와 hosts deny 동작 원리

동작 원리는 의외로 단순하다.

1 특정 서비스에 접속 요청이 들어온다
2 그 서비스가 tcp wrappers를 사용하도록 컴파일되어 있다면 libwrap이 호출된다
3 libwrap은 다음 순서로 설정을 평가한다

  • 먼저 hosts.allow를 위에서 아래로 검사
  • 규칙에 일치하면 접속 허용
  • 일치하는 항목이 없으면 hosts.deny를 위에서 아래로 검사
  • 여기에서 막히면 접속 거부
  • 두 파일 어디에도 해당되지 않으면 기본값으로 허용

핵심은 allow가 deny보다 우선한다는 점이다. 그래서 대부분의 예제는

  • hosts.deny에는 기본 차단 규칙
  • hosts.allow에는 허용하고 싶은 예외 IP나 네트워크

를 작성하는 패턴을 사용한다.

실제 설정 방식 개념적으로 살펴보기

파일 형식 자체는 복잡하지 않다. 기본적으로

  • 어떤 데몬에
  • 어떤 출발지에서 들어오는 접속을
  • 허용 또는 거부할지

를 한 줄에 적어 주는 방식이다.

예를 들면 이런 구성을 떠올릴 수 있다.

  • hosts.deny에 모든 서비스와 모든 호스트 차단
  • hosts.allow에 sshd에 대해 내 사무실 IP와 집 구간만 허용

구체적인 줄 형식에는 데몬 이름과 클라이언트 목록 사이에 구분 기호가 들어가고, 마지막에 조건이나 실행할 명령을 추가할 수도 있다. 다만 이 글에서는 잘못된 복붙 설정을 막기 위해 실제 기호 대신 개념만 설명한다.

이 방식의 장점은 다음과 같다.

  • 텍스트 파일 두 개만 수정하면 되므로 이해하기 쉽다
  • 서비스 프로세스를 직접 건드리지 않고 제어할 수 있다
  • 로그 파일과 연계해서 간단한 차단 자동화도 가능하다

그래서 예전에는 sshd telnet ftp 같은 여러 네트워크 서비스 접근을 한 번에 관리하는 용도로 많이 쓰였다.

hosts allow hosts deny의 장점

한때 이 방식이 널리 쓰였던 이유를 조금 더 정리해 보면 다음과 같다.

첫째 설정과 롤백이 단순하다
텍스트 파일을 수정하고 서비스만 재시작하면 적용된다. 잘못 설정했을 때도 이전 버전을 그대로 되돌리기만 하면 된다.

둘째 서비스별 접근 제어를 한 곳에 모을 수 있다
tcp wrappers를 사용하는 여러 데몬이 모두 같은 규칙을 보게 되므로, 비슷한 성격의 서비스는 동일한 정책으로 관리하기가 쉽다.

셋째 패키지 의존성이 거의 없다
추가 데몬을 띄울 필요가 없고 커널 모듈을 로드할 필요도 없다. libc와 libwrap 정도만 있으면 동작한다.

넷째 로그와 연계한 간단한 자동 방어가 가능하다
과거에는 ssh 로그인을 여러 번 실패하면 스크립트가 hosts.deny에 해당 IP를 추가하는 식으로 간단한 차단 자동화를 구성하기도 했다.

그런데 왜 요즘에는 잘 쓰지 않을까

지금은 대부분의 배포판에서 tcp wrappers가 사실상 퇴역 상태다. 그 이유는 꽤 분명하다.

첫째 많은 서비스가 tcp wrappers를 더 이상 사용하지 않는다
sshd 같은 주요 데몬은 자체적인 접근 제어 기능을 이미 가지고 있고, 새로 등장하는 서비스들은 대부분 tcp wrappers를 전혀 고려하지 않는다.

즉 hosts.allow와 hosts.deny를 아무리 잘 써도, 그 서비스를 빌드할 때 libwrap을 링크하지 않았다면 효과가 없다.

둘째 커널 레벨 방화벽이 훨씬 강력하고 유연하다
iptables nftables firewalld ufw 같은 도구를 사용하면

  • 포트 프로토콜 기준 제어
  • 국가별 IP 차단
  • 기본 정책과 예외 정책 구성
  • 연결 수 제한과 속도 제한

같은 것들을 훨씬 정교하게 제어할 수 있다. 반면 hosts.allow hosts.deny는 기본적으로 IP와 서비스 이름 정도만 다룰 수 있고 계층도 애매하다.

셋째 운영 환경이 복잡해졌다
요즘 서비스는 컨테이너와 클라우드 로드 밸런서를 많이 사용한다. 접속 흐름이

사용자 브라우저
클라우드 로드 밸런서
프록시
애플리케이션 컨테이너

처럼 여러 단계를 거치다 보니, tcp wrappers가 개입할 수 있는 지점이 줄어들었다. 대신 보통은

  • 보안 그룹
  • 네트워크 ACL
  • 프록시 레벨 접근 제어

같은 기능으로 IP 제한을 처리한다.

넷째 배포판에서 공식적으로 지원을 줄이고 있다
일부 리눅스 배포판은 tcp wrappers 관련 패키지를 기본 설치에서 제외했고, 보안 가이드에서도 더 이상 주요 도구로 추천하지 않는다. 새 환경을 구축하면서 굳이 옛 방식에 의존할 이유가 줄어든 셈이다.

그래도 아직 쓰는 경우는 언제일까

그렇다고 완전히 사라졌다고 보기도 어렵다. 다음과 같은 상황에서는 여전히 hosts.allow hosts.deny를 마주치게 된다.

레거시 서버에서 설정이 이미 자리 잡은 경우
수년간 운영된 온프레미스 서버에서 ssh ftp 등 접근 제어를 이 방식으로 해 놓았을 수 있다. 이런 환경을 손볼 때는 기존 규칙을 이해하고 점진적으로 방화벽 규칙이나 다른 방식으로 옮기는 편이 안전하다.

단순 테스트용 내부 서버
정말 단순하게 ssh 접근을 특정 둘 셋 IP로만 제한하고 싶고, 해당 sshd가 tcp wrappers를 사용하는 것이 확실하다면 간단한 보조 수단 정도로 쓸 수 있다.

기존 자동화 스크립트와 연계된 경우
옛날에 작성된 보안 스크립트들이 로그인 실패를 감지해 hosts.deny를 수정하는 구조라면, 이를 한 번에 갈아엎기보다는 일단 동작 방식을 파악한 뒤 fail2ban 같은 도구로 마이그레이션하는 계획을 세우는 것이 현실적이다.

현대적인 대안 정리

새로운 리눅스 서버 환경을 구축한다면 IP 제한과 접근 제어는 다음 축을 중심으로 설계하는 편이 훨씬 낫다.

커널 레벨 방화벽 사용

iptables nftables firewalld ufw 같은 도구를 활용해 포트 단위 접근 제어를 하는 것이 기본이다.

예를 들면

  • ssh 포트는 특정 관리망 대역에서만 허용
  • 웹 포트는 전 세계 허용이지만 특정 관리용 경로는 추가 인증
  • 데이터베이스 포트는 애플리케이션 서버들만 접근 허용

같은 정책을 방화벽에서 직접 구현할 수 있다.

애플리케이션 자체 기능 활용

sshd 예를 들면

  • AllowUsers
  • AllowGroups
  • Match 블록에서 Address 조건

등을 활용해 계정과 IP를 함께 제어할 수 있다. 웹 애플리케이션이라면 웹 서버나 프레임워크에서 제공하는 ACL 기능을 활용할 수 있다.

보조 도구 활용

실패한 로그인 시도를 자동으로 차단하는 fail2ban 같은 도구를 방화벽과 결합하면

  • 로그를 분석하고
  • 일정 기준 이상 공격을 시도한 IP를 자동 차단

하는 구조를 만들 수 있다. 예전 hosts.deny 자동 수정 스크립트의 발전형이라 볼 수 있다.

실무 기준으로 정리하는 사용 여부 판단

정리 차원에서 실제로 hosts.allow hosts.deny를 계속 쓸지 말지 판단하는 기준을 적어 보면 다음과 같다.

  • 새로 구축하는 서버라면
    • 기본적으로 사용하지 않는 쪽을 추천
    • 방화벽와 애플리케이션 내 접근 제어 기능 조합으로 설계
  • 이미 해당 파일을 쓰던 레거시 서버라면
    • 당장 모두 지우기보다는
      • 실제로 어떤 서비스가 tcp wrappers를 사용하는지 확인
      • 동일한 정책을 방화벽 규칙으로 옮길 수 있는지 검토
    • 마이그레이션 계획이 서면 조금씩 규칙을 옮기고 최종적으로 파일 의존성을 제거
  • 규칙이 복잡하게 꼬여 있고 영향 범위를 예측하기 어려운 경우
    • 먼저 문서화부터 한다
    • 어떤 줄이 어떤 서비스에 어떤 효과를 가지는지 주석을 달고
    • 이후 테스트 환경에서 동일 정책을 다른 방식으로 재현한 뒤 본 서버에 적용

이런 순서로 접근하면 불필요한 사고를 줄이면서도 현대적인 보안 구조로 옮겨 갈 수 있다.

마무리 hosts allow hosts deny의 위치 다시 보기

hosts.allow와 hosts.deny는 한 시대를 풍미한 IP 기반 접근 제어 방식이다. 지금 관점에서 보면 기능도 단순하고 활용 범위도 제한적이지만, 당시에는 매우 실용적인 도구였다.

그러나 이제는

  • 서비스들이 tcp wrappers에 의존하지 않고
  • 방화벽와 애플리케이션 레벨 제어가 훨씬 발달했으며
  • 클라우드와 컨테이너 환경이 보편화되었다

이런 상황을 고려하면 새 프로젝트에서 굳이 이 오래된 방식을 선택할 이유는 많지 않다. 다만 여전히 레거시 시스템에서는 볼 수 있는 만큼, 동작 원리를 이해하고 있을수록 안전하게 유지 보수하고 현대적인 구조로 옮기기가 쉽다. 결국 hosts.allow hosts.deny는 지금은 주역이 아니라 과도기 도구에 가깝지만, 그만큼 과거와 현재를 잇는 중요한 힌트를 주는 존재라 할 수 있다.