[우분투, 민트] GeoIP와 Shell Script를 이용해서 ssh 접속 제한하기
GeoIP를 이용하면 외국에서 접속하는 아이피에 대해서 SSH 접속제한을 할수가 있다. 특히 요즘은 중국발 SSH에 대한 무작위 공격은 도가 지나치다 싶을 정도로 많기 때문에 이 작업은 반드시 해줘야 하는 작업이라고 생각된다. ssh뿐만 아니라 http 프로토콜 접속 등의 허용 및 제한이 가능해진다. GeoIP를 이용해서 SSH에 대한 접속 제한을 찾다보니 거의 대부분 iptable을 이용하여 제한하거나 PAM을 이용해서 막기의 방법을 쓰는데, 이 두가지 모두 초보자들이 설정하기엔 조금 어려워 보였다. 특히 iptable을 이용할때 룰을 잘못 이해해서 적용하거나 셋팅하면 오히려 본인이 접속을 못하는 경우가 생길수도 있고해서 자료를 찾다가 Shell Script를 이용하는 방법을 찾아냈고, 적용해보니 꽤 훌륭하다. 초보분들에게는 구현원리나 작동원리의 이해가 쉬운 이 방법을 권고해드리고 싶다.
geoiplookup 명령어와 GeoIP country (free) database를 설치합니다.
$ sudo apt-get install geoip-bin geoip-database
잘 설치 되었는지 다음과 같이 테스트를 해본다.
$ geoiplookup 8.8.8.8 GeoIP Country Edition: US, United States
위와같이 US, United States 가 출력된다면 제대로 설치된 것이다.
이 Shell Script는 접속자의 ip 주소를 GeoIP database와 비교하여 접속지역이 KR인지 유무에 따라 ALLOW와 DENY를 리턴해준다. 또한 이러한 메세지를 logger를 이용해서 log파일(/var/log/syslog)에 기록이 되도록 한다. 이 파일은 /usr/local/bin/sshfilter.sh로 만들면 된다.
#!/bin/bash # UPPERCASE space-separated country codes to ACCEPT ALLOW_COUNTRIES="KR" if [ $# -ne 1 ]; then echo "Usage: `basename $0` <ip>" 1>&2 exit 0 # return true in case of config issue fi COUNTRY=`/usr/bin/geoiplookup $1 | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1` [[ $COUNTRY = "IP Address not found" || $ALLOW_COUNTRIES =~ $COUNTRY ]] && RESPONSE="ALLOW" || RESPONSE="DENY" if [ $RESPONSE = "ALLOW" ] then exit 0 else logger "$RESPONSE sshd connection from $1 ($COUNTRY)" exit 1 fi
Script의 실행권한도 잊지말고 지정해주자.
$ sudo chown root.root /usr/local/bin/sshfilter.sh $ sudo chmod 775 /usr/local/bin/sshfilter.sh
/etc/hosts.deny 파일에 다음과 같은 라인을 추가합니다.
sshd: ALL
그리고 /etc/hosts.allow 파일에도 다음과 같은 라인을 추가합니다.
sshd: ALL: aclexec /usr/local/bin/sshfilter.sh %a
위에서 테스트 했던 US ip를 가지고 테스트 해보도록 한다.
/usr/local/bin/sshfilter.sh 8.8.8.8
KR(한국) 아이피만 접속을 허용하도록 했으므로 DENY 메세지가 나와야 정상이다.
다음 메세지는 /var/log/syslog 에서 볼 수 있다.
Jun 26 17:02:37 pi root: DENY sshd connection from 8.8.8.8 (US)
대부분 중국발 아이피에서 접속을 시도하고 있다는 것을 알 수 있다. 가끔 영국아이피도 많이 보이긴 한다.
3940 Apr 13 22:14:12 akalkid logger: DENY sshd connection from 43.255.190.177 (HK) 3941 Apr 13 22:14:34 akalkid logger: DENY sshd connection from 119.147.137.94 (CN) 3943 Apr 13 22:26:22 akalkid logger: DENY sshd connection from 222.186.56.138 (CN) 3944 Apr 13 22:32:40 akalkid logger: DENY sshd connection from 43.255.190.117 (HK) 3945 Apr 13 22:32:46 akalkid logger: DENY sshd connection from 43.255.190.187 (HK) 3946 Apr 13 22:33:57 akalkid logger: DENY sshd connection from 43.255.190.152 (HK) 3948 Apr 13 22:49:20 akalkid logger: DENY sshd connection from 43.255.190.131 (HK) 3949 Apr 13 22:49:23 akalkid logger: DENY sshd connection from 43.255.190.135 (HK) 3950 Apr 13 22:51:51 akalkid logger: DENY sshd connection from 117.40.239.54 (CN) 3951 Apr 13 22:54:54 akalkid logger: DENY sshd connection from 58.218.204.226 (CN) 3952 Apr 13 23:07:28 akalkid logger: DENY sshd connection from 43.255.190.175 (HK) 3953 Apr 13 23:07:49 akalkid logger: DENY sshd connection from 43.255.190.130 (HK) 3956 Apr 13 23:21:55 akalkid logger: DENY sshd connection from 222.186.21.209 (CN) 3957 Apr 13 23:25:51 akalkid logger: DENY sshd connection from 43.255.190.139 (HK) 3958 Apr 13 23:26:09 akalkid logger: DENY sshd connection from 222.77.190.33 (CN)
/etc/cron.monthly/updatingGeoIP 라는 파일을 만들어서 다음과 같은 내용을 작성해준다.
#!/bin/bash cd /tmp wget -q http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz if [ -f GeoIP.dat.gz ] then gzip -d GeoIP.dat.gz rm -f /usr/share/GeoIP/GeoIP.dat mv -f GeoIP.dat /usr/share/GeoIP/GeoIP.dat else echo "The GeoIP library could not be downloaded and updated" fi
저는 이외에도 Fail2ban 이라는 패키지도 설치해서 3회이상 접속시도를 할때에는 일정시간 이상 접속을 아예 허용치 않고 Ban을 시키고 있습니다. ssh의 기본 포트번호를 바꾼다거나 하는 방법도 괜찮은 방법이라고 생각됩니다. 보안은 아무리 강조해도 지나치지 않기 때문에 서버를 운영하시는 분이라면 특히, 중국발 SSH에 대한 무차별 공격에 대해 어느정도 대비를 해놓는 것이 좋다는 생각입니다. 일단 다음 서버를 구매하고 셋팅할때는 저도 SSH의 기본포트를 바꿔서 시작할 예정입니다 🙂
컴퓨터를 재시작해도 해외 ip 차단해주나요?
아니면 따로 또 설정을 해줘야 하나요?
SSH 접속에 대해 접속요청이 들어오면 hosts.deny, hosts.allow 를 참조해서 접속을 허용하기 때문에 재시작해도 당연히 해당 IP를 차단해 줍니다. 단, 이 쉘 스크립트 방식으로는 ip 변조를 통해서 접속을 요청하는 IP에 대해서는 접속을 강제할 방법이 없습니다.
안녕하세요. 덕분에 잘 사용중인 유저입니다. 한가지질문이 있습니다.
설명하단부에 업데이트 관련 cron작업에서 해당 연결링크가 file not found가 나오네요. 아마도 링크가 변경된듯한데.. 혹시 변경된 주소를 알수가 있을까요?
답변 주시면 너무 감사용… 수고하세요
음 GeoIP 관련 라이센스 정책들이 바뀌면서 다운로드 형태가 바뀐것 같네요. 최근에 바빠서 늦게 체크했습니다. 조만간 답변해드릴수 있도록 할께요.
오늘에야 겨우 시간이나서 살펴봤는데…라이센스가 바뀌어서 제공되는 부분이 바뀐게 맞네요.
아직 전부다 살펴보진 못했지만 geoipupdate를 설치하고
/usr/local/etc/GeoIP.conf를 만들어서 프리계정으로 접속할수 있는 환경을 만들어주고…
geoipupdate를 실행하면 /var/lib/GeoIP 에 GeoLite2-Country.mmdb 가 생성되는 것을 확인했습니다.
새로 받은 mmdb는 geoiplookup으로 확인이 불가능하고…
mmdb-bin 을 설치후에 mmdblookup –file DB파일 –ip 아이피주소 를 지정해야 나오는데 json 스타일의 값을 반환하네요. 예전처럼 간단한 문장으로 반환되지 않습니다. T-T;