KITA Eng.

北海道でサーバー技術者として歩み出したひとが綴るblog。

SSHの接続元IP制限(国単位)をhosts.allow, hosts.denyで

まとめ

  • iptablesIPアドレスを大量に登録するのは、いろいろ大変なので、動的に制御できたら嬉しい
  • Debian/Ubuntuだと、/etc/hosts.allow/etc/hosts.denyaclexec というオプション1を使用してプログラムの終了コードでアクセス制御ができる
  • GeoIPデータベースを利用してIPアドレスの国判定(IPv4/v6対応)のスクリプト書いた
  • OpenSSH自体では、6.7tcpwrappers/libwrapが除かれた2が、Debian/Ubuntu版openssh-serverではtcpwrappers/libwrapのサポートが継続中3という実は微妙な状況

書いたスクリプト

#!/usr/bin/env python3
#
# install required packeges:
# sudo apt-get install python3-geoip geoip-database libgeoip1
#
# download script:
# sudo curl -sS -o /usr/local/bin/check_geoip.py https://gist.githubusercontent.com/kacchan822/f9240646cfd78a5290a2ec95d844b1a0/raw/a5d7047beb493dfdfc63c70b00b3b3c5595e1d64/check_geoip.py
# sudo chmod +x /usr/local/bin/check_geoip.py
#
# setting up hosts.allow and hosts.deny:
# sudo sh -c 'echo "sshd: ALL: aclexec /usr/local/bin/check_geoip.py %a" >> /etc/hosts.allow'
# sudo sh -c 'echo "sshd: ALL" >> /etc/hosts.deny'
#
import ipaddress
import sys
import GeoIP

# CHANGE if allow from other countory.
ALLOWED_COUNTORY = ['JP',]

# Check Value
try:
    ip = ipaddress.ip_address(sys.argv[1])
except ValueError:
    sys.exit(1)

# Local IP is permitted
if ip.is_private:
    sys.exit(0)

# Check IP address version
if ip.version == 4:
    gi = GeoIP.new(GeoIP.GEOIP_STANDARD)
    cc = gi.country_code_by_addr(str(ip))
else:
    gi = GeoIP.open('/usr/share/GeoIP/GeoIPv6.dat', GeoIP.GEOIP_STANDARD)
    cc = gi.country_code_by_addr_v6(str(ip))

# Chaeck Countory Code
if cc in ALLOWED_COUNTORY:
    sys.exit(0)
else:
    sys.exit(1)

https://gist.github.com/kacchan822/f9240646cfd78a5290a2ec95d844b1a0

ポイント - ALLOWED_COUNTORYに許可したい国コード(2文字)を入れれば、日本以外も許可できる - IPv4,IPv6の両方に対応 - ローカルIPは許可

つかいかた

上記スクリプトの上部にもあるけど...

# install required packeges
ubuntu@ubuntu1604:~$ sudo apt-get install python3-geoip geoip-database libgeoip1

# download script
ubuntu@ubuntu1604:~$ sudo curl -sS -o /usr/local/bin/check_geoip.py https://gist.githubusercontent.com/kacchan822/f9240646cfd78a5290a2ec95d844b1a0/raw/a5d7047beb493dfdfc63c70b00b3b3c5595e1d64/check_geoip.py
ubuntu@ubuntu1604:~$ sudo chmod +x /usr/local/bin/check_geoip.py

# setting up hosts.allow and hosts.deny
ubuntu@ubuntu1604:~$ sudo sh -c 'echo "sshd: ALL: aclexec /usr/local/bin/check_geoip.py %a" >> /etc/hosts.allow'
ubuntu@ubuntu1604:~$ sudo sh -c 'echo "sshd: ALL" >> /etc/hosts.deny'

おわりに

openssh-serverのTCPwrapper対応がいつからなくなるのかには気をつけないと...。


  1. http://manpages.ubuntu.com/manpages/artful/man5/hosts_options.5.html

  2. apt-get changelog openssh-server で確認できるchangelogに次の記載がある(Ubuntu 17.10で確認)。”openssh (1:6.7p1-1) unstable; urgency=medium … * Restore TCP wrappers support, removed upstream in 6.7. It is true that dropping this reduces preauth attack surface in sshd. On the other hand, this support seems to be quite widely used, and abruptly dropping it (from the perspective of users who don’t read openssh-unix-dev) could easily cause more serious problems in practice. It’s not entirely clear what the right long-term answer for Debian is, but it at least probably doesn’t involve dropping this feature shortly before a freeze. …”

  3. http://www.openssh.com/txt/release-6.7