• 모닥위키모닥위키
  • 모닥위키
위키
  • 인기글
  • 목록
  • 시리즈
  • 임의열람
    AAAdddvvveeerrrtttiiissseeemmmeeennntttAdvertisement

    © 2025 modak.wiki All rights reserved.

    IP Geolocation by DB-IP

      지역기반 IP로 방화벽 강화하기

      지역기반 IP를 활용하여 iptables 방화벽 규칙을 적용시킨 작업기록입니다.

      컴퓨터/IT작업기록
      lu

      luasenvy (luasenvy)

      CC BY 4.0 국제규약

      iptables

      리눅스를 설치하면 네트워크 패킷 관리자로 iptables 패키지를 만나볼 수 있다. 여러가지 규칙들을 선언하여 커널단위에서 패킷을 차단하거나 허용할 수 있어서 어플리케이션까지 패킷이 전달되어 컴퓨터 자원이 소모되는 것을 최소화할 수 있다. 지역기반 IP 정보로 Nginx 필터 설정하기를 참고하면 DB-IP에서 제공하는 지역기반 IP(이하 GeoIP) 데이터베이스를 활용하여 Nginx 트래픽 차단을 설정한 내역을 확인해볼 수 있다. 이 문서에서는 이와 동일한 데이터 베이스를 활용하여 iptables에 적용하는 방법을 소개하고자 한다.

      xt_geoip

      CLI
      sudo apt install xtables-addons-common libtext-csv-xs-perl unzip
      

      iptables의 애드온으로 간단한 명령을 통하여 설치할 수 있다. 다른 라이브러리는 이후에 빌드를 위해 필요한 라이브러리다. 우선 앞서 소개한 DB-IP 홈페이지로 들어가서 Lite Country 버전의 데이터베이스를 'csv'형식으로 다운로드 받는다. 적당한 위치에 위치시킨 후 xt_geoip가 사용할 수 있는 형태로 빌드를 해야 한다.

      CLI
      sudo /usr/libexec/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip
      sudo modprobe xt_geoip
      
      # 활성화 확인
      sudo lsmod | grep xt_geoip
      
      # 재부팅 시에도 자동으로 로드시키려면
      echo "xt_geoip" | sudo tee -a /etc/modules-load.d/xt_geoip
      

      국가 코드별로 v4, v6에 해당하는 IP 대역이 모두 변환되어 파일로 저장되는데 상당히 많은 파일이 생성되어 오래걸릴 수도 있다. 완료되고 나면 커널모듈로 xt_geoip를 사용할 수 있게 활성화 해주어야 한다. lsmod | grep xt_geoip를 통해서 활성화 되었는지 확인할 수 있다.

      CLI
      sudo iptables -A INPUT -p tcp --dport 22 -m geoip ! --src-cc KR -j DROP
      

      사전 작업이 모두 끝났으니 실제로 방화벽 규칙을 추가하여 트래픽을 제어할 수 있다. 한국 이외 지역에서 들어오는 ssh 포트 패킷을 모두 버리는 규칙이다. iptables의 규칙은 순서대로 작동하며 -A옵션으로 가장 마지막 규칙으로 추가할 수 있다. 설정이 잘못되면 ssh 접속이 불가능한 경우가 생길 수 있으므로 주의하고 콘솔로 접속할 수 있는 대책을 준비하는 것이 좋다.

      웹 접근 제어

      이 방법을 활용하면 Nginx와 mmdb를 연동한 접근제어보다 더 효율적인 지역별 접근 제어를 할 수 있다. 두 가지 모두 동일한 데이터베이스를 사용하며 동일한 결과를 얻기 위한 작업이기 때문에 iptables를 활용한다면 패킷이 어플리케이션까지 도달하는데 필요한 OSI 7계층 작업들을 일부 건너뛰고도 동일한 결과를 얻을 수 있는 셈이다.

      이 말은 곧 Nginx나 fail2ban과 같은 어플리케이션이 전송받기 위해서 필요한 일부 과정을 목표로하는 공격이나 예기치 못한 문제들 또한 사전에 차단할 수 있다는 이야기이다. iptables 패키지는 커널 단위에서 작동하면서 모든 OSI 7계층에 관여할 수 있다. 우리가 지금 설정하는 것은 네트워크 계층(src, ipset)과 전송 계층(IP, PORT)에서 작동한다. 네트워크 계층에서 차단할 수 있다면 이후 4단계를 모두 실행할 필요가 없고 패킷은 바로 폐기된다. 이러한 이유로 iptables를 사용한 GeoIP 차단이 보안과 성능면에서 더 좋은 효과를 얻을 수 있다.

      ipset

      시중에 유통되는 GeoIP 데이터베이스는 일반적으로 큰 용량을 차지한다. v4대역은 물론 v6대역도 기술되어 있기 때문인데 이 문서에서는 v4에 대해서만 작성하겠다. 애초에 VM을 구매할 때 v6는 추가 요금이 붙어서 비활성화 했기 때문이기도 하니 v6에 대한 설정이 더 필요하다면 내용을 잘 수정하거나 다른 문서를 참조하는 것이 도움이 될 것이다.

      CLI
      sudo apt install ipset
      

      ipset은 이런 광범위한 대역 정보를 그루핑하여 효율적으로 관리할 수 있도록 도와주는 툴이다. 커널 모듈로 작동하여 iptables와 함께 구동할 수 있어서 많은 대역정보를 핸들링할 때 유용하게 사용할 수 있다. 단지 국내 IP만 허용하겠다고 한다면 앞서 소개한 ssh 포트 22를 http, https 포트인 80, 443으로 변경하면 해결되니 참고하길 바란다.

      IP 대역 집합 등록

      ipset_create.sh
      #!/bin/bash
      # 오류 발생 시 즉시 중단
      set -e
      
      # 다운로드 받은 csv 형식의 Geo IP 데이터베이스
      CSV_FILE_PATH="/path/to/dbip-country-lite.csv"
      
      if [ -z "$CSV_FILE_PATH" ]; then
        echo "오류: IPv4 CSV 파일을 찾을 수 없습니다. 경로와 파일명을 확인하세요."
        exit 1
      fi
      
      # 허용할 국가 코드 목록
      COUNTRIES=(KR US JP)
      
      # ipset 집합명
      IPSET_NAME_V4="allowed_countries_v4"
      
      # 그룹이 이미 있다면 제거한 후 등록
      # iptables에서 이미 사용하고 있다면 커널모듈에 등록되어서 삭제가 불가능함
      # 삭제하려면 반드시 iptables 규칙에서 그룹을 사용하고 있는 규칙을 제거한 후 실행해야함
      echo "새로운 ipset 집합 '$IPSET_NAME_V4'을(를) 생성합니다."
      ipset destroy "$IPSET_NAME_V4" || true
      
      # 환경에 맞게 그룹 최대 길이를 설정
      # maxelem 524288 로 기본값의 8배로 설정
      ipset create "$IPSET_NAME_V4" hash:net maxelem 524288
      
      echo "CSV 파일에서 허용된 국가들의 IPv4 대역을 ipset에 추가합니다..."
      
      # 추출된 IP 대역을 ipset에 바로 추가
      for COUNTRY in "${COUNTRIES[@]}"; do
          # IPv4 주소만 필터링하도록 awk에 조건 추가
          awk -F, '$3 == "'"$COUNTRY"'" && $1 !~ ":" {print $1 "-" $2}' "$CSV_FILE_PATH" | while read -r IPRANGE; do
              if [ -n "$IPRANGE" ]; then
                  ipset add "$IPSET_NAME_V4" "$IPRANGE" || echo "Error adding $IPRANGE to ipset."
              fi
          done
      done
      
      # ipset 집합 파일로 저장
      ipset save > /etc/ipset.rules
      
      echo "ipset 업데이트 완료. 규칙이 /etc/ipset.rules에 저장되었습니다."
      

      ipset을 실행하기 위해서 해당 쉘 파일은 root 권한으로 실행해야 한다. 위 코드는 예시로 '한미일' 세 국가만 지정했지만 더 많은 국가를 지정하려면 그룹 생성 옵션인 maxelem을 반드시 확인해야한다. 기본값은 65536으로 대역에 대한 정보가 너무 많으면 입력이 실패하는 경우가 있을 수 있기 때문이다. 예시에서 지정한 값은 8배에 해당하며 이 부분은 자신의 환경에 맞는 사이즈로 적절하게 조절하면 된다.

      CLI
      sudo iptables-save > /path/to/iptables.save
      sudo iptables -I INPUT -p tcp -m multiport --dports 80,443 -m set --match-set allowed_countries_v4 src -j ACCEPT
      sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j DROP
      
      # 복구 필요시
      # sudo iptables-restore < /path/to/iptables.save
      
      Docker Container

      서버 내부 동작코드가 도메인이나 IP를 사용하여 자신에게 Ajax 호출하는 경우 등

      만약 웹 서비스를 도커 컨테이너에서 작동시키고 있는 경우라면 설정이 하나 더 필요하다. 예를들어 서버 내부에서 자기 자신에게 구현된 API Ajax 호출을 도메인이나 IP 등 호스트에 설정된 네트워크 인터페이스를 거치게 된다면 마찬가지로 패킷이 드랍된다. 이는 도커 컨테이너가 도커 네트워크 인터페이스를 통해 네트워크 통신을 하게 되기 때문인데 컨테이너에 연결된 네트워크 인터페이스 명을 찾아 ACCEPT 설정을 해주면 된다. ifconfig 또는 도커에서 제공해주는 network 명령을 통하여 확인할 수 있다.

      iptables의 규칙은 등록된 순서대로 실행되기 때문에 잘 확인하면서 수행해야 한다. iptables -L INPUT --line-numbers 명령을 사용하면 현재 등록된 들어오는 패킷에 대한 규칙들을 순서대로 확인할 수도 있다. fail2ban 처럼 작업이 실행되기 전까지 패킷이 살아있는 것이 아니라 규칙이 적용되면 바로 작동하기 때문에 반드시 대체할 수 있는 방안을 마련해두어야 한다. 또한 규칙을 변경하기 전에 항상 iptables-save를 통해 백업본을 만들어 두고 잘 못 되었을 경우 iptables-restore를 통해 복구할 수 있다.

      네트워크 차단

      네트워크 차단

      Nginx에서 처리한 것과는 다르게 브라우저가 아예 응답을 받지 못하는 것을 확인할 수 있었다. 커널 단위에서 패킷을 조용히 버려버리기 때문에 좀 더 효율적으로 컴퓨터 자원을 사용할 수 있다. 계속되는 공격을 Nginx가 처리할 필요도 없으며 공개된 IP 대역으로는 더 원할한 서비스를 제공할 수 있다. 공개 지역에서도 공격이 있기는 하지만 어차피 같은 효과를 얻을 수 있기 때문에 이전 보다 더 나은 선택이라고 생각한다.

      설정 유지하기

      CLI
      sudo apt install iptables-persistent
      
      # 등록된 데몬들이 재부팅시에 자동으로 실행되도록
      # 'enable'을 다시 한 번 확인한다.
      sudo systemctl enable iptables.service
      sudo systemctl enable ip6tables.service
      
      netfilter-persistent

      netfilter-persistent

      커널에 설정된 값들은 재부팅 후에는 복원되지 않는데 이를 위해서 iptables-persistent를 적용해야한다. 이 패키지는 구형 패키지로 netfilter-persistent가 최신 패키지이다. 또한 구형 패키지명을 사용하더라도 실제로 설치되는 것은 netfilter-persistent임을 확인할 수 있다. 설치를 진행하면 v4, v6에 대한 룰 저장을 물어보는데 예를 선택하면 /etc/iptables/rules.v4, /etc/iptables/rules.v6가 자동으로 생성된다. rules.v4 파일을 확인해보면 설정했던 규칙들이 포함된 것을 확인할 수 있다.

      /etc/systemd/system/ipset.service
      [Unit]
      Description=Restore ipset rules
      Before=iptables-persistent.service
      After=network-online.target
      
      [Service]
      Type=oneshot
      ExecStart=/usr/sbin/ipset restore -file /etc/ipset.rules
      RemainAfterExit=yes
      
      [Install]
      WantedBy=multi-user.target
      

      iptables-persistent는 iptables와 관련된 작업만 복원하므로 ipset에 대해서는 복원되지 않는다. 따라서 재부팅시에 iptables가 작동하기 전에 ipset을 복원시켜줘야 한다. 이를 위한 시스템 데몬을 등록하고 마찬가지로 enable 해주면 끝이다. 만약 Nginx + fail2ban 조합으로 GeoIP를 적용한 경우라면 Nginx 설정에서 잊지 말고 geoip2 모듈을 제거해주자.

      초판: 2025. 10. 11. 21:20:27

      수정판: 2025. 10. 11. 22:43:30

      © 2025 이 문서는 "CC BY 4.0 국제규약" 라이선스로 배포 되었습니다. 모든 권리는 저자에게 있습니다.

      지역기반 IP로 방화벽 강화하기

      iptables
      xt_geoip
      웹 접근 제어
      ipset
      IP 대역 집합 등록
      설정 유지하기