背景
某システムで、ssh 接続した際に下記のようなエラーが稀に出るという現象が発生し出しました。
ssh_exchange_identification: Connection closed by remote host
このエラー自体はよく見かけるエラーで、IP アドレスが間違っているとか、フィルタリングされているとか、基本的に設定や接続方法に問題があるというイメージでした。
実際、少しググって見ましたが、やはり上記のようなケースの情報がほとんどで、これらのケースでは問題を解決しない限りは何度実行してもこのエラーが 100% 発生します。
従って、稀に発生する 今回の現象は明らかに異なる原因でした。
結論としては、MaxStartups
という sshd の設定値が関係しており、この設定値を引き上げることで問題が解決しました。
自分的な感覚では少々レアな現象だったと思うので、メモ的に残しておこうと思います。
MaxStartups とは
sshd_config の日本語訳では下記の様に記載されています。
MaxStartups (最大起動数)
認証されていない段階の接続をSSH デーモンが最大でどれだけ受けつけるかを指定します。
この値を超えた (認証されていない段階の) 接続は捨てられます。
この状態は (すでに接続したクライアントの) 認証が成功するか、そのLoginGraceTime(ログイン猶予時間) が切れるまで続きます。
…
つまり ssh 接続した瞬間から認証OKとなるまでの間の最大接続数です。
他のサイトを見ていると単なる同時接続数のように記載しているサイトが非常に多い印象ですが、単純な ssh の同時接続数ではありません。
あくまでも、ssh 接続した瞬間から認証OKとなるまで の非常に短い間の同時接続数です。
認証OK後の接続数は MaxStartups には無関係ですので注意が必要です。
設定値
CentOS7 などのデフォルト設定では 10:30:100
になっています。
これは、非認証な接続が 10 を超えるとそれ以降の接続を 30% の確率で拒絶し、さらに 100 に達した時点でそれ以降の接続を全て拒絶するという設定になります。
通常、非認証な接続が一気に 10 も来ることはほとんどの環境では無いと思いますので、いわゆる不正アクセス対策のための設定と考えて良いと思います。
上記の 拒絶 パターンの際に、下記のエラーが表示されます。
ssh_exchange_identification: Connection closed by remote host
今回は、この MaxStartups
の値を引き上げることで問題を解消することができました。
2019/09/09 追記
hiroaki_sengoku さんより、下記のように指摘をいただきました。(コメント欄参照)
MaxStartups の値を引き上げるのは、ssh サーバの負荷をそれだけ上げてしまうことになってしまうのではないでしょうか?
まったくもってその通りです。
本来は、背景 に記載しておくべきだったのですが、本文中で下記のように解消したと書いた環境はインターネットに接続していないプライベートな環境、つまり不正アクセスが皆無な環境下でした。
今回は、この
MaxStartups
の値を引き上げることで問題を解消することができました。
従って、本稿は不正アクセスが大量に来ることによって引き起こされる ssh_exchange_identification
の問題を MaxStartups
の値を引き上げることによって解消することを勧めるものではありません。
※場合によっては効果も見込めますが、良い方法ではない
本稿はあくまでも、ssh_exchange_identification
と MaxStartups
の関係に焦点を絞った内容となります。
不正アクセスに対する対応については、これも hiroaki_sengoku さんがコメント欄で書かれていますが、iptables などで sshd に接続する前に対処するのが王道でしょう。
もう少し詳しい話が下記に記載されていますが、この方法はスマートでとても良いと思います。
https://www.facebook.com/sengoku.hiroaki/posts/2380178762095810
おまけ
非常に短い時間での同時接続数なので、普通の手段で行なっていてはかなり面倒なことになります。
ただ単にエラー表示を再現させるだけなら、1 とか 2 あたりの小さな数値を設定すれば簡単に再現できますが、例えば 10 だったものを 20 にするとどの程度効果があるのか?といった検証では、最低でも 10 以上の同時接続を発生させる必要があります。
真面目にマルチプロセス/マルチスレッド的なプログラムを作成しても良いですが、私は Mac の Iterm2 の Broardcast Input を使ってこの検証を行いました。
この方法だと、単純に同時接続を発生させたい分だけターミナルを開いて一気に実行でき、結果も単純に個々のターミナルを確認すれば良いだけなのでとてもお手軽です。