OpenSSH
OpenSSH (OpenBSD Secure Shell) は、Secure Shell (SSH) プロトコルを用いてコンピュータネットワーク経由の暗号化された通信セッションを提供するコンピュータプログラム群です。OpenSSH は、SSH Communications Security によって提供されているプロプライエタリな Secure Shell ソフトウェアスイートのオープンソースな代替として作成されました。OpenSSH は OpenBSD プロジェクトの一部として開発されており、Theo de Raadt によって率いられています。
OpenSSH は、似た名前の OpenSSL と混同されることがあります。しかし、これらのプロジェクトの目的は異なり、開発チームも異なります。この似たような名前は、ただ単にゴールが似ているからです。
目次
- 1 インストール
- 2 クライアントの使用
- 3 サーバの使用
- 4 ヒントとテクニック
- 4.1 暗号化 SOCKS トンネル
- 4.2 X11 フォワーディング
- 4.3 他のポートのフォワーディング
- 4.4 踏み台ホスト
- 4.5 リレーを介したリバース SSH
- 4.6 マルチプレクス
- 4.7 SSH の高速化
- 4.8 SSHFS でリモートファイルシステムをマウントする
- 4.9 セッションを生かし続ける
- 4.10 systemd で SSH トンネルを自動的に再起動
- 4.11 Autossh - SSH セッションとトンネルの自動再起動
- 4.12 SSH デーモンが失敗した場合の代替サービス
- 4.13 ホストに基づいてターミナル背景色を設定する
- 4.14 ネットワーク固有の設定
- 4.15 プライベートネットワークのホスト鍵検証
- 4.16 ログイン時にコマンドを実行
- 4.17 エージェントフォワーディング
- 4.18 新しい鍵の生成
- 4.19 sshd を非特権ユーザとして実行
- 5 トラブルシューティング
- 5.1 チェックリスト
- 5.2 接続が拒否されるまたはタイムアウトする
- 5.3 "[your shell]: No such file or directory" / ssh_exchange_identification 問題
- 5.4 "Terminal unknown" や "Error opening terminal" エラーメッセージ
- 5.5 Connection closed by x.x.x.x [preauth]
- 5.6 サブシステム要求の失敗
- 5.7 OpenSSH 7.0 によって id_dsa が拒否される
- 5.8 OpenSSH 7.0 で No matching key exchange method found
- 5.9 SSH から切断したときに tmux/screen セッションが終了する
- 5.10 SSH セッションが応答しなくなる
- 5.11 Broken pipe
- 5.12 再起動後デーモンの起動が遅い
- 5.13 応答のない SSH 接続を終了する
- 5.14 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
- 5.15 適切な terminfo エントリがないリモートに接続する場合
- 6 参照
インストール
クライアントの使用
サーバに接続するには、以下を実行してください:
$ ssh -p ポート ユーザ@サーバアドレス
サーバが公開鍵認証のみを許可している場合、SSH 鍵 の記事に従ってください。
設定
クライアントは、共通のオプションとホストを保存するように設定することができます。全プションは、グローバルに、あるいは特定のホストに制限して宣言することができます。例えば:
~/.ssh/config
# グローバルなオプション User user # 特定のホストのオプション Host myserver Hostname server-address Port port
このような設定を用いると、以下の2つのコマンドは等価になります:
$ ssh -p port user@server-address $ ssh myserver
詳細は ssh_config(5) を見てください。
一部のオプションには等価なコマンドラインスイッチがありません。しかし、コマンドラインで -o
フラグを用いることで設定オプションを指定できます。例えば: -oKexAlgorithms=+diffie-hellman-group1-sha1
。
サーバの使用
sshd
は OpenSSH サーバのデーモンです。/etc/ssh/sshd_config
で設定され、sshd.service
によって管理されます。設定を変更する際は、サーバを再起動する前に sshd
をテストモードで使用し、サーバが正しく起動できることを確認してください。設定が有効である場合は、何も出力されません。
# sshd -t
設定
一部のユーザにのみアクセスを許可するには、以下の行を追加してください:
AllowUsers user1 user2
一部のグループにのみアクセスを許可するには:
AllowGroups group1 group2
素晴らしいウェルカムメッセージを (/etc/issue
ファイルなどから) 追加するには、Banner
オプションを設定してください:
Banner /etc/issue
公開ホスト鍵と秘密ホスト鍵は、sshdgenkeys サービスによって /etc/ssh
内に自動で生成されます。sshd_config
内の HostKeyAlgorithms
オプションによって一部の署名アルゴリズムしか許可されていない場合でも、鍵が存在しない場合、再生成されます。dsa、rsa、ecdsa、そして ed25519 アルゴリズムに基づく4組の鍵のペアが提供されます。sshd に特定の鍵を使用させるには、以下のオプションを指定してください:
HostKey /etc/ssh/ssh_host_rsa_key
サーバを WAN に公開するつもりであるならば、以下のようにデフォルトのポートを 22 から別のランダムで大きい値に変更することが推奨されます:
Port 39901
デーモンの管理
sshd.service
を起動/有効化してください。これは、SSH デーモンを永続的にアクティブ状態に保ち、各着信接続に対してフォークします。[1]
保護
SSH によるリモートログインを許可することは管理業務においては良いことですが、サーバーのセキュリティに脅威を及ぼすことにもなりえます。総当り攻撃の標的になりやすいので、SSH のアクセスは制限して、第三者がサーバーにアクセスできないようにする必要があります。
ssh-audit は、サーバとクライアントの設定の自動化された解析を提供します。このトピックに関して、いくつか他のガイドやツールが利用できます。例えば:
公開鍵認証を強制する
デフォルトでは、クライアントが公開鍵で認証できない場合、SSH サーバはパスワード認証にフォールバックします。なので、悪意のあるユーザがパスワードのブルートフォースによるアクセスを試みることができてしまいます。このような攻撃から保護する最も効果的な方法の1つが、パスワードログインを完全に無効化し、SSH 鍵の使用を強制することです。これは、デーモンの設定ファイルで以下のオプションを設定することで可能です:
/etc/ssh/sshd_config
PasswordAuthentication no AuthenticationMethods publickey
二要素認証と公開鍵
SSH は、認証に複数の方法を要求するようにセットアップすることができます。AuthenticationMethods
オプションを使うことで、どの認証方法を要求するかを指定することができます。これにより、公開鍵と2要素認証を使用することができます。
認証プロバイダ
Google Authenticator をセットアップする方法については Google Authenticator を参照してください。
Duo の場合、pam_duo.so
モジュールを提供する duo_unixAUR をインストールしてください。必須の Duo 認証情報 (Integration Key、Secret Key、API Hostname) をセットアップする方法に関するインストラクションは Duo Unix ドキュメント を参照してください。
PAM セットアップ
PAM を OpenSSH で使用するには、以下のファイルを編集してください:
/etc/ssh/sshd_config
KbdInteractiveAuthentication yes AuthenticationMethods publickey keyboard-interactive:pam
これで、PAM セットアップによって要求されるユーザ認証か公開鍵のどちらか一方でログインできます。
一方、PAM セットアップによって要求されるユーザ認証と公開鍵の両方でユーザを認証したい場合、AuthenticationMethods の分割にスペースではなくコンマを使用してください:
/etc/ssh/sshd_config
KbdInteractiveAuthentication yes AuthenticationMethods publickey,keyboard-interactive:pam
要求される公開鍵と pam 認証の両方を用いて、パスワード要件を無効化すると良いでしょう:
/etc/pam.d/sshd
auth required pam_securetty.so #disable remote root #Require google authenticator auth required pam_google_authenticator.so #But not password #auth include system-remote-login account include system-remote-login password include system-remote-login session include system-remote-login
ブルートフォース攻撃に対する保護
ブルートフォース (総当り) は単純なコンセプトです: 大量のランダムなユーザ名とパスワードの組み合わせを用いて、あるウェブページやサーバの SSH のようなログインプロンプトに絶え間なくログインを試みるのです。
iptables については ufw#ufw によるレート制限 や シンプルなステートフルファイアウォール#ブルートフォース攻撃 を参照してください。
あるいは、fail2ban や sshguard などの自動スクリプトを使うことで攻撃者をブロックすることでブルートフォース攻撃から身を守ることができます。
- 信頼された場所からの着信 SSH 接続のみを許可する。
- fail2ban か sshguard を使用して、パスワード認証に失敗しすぎた IP アドレスを自動的にブロックする。
- pam_shield を使用して、特定の時間内に多くのログイン試行を行った IP アドレスをブロックする。fail2ban や sshguard とは対照的に、このプログラムはアカウントへのログイン成功や失敗を考慮しません。
root ログインの制限
一般的に、root ユーザが制限無しで SSH を介してログインできることはバッドプラクティスだと考えられています。セキュリティを向上させるために SSH の root アクセスを制限する方法は2つあります。
拒否
Sudo を使うことで、root アカウントの認証を行うことなく、必要に応じて root 権限を選択的に付与することができます。このため SSH による root ログインを拒否して、攻撃者にパスワードに加えて (root でない) ユーザー名も推測させる必要を生じさせることで、ブルートフォース攻撃を困難にすることが可能です。
デーモンの設定ファイルで "Authentication" セクションを編集することで SSH からの root ユーザのログインを拒否するように設定できます。PermitRootLogin
を no
に設定してください:
/etc/ssh/sshd_config
PermitRootLogin no
次に、SSH デーモンを再起動してください。
これで、SSH を使って root でログインすることはできなくなります。ただし、通常ユーザーでログインしてから su や sudo を使ってシステム管理を行うことは依然として可能です。
制限
自動的な作業の中にも、リモートによるフルシステムバックアップなど、root 権限を必要とするものがあります。セキュアな方法で root を許可したい場合、SSH による root ログインを無効化する代わりに、特定のコマンドだけ root ログインを許可することができます。~root/.ssh/authorized_keys
を編集して、以下のように特定のキーの前にコマンドを記述します:
command="/usr/lib/rsync/rrsync -ro /" ssh-rsa …
上記の設定で、特定の鍵を使ってログインした場合はクォートで囲ったコマンドを実行できるようになります。
ログイン時に root ユーザーの名前を出すことで攻撃する対象が増えてしまうことに対しては sshd_config
に以下を追加することで埋め合わせができます:
PermitRootLogin forced-commands-only
上記の設定は root が SSH で実行できるコマンドを制限するだけでなく、パスワードの使用も無効化して、root アカウントでは強制的に公開鍵認証を使うようになります。
root で使えるコマンドは制限しないで公開鍵認証の強制だけをするという手もあり、それでもブルートフォース攻撃はほぼ不可能です。その場合、以下を設定:
PermitRootLogin prohibit-password
authorized_keys ファイルのロック
何らかの理由により、疑いのあるユーザに既存の鍵を追加/変更させるべきではないと思われる場合、そのファイルを操作できないようにできます。
サーバでは、ユーザの authorized_keys
ファイルを読み取り専用にして、他の全パーミッションを禁止してください:
$ chmod 400 ~/.ssh/authorized_keys
ユーザがパーミッションを元に戻せないようにするには、authorized_keys
ファイルに変更不可のビットを設定してください。ユーザが ~/.ssh
ディレクトリをリネームして新しい ~/.ssh
ディレクトリと authorized_keys
ファイルを作成できないようにするには、~/.ssh
ディレクトリにも変更不可のビットを設定してください。鍵を追加/削除するには、authorized_keys
から変更不可のビットを削除して一時的に書き込み可能にする必要があります。
ヒントとテクニック
暗号化 SOCKS トンネル
暗号化トンネルは、安全でない様々なワイヤレス接続を使用するノートパソコンユーザにとって非常に有用です。必要なのは SSH サーバーが安全な場所 (家や仕事場など) で動作していることだけです。DynDNS などのダイナミック DNS サービスを利用すれば IP アドレスを覚える必要もありません。
手順 1: 接続の開始
以下のコマンドを実行するだけで接続を開始できます:
$ ssh -TND 4711 user@host
user
はユーザー名に、host
は SSH サーバーが動作しているホストに置き換えてください。パスワードを入力すると接続が行われます。N
フラグはインタラクティブプロンプトを無効化し、D
フラグは listen するローカルポートを指定します (ポート番号は何でもかまいません)。T
フラグは疑似 tty アロケーションを無効化します。
verbose (-v
) フラグを追加することで、接続が成功していることを出力から確認することができます。
手順 2 (やり方 A): ブラウザ (或いはその他のプログラム) の設定
新しく作成した SOCKS トンネルを使用するようにウェブブラウザ (や他のプログラム) を設定しないと上記の作業は無意味です。SSH は現在 SOCKS v4 と SOCKS v5 の両方をサポートしているため、使用するのはどちらでも構いません。
- Firefox の場合: 設定 > 一般 を開き、ページ下部に移動し、ネットワーク設定の右にある 接続設定... をクリックしてください。次に、セミウィンドウ内で、手動でプロキシを設定する オプションにチェックを入れ、SOCKS ホスト テキストフィールドに
localhost
と入力し、ポート テキストフィールドには SSH のポート番号 (上記の例では4711
) を入力してください。
- Firefox は自動的に SOCKS トンネルを介して DNS リクエストを行いません。この潜在的なプライバシーの問題は、インターネット接続の設定画面を更にスクロールし、SOCKS v5 を使用するときは DNS もプロキシーを使用する にチェックを入れることで、軽減することができます。明らかに、この方法は SOCKS v4 ではなく SOCKS v5 を選んだ場合にしか適用できません。
- これらの設定をアクティブ化するために Firefox を再起動してください。
- Chromium の場合: SOCKS の設定を環境変数かコマンドラインオプションとして設定できます。以下の関数のうち1つを
.bashrc
に追加することをおすすめします:
function secure_chromium { port=4711 export SOCKS_SERVER=localhost:$port export SOCKS_VERSION=5 chromium & exit }
あるいは
function secure_chromium { port=4711 chromium --proxy-server="socks://localhost:$port" & exit }
そして、ターミナルを開いて、以下を実行してください:
$ secure_chromium
セキュアトンネルを楽しみましょう!
手順 2 (やり方 B): ローカルの TUN インターフェイスをセットアップする
このやり方は若干複雑ですが、SOCKS プロキシを使用するためにアプリケーションを1つずつ手動で設定する必要が無くなります。この方法には、ローカル TUN インターフェイスのセットアップと、そのインターフェイスを介したトラフィックのルーティングが含まれます。
VPN over SSH#badvpn とトンネルインターフェイスをセットアップする を見てください。
X11 フォワーディング
X11 フォワーディングは、リモートシステムで X11 プログラムを動作させて、グラフィカルインターフェイスをローカルのクライアントマシンで表示させるメカニズムです。X11 フォワーディングではリモートホストに X11 システムを完全にインストールさせる必要はなく、xauth をインストールするだけで十分です。xauth は、X11 セッションの認証を行うために必要なサーバーとクライアントによって使用される Xauthority
の設定を管理するユーティリティです (ソース)。
セットアップ
リモート側
- xorg-xauth パッケージをインストールしてください
/etc/ssh/sshd_config
内で:X11Forwarding
を yes に設定してくださいAllowTcpForwarding
とX11UseLocalhost
オプションが yes に設定されおり、X11DisplayOffset
が 10 に設定されていることを確認してください (これらの設定は、何も変更していなければ、デフォルト値です。sshd_config(5) を参照)。
- そして、sshd デーモンを再起動してください。
クライアント側
- xorg-xauth パッケージをインストールしてください。
- コマンドラインで日和見的な接続を行うための
-X
スイッチを指定するか、或いはクライアントの設定でForwardX11
を yes に設定して、ForwardX11
オプションを有効化してください。
使用方法
通常通りリモートマシンにログオンしてください。クライアントの設定ファイルで ForwardX11 が有効化されていない場合は -X
スイッチを指定してください:
$ ssh -X user@host
グラフィカルアプリケーションを実行しようとしてエラーが発生する場合は、代わりに ForwardX11Trusted を試してください:
$ ssh -Y user@host
Given the output X11 forwarding request failed
, redo the setup for your remote machine. Once the X11 forwarding request succeeds, you can start any X program on the remote server, and it will be forwarded to your local session:
X11 forwarding request failed
と出力される場合、リモートマシンでセットアップをやり直してください。X11 フォワーディングのリクエストが成功したら、リモートサーバ上の任意の X プログラムを実行でき、プログラムがローカルセッションにフォワーディングされます:
$ xclock
Can't open display
という内容が含まれるエラーが出力される場合は、DISPLAY
が適切に設定されていないことを意味します。
一部のアプリケーションは、実行中のインスタンスのチェックをローカルのマシンで行うため、注意してください。Firefox がその例です: すでに実行中の Firefox を閉じるか、以下の起動パラメータを使用してリモートインスタンスをローカルマシン上で起動してください:
$ firefox --no-remote
接続時に "X11 forwarding request failed on channel 0" と表示される場合 (サーバーの /var/log/errors.log
に "Failed to allocate internet-domain X11 display socket" と出力される場合)、xorg-xauth パッケージがインストールされていることを確認してください。上手く機能しない場合、以下の設定を試してみてください:
- サーバの
sshd_config
でAddressFamily any
オプションを有効にする。 - 或いは、サーバの
sshd_config
でAddressFamily
オプションを inet に設定する。
IPv4 で Ubuntu クライアントを使っている場合は inet に設定することで問題が解決する場合があります。
SSH サーバーの他のユーザーで X アプリケーションを実行するには SSH でログインしているユーザーの xauth list
の認証行を xauth add
する必要があります。
他のポートのフォワーディング
SSH の X11 の組み込みサポートに加えて、SSH には任意の TCP 接続をセキュアにトンネル化することもできます。ローカルフォワーディングとリモートフォワーディングの両方が使えます。
ローカルフォワーディングはローカルマシンのポートを開き、ローカルマシンに対する接続はリモートホストにフォワーディングされ、リモートホストから指定された宛先に転送されます。転送先をリモートホストと同じにすることで、同一マシンに対してセキュアシェルやセキュアな VNC 接続を提供します。ローカルフォワーディングは -L
スイッチで利用することができ <トンネルポート>:<宛先アドレス>:<宛先ポート>
という形式で転送先を指定します。
ゆえに:
$ ssh -L 1000:mail.google.com:25 192.168.0.100
上記のコマンドは SSH で 192.168.0.100
にログインしてシェルを開き、ローカルマシンの TCP ポート 1000 から mail.google.com のポート 25 へのトンネルが作成されます。接続が確立すると localhost:1000
への通信は Gmail の SMTP ポートに接続されます。Google から見ると、192.168.0.100
から接続が来ているように見えます (必ずしも接続と一緒にデータが運ばれるとは限りません)。データはローカルマシンと 192.168.0.100
との間でセキュアに運ばれますが、192.168.0.100
と Google との間はセキュアではありません (他の方法を取らない限り)。
似たように:
$ ssh -L 2000:192.168.0.100:6001 192.168.0.100
このコマンドは、localhost:2000
に接続することができ、リモートホストのポート 6001 へ透過的に送信されます。前者の例は、vncserver ユーティリティ (tightvnc パッケージの一部) を使用して VNC 接続を行う際に便利です。便利とはいえ、セキュリティの問題があります。
リモートフォワーディングは SSH トンネルとローカルマシンを通してリモートホストから任意のホストに接続できるようにします。ローカルフォワーディングとは逆の機能であり、ファイアウォールによってリモートホストの接続が限られている場合などに有用です。リモートフォワーディングは -R
スイッチで使うことができ <トンネルポート>:<宛先アドレス>:<宛先ポート>
という形式で転送先を指定します。
ゆえに:
$ ssh -R 3000:irc.libera.chat:6667 192.168.0.200
上記のコマンドは 192.168.0.200
にシェルを立ち上げて、192.168.0.200
からローカルホストの 3000 番ポートへの接続をトンネルを通して送信し、それから irc.freenode.net のポート 6667 に転送します。ポート 6667 がブロックされている場合でもリモートホストから IRC プログラムを利用することができるようになります。
ローカルフォワーディングとリモートフォワーディングはどちらもセキュアなゲートウェイとして使用することができます。<tunnel address>:<tunnel port>:<destination address>:<destination port>
のようにバインドアドレスをつかうことで、SSH や SSH デーモンを動かしていなくても他のコンピュータが SSH トンネルを利用することが可能です。<tunnel address>
はトンネルの入り口となるマシンのアドレスです: localhost
, *
(あるいは空)。特定のアドレス経由の接続、ループバックインターフェイス経由の接続、全てのインターフェイス経由の接続を許可します。デフォルトでは、フォワーディングはトンネルの入り口のマシンからの接続だけに制限されており <tunnel address>
は localhost
に設定されています。ローカルフォワーディングは特に設定が必要ありませんが、リモートフォワーディングはリモートサーバーの SSH デーモンの設定によって制限を受けます。詳しくは sshd_config(5)
の GatewayPorts
オプションを見てください。
踏み台ホスト
場合によっては、接続先の SSH デーモンに直接接続できず、踏み台サーバー (ジャンプサーバー) を使わざるを得ないことがあります。2つ以上の SSH トンネルを接続して、それぞれのサーバーに対してローカルの鍵で認証します。SSH エージェントの転送 (-A
) と疑似端末の割当 (-t
) を使って以下のようにローカルの鍵を転送します:
$ ssh -A -t -l user1 bastion1 \ ssh -A -t -l user2 intermediate2 \ ssh -A -t -l user3 target
以下のように -J
フラグを使うとより簡単です:
$ ssh -J user1@bastion1,user2@intermediate2 user3@target
-J
ディレクティブで指定するホストはカンマで区切り、指定された順番で接続されます。user...@
の部分は必須ではありません。-J
で指定したホストは ssh の設定ファイルを使うため、必要であればホスト毎にオプションを設定することが可能です。
設定ファイルにも、-J
フラグと等価なものとして ProxyJump
オプションがあります。詳細は ssh_config(5) を見てください。
リレーを介したリバース SSH
The idea is that the client connects to the server via another relay while the server is connected to the same relay using a reverse SSH tunnel. This is useful when the server is behind a NAT, and the relay is a publicly accessible SSH server used as a proxy to which the user has access. Therefore, the prerequisite is that the client's keys are authorized against both the relay and the server, and the server needs to be authorized against the relay as well for the reverse SSH connection.
The following configuration example assumes that user1 is the user account used on client, user2 on relay and user3 on server. First, the server needs to establish the reverse tunnel with:
ssh -R 2222:localhost:22 -N user2@relay
Which can also be automated with a startup script, systemd service or autossh.
At the client side, the connection is established with:
ssh -t user2@relay ssh user3@localhost -p 2222
The remote command to establish the connection to reverse tunnel can also be defined in relay's ~/.ssh/authorized_keys
by including the command
field as follows:
command="ssh user3@localhost -p 2222" ssh-rsa KEY2 user1@client
In this case the connection is established with:
ssh user2@relay
Note that SCP's autocomplete function in client's terminal is not working and even the SCP transfers themselves are not working under some configurations.
マルチプレクス
SSH デーモンは通常はポート 22 番をリッスンします。しかし、公共のインターネット・ホットスポットでは通常の HTTP/HTTPS のポート(80 と 443)以外のトラフィックをブロックしていることが一般的です。そのため SSH 接続がブロックされてしまいます。すぐできる解決策として、sshd
に許可されているポートをリッスンさせるという方法があります:
/etc/ssh/sshd_config
Port 22 Port 443
しかしポート 443 番は HTTPS コンテンツを提供する Web サーバによってすでに使われていることが多いです。その場合は sslh のようなマルチプレクサを使います。これは複数のポートをリッスンし、そこに来るパケットを複数のサービスに賢く振り分けることができます。
SSH の高速化
接続をグローバル及び特定のホストに対して高速化させることのできるクライアント設定がいくつかあります。これらのオプションに関する完全な説明は ssh_config(5) を参照してください。
- より高速な暗号を使う: AESNI 命令セットを持つ最近の CPU では、
aes128-gcm@openssh.com
やaes256-gcm@openssh.com
を使うことで openssh のデフォルトの優先暗号 (通常chacha20-poly1305@openssh.com
) よりも劇的に優れたパフォーマンスを得られるはずです。暗号は-c
フラグで選択できます。永続的に設定するには、~/.ssh/config
内にCiphers
オプションを追加し、暗号を優先順に並べて設定してください (例:Ciphers aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
)。
- 圧縮を有効化あるいは無効化する: 圧縮は低速な接続において速度を向上させることができます。
Compression yes
オプションか-C
フラグで有効化できます。しかし、使用される圧縮アルゴリズムは比較的低速な gzip(1) であり、高速なネットワークにおいてはボトルネックになってしまいます。接続を高速化させるために、ローカルネットワークや高速なネットワークにおいてはCompression no
を使うべきでしょう。
- 接続共有: 以下のオプションを使用することで、同一ホストに対するセッションをすべて単一の接続に共有させることができます:
ControlMaster auto ControlPersist yes ControlPath ~/.ssh/sockets/socket-%r@%h:%p
~/.ssh/sockets
の部分は、他のユーザによって書き込むことができないのであれば、どのディレクトリでも構いません。
ControlPersist
は、初回のクライアント接続が閉じられてから、新しいクライアントのためにマスターがどれくらいバックグラウンドで待機すべきかを指定します。利用可能な値は:no
: 最後のクライアントが切断されたらすぐに接続を閉じます。- 秒単位の時間
yes
: 永遠に待ちます。接続は自動的に閉じられなくなります。
AddressFamily inet
オプションか-4
フラグを使用して IPv6 ルックアップをバイパスすることで、ログインに要する時間を短くすることができます。
- 最後に、SSH を SFTP や SCP のために使用するつもりであれば、High Performance SSH/SCP は、SSH バッファサイズを動的に大きくすることで、スループットを劇的に増やすことができます。この改善のパッチが施されたバージョンの OpenSSH である openssh-hpn-gitAUR パッケージをインストールしてください。
SSHFS でリモートファイルシステムをマウントする
sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は SSHFS の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に shfs よりも sshfs を使用することを推奨します。sshfs は shfs の新しいバージョンであり、元の shfs は2004年から更新されていません。
セッションを生かし続ける
By default, the SSH session automatically logs out if it has been idle for a certain time. To keep the session up, the client can send a keep-alive signal to the server if no data has been received for some time, or symmetrically the server can send messages at regular intervals if it has not heard from the client.
- On the server side,
ClientAliveInterval
sets the timeout in seconds after which if no data has been received from the client, sshd will send a request for response. The default is 0, no message is sent. For example to request a response every 60 seconds from the client, set theClientAliveInterval 60
option in your server configuration. See also theClientAliveCountMax
andTCPKeepAlive
options. - On the client side,
ServerAliveInterval
controls the interval between the requests for response sent from the client to the server. For example to request a response every 120 seconds from the server, add theServerAliveInterval 120
option to your client configuration. See also theServerAliveCountMax
andTCPKeepAlive
options.
systemd で SSH トンネルを自動的に再起動
systemd を使ってブート時/ログイン時に SSH 接続を自動的に開始して、さらに接続が失敗した時に再起動させることができます。SSH トンネルの管理に役立つツールとなります。
以下のサービスでは、ssh の設定に保存された接続設定を使って、ログイン時に SSH トンネルを開始します。接続が何らかの理由で閉じられた場合、10秒待機してから再起動します:
~/.config/systemd/user/tunnel.service
[Unit] Description=SSH tunnel to myserver [Service] Type=simple Restart=always RestartSec=10 ExecStart=/usr/bin/ssh -F %h/.ssh/config -N myserver
上記の systemd/ユーザーサービスを有効化して起動してください。トンネルがタイムアウトするのを防ぐ方法は #セッションを生かし続ける を見て下さい。起動時にトンネルを開始したい場合、ユニットをシステムサービスとして書きなおして下さい。
Autossh - SSH セッションとトンネルの自動再起動
ネットワークの状態が悪かったりしてクライアントが切断してしまい、セッションやトンネルの接続を維持できない場合、autossh を使って自動的にセッションとトンネルを再起動できます。
使用例:
$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" username@example.com
SSHFS と組み合わせる:
$ sshfs -o reconnect,compression=yes,transform_symlinks,ServerAliveInterval=45,ServerAliveCountMax=2,ssh_command='autossh -M 0' username@example.com: /mnt/example
プロキシ設定で設定した SOCKS プロキシを使って接続:
$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" -NCD 8080 username@example.com
-f
オプションで autossh をバックグラウンドプロセスとして実行することができます。ただし対話式でパスフレーズを入力することができなくなります。
セッション中に exit
と入力したり autossh プロセスに SIGTERM、SIGINT、SIGKILL シグナルが送られるとセッションは終了します。
systemd を使ってブート時に自動的に autossh を起動する
autossh を自動的に起動したい場合、以下の systemd ユニットファイルを作成します:
/etc/systemd/system/autossh.service
[Unit] Description=AutoSSH service for port 2222 After=network.target [Service] Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -M 0 -NL 2222:localhost:2222 -o TCPKeepAlive=yes foo@bar.com [Install] WantedBy=multi-user.target
AUTOSSH_GATETIME=0
は接続が成功して ssh が立ち上がったと autossh が認識する秒数です。0に設定すると autossh は ssh の最初の起動失敗を無視します。起動時に autossh を実行する場合は設定するべきです。他の環境変数は man ページを見てください。必要であればもっと複雑に設定することもできますが、AUTOSSH_GATETIME=0
を含む -f
は systemd では機能しません。
以下のように ControlMaster を無効化する必要もあるかもしれません:
ExecStart=/usr/bin/autossh -M 0 -o ControlMaster=no -NL 2222:localhost:2222 -o TCPKeepAlive=yes foo@bar.com
SSH デーモンが失敗した場合の代替サービス
For remote or headless servers which rely exclusively on SSH, a failure to start the SSH daemon (e.g., after a system upgrade) may prevent administration access. systemd offers a simple solution via OnFailure
option.
Let us suppose the server runs sshd
and telnet is the fail-safe alternative of choice. Create a file as follows. Do not enable telnet.socket
!
/etc/systemd/system/sshd.service.d/override.conf
[Unit] OnFailure=telnet.socket
That's it. Telnet is not available when sshd
is running. Should sshd
fail to start, a telnet session can be opened for recovery.
ホストに基づいてターミナル背景色を設定する
To better distinguish when you are on different hosts, you can set a different background color based on the kind of host.
This solution works, but is not universal (ZSH only).
ネットワーク固有の設定
You can use host configuration specific to the network you are connected to using a Match exec
.
For example, when using nmcli(1), and the connection is configured (manually or through DHCP) to use a search-domain:
Match exec "nmcli | grep domains: | grep example.com" CanonicalDomains example.com # Should you use a different username on this network #User username # Use a different known_hosts file (for private network or synchronisation) #UserKnownHostsFile <network>_known_hosts
Another example for Match host ... exec "..."
: Consider that connecting to internal.example.com
requires a bastion/proxy (via ProxyJump
) unless you are already connected via VPN. The fragment !exec "host internal.example.com"
applies only when internal.example.com
cannot be looked up via DNS. Various alternatives are discussed at [5].
Match host internal.example.com !exec "host internal.example.com" ProxyJump bastion.example.com Host internal.example.com User foobar
プライベートネットワークのホスト鍵検証
Because different servers on different networks are likely to share a common private IP address, you might want to handle them differently.
The best solution is to use the #Network specific configuration to use a different UserKnownHostsFile
depending on the network you are on. The second solution, best used as default when you are working on new/prototype networks, would be to simply ignore hostkeys for private networks:
Host 10.* 192.168.*.* 172.31.* 172.30.* 172.2?.* 172.1?.* # Disable HostKey verification # Trust HostKey automatically StrictHostKeyChecking no # Do not save the HostKey UserKnownHostsFile=/dev/null # Do not display: "Warning: Permanently Added ..." LogLevel Error
ログイン時にコマンドを実行
If you are using an interactive session, there are multiple ways to execute a command on login:
- use the
authorized_keys
file on the remote host (seeAUTHORIZED_KEYS FILE FORMAT
in sshd(8)) - use
~/.ssh/rc
on the remote host if the server has enabled thePermitUserRC
option - use your shell configuration file on the remote host, e.g.
.bashrc
エージェントフォワーディング
SSH agent forwarding allows you to use your local keys when connected to a server. It is recommended to only enable agent forwarding for selected hosts.
~/.ssh/config
Host myserver.com ForwardAgent yes
Next, configure an SSH agent and add your local key with ssh-add.
If you now connect to a remote server you will be able to connect to other services using your local keys.
新しい鍵の生成
New server private keys can be generated by:
- Deleting all the keys, e.g.:
# rm /etc/ssh/ssh_host_*_key*
- Restarting
sshdgenkeys.service
or runningssh-keygen -A
as root.
sshd を非特権ユーザとして実行
sshd
をコンテナ内で (或いはテスト目的などで) 非特権ユーザとして実行したい場合もあるでしょう。
非特権ユーザは /etc/ssh
内のホスト鍵を読むことができないため、新しいホスト鍵を生成しなければなりません:
$ ssh-keygen -q -N "" -t rsa -b 4096 -f /path/to/host/keys/ssh_host_rsa_key $ ssh-keygen -q -N "" -t ecdsa -f /path/to/host/keys/ssh_host_ecdsa_key $ ssh-keygen -q -N "" -t ed25519 -f /path/to/host/keys/ssh_host_ed25519_key
sshd_config
を作成してください。以下の例では、1024 より大きい値のポート番号を使用し、ホスト鍵への新しいパスを提供し、PAM を無効化します:
/path/to/sshd_config
Port 2022 HostKey /path/to/host/keys/ssh_host_rsa_key HostKey /path/to/host/keys/ssh_host_ecdsa_key HostKey /path/to/host/keys/ssh/ssh_host_ed25519_key UsePAM no
新しく作成した設定で sshd を実行します。-D
フラグはデーモンモードを無効化し、-e
は出力を標準出力にリダイレクトしてモニタしやすくします:
$ sshd -f /path/to/sshd_config -D -e
トラブルシューティング
チェックリスト
以下は最初に行うべきトラブルシューティングのチェックリストです。何かする前に以下の問題をチェックすることを推奨します。
- 設定ディレクトリ
~/.ssh
の中身がユーザーからアクセスできることを確認する (クライアントとサーバーの両方で確認してください):$ chmod 700 ~/.ssh $ chmod 600 ~/.ssh/* $ chown -R $USER ~/.ssh
- クライアントの公開鍵 (例:
id_rsa.pub
) がサーバーの~/.ssh/authorized_keys
に存在することを確認する。 - サーバーの設定で
AllowUsers
やAllowGroups
によって SSH によるアクセスが制限されていることを確認する。 - ユーザーにパスワードが設定されていることを確認する。新しいユーザーにはパスワードが設定されていない可能性があります。
sshd
を再起動してクライアントとサーバーの両方で一度ログアウトをしてみる。
接続が拒否されるまたはタイムアウトする
ルーターがポートフォワーディングをしていないか?
NAT モードやルーターを使っている場合、ルーターが ssh 接続を転送していないか確認してください。サーバーの内部 IP アドレスは $ ip addr
で確認することができるので、SSH ポートの TCP をその IP に転送するようにルーターを設定してください。portforward.com も役に立ちます。
SSH が動作しているか?
$ ss -tnlp
上記のコマンドで SSH ポートが開いていると表示されない場合、SSH は動作していません。/var/log/messages
にエラーがないか確認してください。
接続をブロックするようなファイアウォールのルールが存在しないか?
iptables によってポート 22
の接続がブロックされている可能性があります。次のコマンドで確認してください:
# iptables -nvL
INPUT
チェインのパケットを拒否するようなルールがないか見て下さい。そして、必要であれば、次のようなコマンドでポートのブロックを解除します:
# iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
ファイアウォールの設定に関する詳細はファイアウォールを見て下さい。
トラフィックがコンピュータにまで到達しているか?
以下のように問題のコンピュータのトラフィックを収集してみてください:
# tcpdump -lnn -i any port ssh and tcp-syn
上記は基本的な情報を表示します。トラフィックが表示されるまで待ってください。その後、接続を試行してみてください。何も出力がされない場合、コンピュータの外側にある何かがトラフィックを妨害しています (例: ハードウェアファイアウォールや NAT ルーターなど)。
ISP またはサードパーティによってデフォルトのポートがブロックされてないか?
ときどき ISP (インターネット・サービス・プロバイダ) が SSH のデフォルトポート (22番) をブロックしている場合があります。この場合はあなたが何をしても (ポートを開ける、スタックを強化する、フラッドアタックを防御する、など) 無意味になります。ブロックされているかどうか確認するために、全てのインターフェイス (0.0.0.0) をリッスンする sshd を立ち上げ、リモートから接続してみます。
このようなエラーメッセージが出る場合:
ssh: connect to host www.inet.hr port 22: Connection refused
これはそのポートが ISP にブロックされていないが、そのポートでサーバーの SSH が起動していないことを意味します (security through obscurity を参照)。
しかし、次のようなエラーメッセージが出る場合:
ssh: connect to host 111.222.333.444 port 22: Operation timed out
これは何かがポート 22 での TCP トラフィックを拒否 (reject) していることを意味します。そのポートはあなたのサーバー上のファイアーウォールか第三者 (ISP など) のどちらかによってステルスされています。自分のサーバーでファイアーウォールが起動していないことが確かなら、また、ルーターやスイッチの中でグレムリンが育っていないことが確かなら、ISP がトラフィックをブロックしています。
ダブルチェックのために、サーバ上で Wireshark を起動してポート 22 でのトラフィックをリッスンしてみましょう。Wireshark はレイヤ 2 のパケット・スニファリング・ユーティリティであり、TCP/UDP はレイヤ 3 以上なので (IP ネットワークスタックを参照)、もしリモートから接続するときに何も受け取っていなければ、十中八九、第三者がブロックしています。
問題診断
tcpdump または wireshark-cli パッケージの Wireshark をインストールしてください。
tcpdump の場合:
# tcpdump -ni interface "port 22"
Wireshark の場合:
$ tshark -f "tcp port 22" -i interface
interface
は WAN 接続に使っているネットワークインターフェイスに置き換えてください (確認したいときは ip a
を実行)。リモートで接続を試行してもパケットが全く受け取れない場合、ISP によってポート 22 のトラフィックがブロックされている可能性があります。
解決方法
解決方法は、単に ISP がブロックしていない他のポートを使うことです。/etc/ssh/sshd_config
を編集して他のポートを使うようにしましょう。例えば次を追加します:
Port 22 Port 1234
そしてこのファイル中の他の Port 設定をコメントアウトします。「Port 22」をコメントにして「Port 1234」を追加するだけでは、sshd がポート 1234 しかリッスンしなくなるので、この問題は解決しません。この 2 行どちらも使用し、sshd が両方のポートをリッスンするようにします。
あとは systemctl restart sshd.service
で sshd を起動するだけです。そして ssh クライアントでも同じポートに変更します。
Read from socket failed: connection reset by peer
最近の openssh のバージョンでは、楕円曲線暗号関連のバグのせいで、上記のエラーメッセージで接続が失敗することがあります。その場合 ~/.ssh/config
に次の行を追加してください:
HostKeyAlgorithms ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,ssh-rsa-cert-v00@openssh.com,ssh-dss-cert-v00@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss
openssh 5.9 では、上記の修正方法は働きません。代わりに、~/.ssh/config
に以下の行を記述してください:
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc MACs hmac-md5,hmac-sha1,hmac-ripemd160
openssh バグフォーラムの 議論 も参照。
"[your shell]: No such file or directory" / ssh_exchange_identification 問題
シェルのバイナリに $PATH
が通っている場合でも、特定の SSH クライアントは $SHELL
に絶対パスを設定する必要があります (パスは whereis -b [your shell]
で確認できます)。
"Terminal unknown" や "Error opening terminal" エラーメッセージ
ssh でログイン時に "Terminal unknown" のようなエラーが表示されることがあります。これはサーバーがターミナルを認識できていないことを意味します。また、nano などの ncurses アプリケーションを実行すると "Error opening terminal" というメッセージが表示されます。
クライアントで使用しているターミナルの terminfo ファイルをサーバーにインストールするのが正しい解決方法です。これによってサーバーのコンソールプログラムがターミナルを正しく扱えるようになります。infocmp
を実行してからパッケージを確認することで terminfo に関する情報を取得できます。
通常の方法でファイルをインストールできない場合、サーバーのホームディレクトリに terminfo をコピーしてください:
$ ssh myserver mkdir -p ~/.terminfo/${TERM:0:1} $ scp /usr/share/terminfo/${TERM:0:1}/$TERM myserver:~/.terminfo/${TERM:0:1}/
サーバーから一度ログアウトしてからログインしなおすと問題が解決しているはずです。
$TERM 変数を設定する解決策
.bash_profile
などで TERM=xterm
と設定することでもエラーが表示されなくなり、ncurses アプリケーションが動作するようになります。ただし副作用があり、ターミナルの制御シーケンスが xterm と異なっている場合グラフィックがおかしくなります。
Connection closed by x.x.x.x [preauth]
sshd のログでこのエラーが確認できる場合、HostKey が正しく設定されているか確認してください:
HostKey /etc/ssh/ssh_host_rsa_key
サブシステム要求の失敗
OpenSSH 8.8 以降、scp はデータ転送のデフォルトプロトコルとして SFTP を使用し、sftp
というサブシステムを要求するようになりました。もし scp を冗長モード scp -v
で実行すれば、クライアントがどのサブシステムを使っているかがわかります (例: Sending subsystem: <subsystem-name>
)。subsystem request failed on channel 0
のようなエラーは、サーバのサブシステムを設定することで修正できるかもしれません。{man|5|sshd_config|Subsystem}} のように設定します。サーバの設定は、以下の例のようにする必要があります。
/etc/ssh/sshd_config
... Subsystem subsystem-name /path/to/subsystem-executable ...
OpenSSH 7.0 によって id_dsa が拒否される
OpenSSH 7.0 ではセキュリティ上の理由から ssh-dss が無効になっています。どうしても有効にする必要がある場合、クライアントの設定オプションを使用してください ([6] には書かれていない方法です):
PubkeyAcceptedKeyTypes +ssh-dss
OpenSSH 7.0 で No matching key exchange method found
OpenSSH 7.0 では Logjam 攻撃からの(理論上の)脆弱性を理由に diffie-hellman-group1-sha1 鍵アルゴリズムが無効になっています (http://www.openssh.com/legacy.html を参照)。特定のホストで鍵アルゴリズムが必要な場合、ssh は以下のようなエラーメッセージを吐きます:
Unable to negotiate with 127.0.0.1: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1
古いアルゴリズムを使用しないようにサーバーをアップグレード・設定することで上記のエラーは解決します。サーバー側の設定を変更できない場合、クライアント設定で KexAlgorithms +diffie-hellman-group1-sha1
オプションを使うことでアルゴリズムを有効化できます。
SSH から切断したときに tmux/screen セッションが終了する
セッションの最後にプロセスが終了する場合、ソケットアクティベーションを使っているために SSH セッションプロセスが終了したときに systemd によって終了されている可能性があります。ssh.socket
の代わりに ssh.service
を使用してソケットアクティベーションを使わないことで解決できます。もしくは ssh@.service
の Service セクションで KillMode=process
を設定してください。
KillMode=process
は古典的な ssh.service
でも役に立つことがあります。サーバーが停止したり再起動したときに SSH セッションプロセスや screen や tmux のプロセスが終了されることを防ぐことができます。
SSH セッションが応答しなくなる
SSH は Software flow control XON
と XOFF
に反応します。Ctrl+s
を押すとフリーズ/ハングアップ/応答停止します。セッションを再開するには Ctrl+q
を使ってください。
Broken pipe
接続を作ろうとして packet_write_wait
のレスポンスが Broken pipe
になった場合、デバッグモードで接続を再試行し、出力がエラーで終わるかどうか確認する必要があります。
debug3: send packet: type 1 packet_write_wait: Connection to A.B.C.D port 22: Broken pipe
上記の send packet
の行は、応答パケットが受信されなかったことを示しています。つまり、これは QoS の問題であることがわかります。パケットを落とす可能性を減らすには、IPQoS
を設定してください。
/etc/ssh/ssh_config
Host * IPQoS reliability
サービスタイプは reliability
(0x04
) で、0x00
や throughput
(0x08
) と同様に問題を解決できるはずです。
再起動後デーモンの起動が遅い
特にヘッドレスサーバや仮想化サーバにおいて、再起動後のデーモン起動時間が過度に長くなる場合(例:デーモンが接続を受け付け始めるまでに数分かかる)、エントロピー不足が原因かもしれません [7] これは、あなたのシステムに適した Rng-tools や Haveged をインストールすれば改善することが可能です。ただし、それぞれのパッケージの wiki ページで説明されている、関連するセキュリティ上の影響に注意してください。
応答のない SSH 接続を終了する
クライアントセッションが応答しなくなり、実行中のプログラム (例えば シェル) に終了を指示しても終了しない場合、 Enter
, ~
, .
をこの順番で次々に押すと、セッションを終了させることが可能です。
この ~
は疑似端末エスケープ文字で (ssh(1) § ESCAPE CHARACTERS 参照) 終了させるクライアントセッションに応じて複数回付加することが可能です。例えば、A から B へ接続し、B から C へ接続したときに B から C へのセッションがフリーズした場合、 Enter
を押して ~.
と入力すれば、B の作業セッションを残して終了させることができます。
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
クライアントが ssh サーバの鍵が変更されたことを警告した場合、新しく提供された鍵が 本当にサーバオペレータのものであるかどうかを確認する必要があります。そして known_hosts
ファイルから古い鍵を ssh-keygen -R $SSH_HOST
で削除し、新しい鍵を新しいサーバであるかのように受け入れてください。
適切な terminfo エントリがないリモートに接続する場合
端末の terminfo エントリがないホストに接続する場合、例えば、terminfo エントリが ncurses に同梱されていない端末エミュレータを使用する場合などです。(例えば kitty や rxvt-unicode) terminfo データベースが制限されているホスト (例えば OpenWrt が動いているシステム) に接続する場合、terminfo(5) に依存しているソフトウェアで様々な問題が発生する可能性があります。
適切な解決策は、適切な terminfo エントリをホストに設置することです。それが不可能な場合は、リモートホストがサポートし、かつ端末と互換性のある値を TERM
に設定することで解決できます。
OpenSSH 8.7 以降、カスタムの TERM
環境変数をリモートホストに渡すには、 簡単な設定スニペットを使います。
~/.ssh/config
Host example.com SendEnv TERM=xterm-256color
参照
- Defending against brute force ssh attacks
- OpenSSH 鍵管理: IBM developerWorks の Part 1、funtoo.org の Part 2、Part 3
- Secure Secure Shell