ポートノッキングで少しだけ SSH 接続をセキュアにした
決められた順番でポートノッキングした時だけ、SSH 接続ができるようにしました。
ポートノッキングとは?
決められた順番でポートを叩くことで、あらかじめ設定してあるコマンドを実行する仕組みのことです。
今回は、ポートノッキングされた時にファイアウォール (iptables) に穴を空ける設定をしました。
逃げ道の確保
設定ミスにより、一切 SSH 接続ができなくなるといった事態を避けるために逃げ道を確保しておきます。
複数ポートで sshd を起動する、特定のネットワークからは(ポートノッキングを使わない) SSH 接続を許可するなど設定を行ってください。
knockd インストール
$ sudo apt install -y knockd
knockd 設定
設定(1)
$ sudo vi /etc/default/knockd START_KNOCKD=1 #knockd 自動起動 KNOCKD_OPTS="-i ens3" #ネットワークインタフェース設定、さくらの VPS なら ens3 のはず(?)
設定(2)
ポートノッキングに 10001/tcp, 10002/tcp, 10003/tcp を使いました。
$ sudo vi /etc/knockd.conf [options] logfile = /var/log/knockd.log #ログ出力設定 [openSSH] sequence = 10001:tcp,10002:tcp,10003:tcp seq_timeout = 5 command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = syn [closeSSH] sequence = 10003:tcp,10002:tcp,10001:tcp seq_timeout = 5 command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = syn
“sequence” で設定した順番でポートノッキングすると、"command" が実行されます。
[openSSH] で SSH 通信許可ルールを追加して、[closeSSH] で SSH 接続ルールを削除しています。
iptables 設定
iptables で許可していた SSH 接続は REJECT します。
$ sudo vi /etc/iptables/rules.v4 -A INPUT -p tcp --dport 22 -j REJECT $ sudo iptables-restore < /etc/iptables/rules.v4 $ sudo iptables -L ..... REJECT tcp -- anywhere anywhere tcp dpt:ssh reject-with icmp-port-unreachable .....
knockd 起動
$ sudo systemctl start knockd.service
確認
ローカル Mac から動作確認を行います。
knock インストール
ローカル Mac へ knock をインストールします。
$ brew install knock
動作確認
ポートノッキングする前の状態を確認します。
$ nmap %remote-server% PORT STATE SERVICE 22/tcp closed ssh
STATE が “closed” になっていて、SSH 接続ができない状態です。
knock コマンドで、ポートノッキングします。
$ knock -v -d 100 %remote-server% 10001:tcp 10002:tcp 10003:tcp
STATE が “open” になっていることを確認します。
$ nmap %remote-server% PORT STATE SERVICE 22/tcp open ssh
ポートノッキングして、ポートを閉じます。
$ knock -v -d 100 %remote-server% 10003:tcp 10002:tcp 10001:tcp $ nmap %remote-server% PORT STATE SERVICE 22/tcp closed ssh
ポートノッキング後に 10 秒間だけポートを空けるように設定
上記の設定だと明示的にポートノッキングしないと、SSH 切断後もポートが空いたままになってしまうので、ポートノッキング時に 10 秒間だけポートを空けるように設定します。
SSH 接続時のポートノッキングは、.ssh/config の ProxyCommand 設定で行えるので、組み合わせることで SSH 接続時のみポートが空くような動作になります。
knockd 設定
サーバ側の knockd 設定を以下のように変更します。
$ sudo vi /etc/knockd.conf [options] logfile = /var/log/knockd.log [opencloseSSH] sequence = 10001:tcp,10002:tcp,10003:tcp seq_timeout = 5 tcpflags = syn start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT cmd_timeout = 10 stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
ポートノッキングされると、"start_command" が実行され、10 秒 (cmd_timeout) 後に “stop_command” が実行されます。
ssh 設定
ローカル Mac の .ssh/config に “ProxyCommand” を設定することで、SSH 接続直前にポートノッキングを行います。
$ vi ~/.ssh/config Host %remote-server% Port 22 ProxyCommand bash -c '/usr/local/bin/knock -d 100 %h 10001:tcp 10002:tcp 10003:tcp; sleep 1; exec /usr/bin/nc %h %p'
このように設定することで、ポートノッキングを意識しないで SSH 接続できます。
knockd がシステムブート時に自動起動しない問題
/etc/default/knockd で自動起動設定したけど、Debian 9 では自動起動しませんでした。
どうやらバグのようです。
- #868015 - knockd does not start after system reboot - Debian Bug report logs
- [Install] セクションがないのが原因ですかね。。。
ということで対応
$ sudo vi /etc/systemd/system/knockd.service [Unit] Description=Port-Knock Daemon After=network.target Documentation=man:knockd(1) [Service] EnvironmentFile=-/etc/default/knockd ExecStart=/usr/sbin/knockd $KNOCKD_OPTS ExecReload=/bin/kill -HUP $MAINPID KillMode=mixed SuccessExitStatus=0 2 15 ProtectSystem=full CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN [Install] WantedBy=multi-user.target
設定を反映させます。
$ sudo systemctl daemon-reload $ sudo systemctl enable knockd.service
これでシステムブート時に自動起動するようになります。
まとめ
ポートノッキングで少しだけ SSH 接続をセキュアにしました。
ポートノッキングはセキュリティ的には気休めに過ぎないので、sshd 設定はこれまで通りセキュアにしましょう。