「OpenSSH」の版間の差分
(同期) |
Kusanaginoturugi (トーク | 投稿記録) |
||
1行目: | 1行目: | ||
− | [[Category: |
+ | [[Category:セキュアシェル]] |
[[Category:サーバー]] |
[[Category:サーバー]] |
||
[[Category:OpenBSD]] |
[[Category:OpenBSD]] |
2024年8月16日 (金) 18:37時点における版
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 "[シェル]: 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 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 応答のない SSH 接続を終了する
- 5.13 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
- 5.14 適切な terminfo エントリがないリモートに接続する場合
- 5.15 踏み台ホストを介する接続が "bash: No such file or directory" で失敗する
- 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
オプションによって一部の署名アルゴリズムしか許可されていない場合でも、鍵が存在しない場合、再生成されます。rsa、ecdsa、そして ed25519 アルゴリズムに基づく3組の鍵のペアが提供されます。sshd に特定の鍵を使用させるには、以下のオプションを指定してください:
HostKey /etc/ssh/ssh_host_rsa_key
サーバを WAN に公開するつもりであるならば、以下のようにデフォルトのポートを 22 から別のランダムで大きい値に変更することが推奨されます:
Port 39901
デーモンの管理
sshd.service
を起動/有効化してください。これは、SSH デーモンを永続的にアクティブ状態に保ち、各着信接続に対してフォークします。
保護
SSH によるリモートログインを許可することは管理業務においては良いことですが、サーバーのセキュリティに脅威を及ぼすことにもなりえます。総当り攻撃の標的になりやすいので、SSH のアクセスは制限して、第三者がサーバーにアクセスできないようにする必要があります。
ssh-audit は、サーバとクライアントの設定の自動化された解析を提供します。このトピックに関して、いくつか他のガイドやツールが利用できます。例えば:
公開鍵認証を強制する
デフォルトでは、クライアントが公開鍵で認証できない場合、SSH サーバはパスワード認証にフォールバックします。なので、悪意のあるユーザがパスワードのブルートフォースによるアクセスを試みることができてしまいます。このような攻撃から保護する最も効果的な方法の1つが、パスワードログインを完全に無効化し、SSH 鍵の使用を強制することです。これは、デーモンの設定ファイルで以下のオプションを設定することで可能です:
/etc/ssh/sshd_config.d/20-force_publickey_auth.conf
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.d/20-pam.conf
KbdInteractiveAuthentication yes AuthenticationMethods publickey keyboard-interactive:pam
これで、PAM セットアップによって要求されるユーザ認証か公開鍵のどちらか一方でログインできます。
一方、PAM セットアップによって要求されるユーザ認証と公開鍵の両方でユーザを認証したい場合、AuthenticationMethods の分割にスペースではなくコンマを使用してください:
/etc/ssh/sshd_config.d/20-pam.conf
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.d/20-deny_root.conf
PermitRootLogin no
次に、SSH デーモンを再起動してください。
これで、SSH を使って root でログインすることはできなくなります。ただし、通常ユーザーでログインしてから su や sudo を使ってシステム管理を行うことは依然として可能です。
制限
自動的な作業の中にも、リモートによるフルシステムバックアップなど、root 権限を必要とするものがあります。セキュアな方法で root を許可したい場合、SSH による root ログインを無効化する代わりに、特定のコマンドだけ root ログインを許可することができます。~root/.ssh/authorized_keys
を編集して、以下のように特定のキーの前にコマンドを記述します:
command="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
から変更不可のビットを削除して一時的に書き込み可能にする必要があります。
SSH 証明書
一般的な SSH 鍵と手動でのフィンガープリントの検証は、一人の管理者によって管理されている少数のホストにおいては簡単でしょうが、この認証方法は拡張性が全くありません。一定数のサーバをいくつかのユーザが SSH を通してアクセスする必要がある場合、全てのホストの SSH 公開鍵フィンガープリントを手動でセキュアかつ確実に検証するのは、ほぼ不可能です。
これに対する解決策は、SSH 証明書を使うことです。SSH 証明書を使えば、SSH のデフォルトの Trust On First Use アプローチよりも拡張性の高い信用の鎖によって、公開鍵の正当性を自動で検証できます。SSH 証明書は、基本的には通常の SSH 公開鍵ですが、信頼されている認証局からの署名が付け加えられおり、これにより鍵の正当性を検証します。
インフラストラクチャ用のホスト認証局の鍵を作成する
$ ssh-keygen -t ed25519 -f ~/.ssh/ca_host_key -C 'Host certificate authority for *.example.com'
認証局の秘密鍵はセキュアに保存されているべきです。鍵の抽出を防止する機構が備わっている Nitrokey や YubiKey といったスマートカードやハードウェアトークン上に保存するのが理想です。
サーバの SSH ホスト公開鍵を署名する
サーバの公開鍵を、認証局の秘密鍵が保存されているローカルのシステムにコピーし、サーバの公開鍵を署名してください:
$ ssh-keygen -h -s ~/.ssh/ca_key -I certLabel -n server01.example.com ./ssh_host_ed25519_key.pub
新しい証明書を移動し、sshd にそれを使わせる
生成された証明書 ssh_host_ed25519_key-cert.pub
は、サーバの /etc/ssh/
にコピーする必要があります。
/etc/ssh/sshd_config.d/20-ed25519_key.conf
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
認証局を信頼するように全てのクライアントを設定する
~/.ssh/known_hosts
@cert-authority *.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKL8gB/pjuff005YNazwMCqJpgsXAbQ3r4VStd/CRKwU Host certificate authority for *.example.com
SSH ユーザ証明書
ユーザの数やデプロイ方法にもよりますが、SSH ユーザ鍵を証明書と共に使用することもできます。多くの ssh ユーザが存在する組織では、この方法でユーザ鍵のデプロイをセキュアに管理することが強く推奨されます。
ユーザ証明書のデプロイは、基本的にはサーバの ID と同じように機能します。詳細と方法については Wikibooks:OpenSSH/Cookbook/Certificate-based Authentication で見られます。
証明書のデプロイを自動化する
多くのオープンソースなツールによって、SSH 証明書のデプロイを自動化する方法が提供されています。人気なものとしては例えば以下があります:
SSHFP レコード
Secure Shell fingerprint record (SSHFP) は、DNS におけるオプションのリソースレコードで、SSH 鍵をホスト名と関連付けます。信用された CA 証明書をサーバー上にアップロードする代わりに DNSSEC を使用することで、公開サーバー上の SSH フィンガープリントを検証することができます。これにより、管理されていないクライアントも鍵のフィンガープリントの有効性を検証することができます。
レコードエントリを生成する
16進数の鍵フィンガープリントを生成して、DNS レコードに記録するには、対象サーバー上でハッシュ値を作成してください。
$ ssh-keygen -r host.example.com
このコマンドで、指定したドメインの利用可能な全 SSH 鍵を読み出し、有効な SSHFP レコードを出力します。この出力されたレコードを、影響するドメインの DNS エントリに記録することができます。
クライアントの設定
SSHFP レコードとして保存されている SSH 鍵フィンガープリントを自動的に取得して信用するには、以下の設定を ssh クライアント側の設定ファイルに追加してください:
~/.ssh/config
# global options Match all VerifyHostKeyDNS yes
対象ホストに有効な SSHFP レコードがあり、そのレコードが有効な DNSSEC 署名で検証されると、ホストが本物であるかどうかを尋ねるプロンプトが表示されずに、フィンガープリントが自動的に受理されます。DNS レコードが DNSSEC によって検証されない場合は、フィンガープリントが正しいかどうかを尋ねるプロンプトが代わりに表示されます。
SSHFP レコードを生成する
ドメインの SSH フィンガープリントを知りたい場合は、ssh-keyscan を使うことで有効な DNS レコードの形式で SSH フィンガープリントを取得できます。(注: デフォルトでは、利用可能な鍵タイプすべてのフィンガープリントが SHA1 と SHA256 の両方で出力されます。)
$ ssh-keyscan -D github.com
; github.com:22 SSH-2.0-babeld-57ca1323 ; github.com:22 SSH-2.0-babeld-57ca1323 github.com IN SSHFP 1 1 6f4c60375018bae0918e37d9162bc15ba40e6365 github.com IN SSHFP 1 2 b8d895ced92c0ac0e171cd2ef5ef01ba3417554a4a6480d331ccc2be3ded0f6b ; github.com:22 SSH-2.0-babeld-57ca1323 github.com IN SSHFP 3 1 3358ab5dd3e306c461c840f7487e93b697e30600 github.com IN SSHFP 3 2 a764003173480b54c96167883adb6b55cf7cfd1d415055aedff2e2c8a8147d03 ; github.com:22 SSH-2.0-babeld-57ca1323 github.com IN SSHFP 4 1 e9619e2ed56c2f2a71729db80bacc2ce9ccce8d4 github.com IN SSHFP 4 2 f83898df0bef57a4ee24985ba598ac17fccb0c0d333cc4af1dd92be14bc23aa5 ; github.com:22 SSH-2.0-babeld-57ca1323
SSH フィンガープリントは一般的には公開鍵の SHA256 ハッシュ値を base64 エンコードしたものですが、SSHFP レコードは鍵のフィンガープリントを16進数で保存します。そのため、通常 SHA256 でフィンガープリントを記録している known_hosts ファイルやその他の文書にある値と比べるために、レコードを base64 の形式に変換する必要があります。
$ echo "SSHFP-fingerprint" | xxd -r -p | base64
鍵タイプ ed25519 の SHA256 フィンガープリントに16進数を使用している github.com の例です。
$ echo "f83898df0bef57a4ee24985ba598ac17fccb0c0d333cc4af1dd92be14bc23aa5" | xxd -r -p | base64
+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU=
known_hosts エントリと比べるには:
$ ssh-keygen -l -f ~/.ssh/known_hosts
DNS から手動で SSHFP レコードを取得する
$ dig SSHFP targetdomain.tld +short
ヒントとテクニック
暗号化 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
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
ProxyCommand オプションを使えばこれを自動化することができます:
$ ssh -o ProxyCommand="ssh -W %h:%p bastion.example.org" targetserver.example.org
-J
フラグで ProxyJump オプションを使用すれば、これをより簡単かつセキュアに行うことができます:
$ ssh -J user1@bastion1,user2@intermediate2 user3@target
-J
ディレクティブで指定するホストはカンマで区切り、指定された順番で接続されます。user...@
の部分は必須ではありません。-J
で指定したホストは ssh の設定ファイルを使うため、必要であればホスト毎にオプションを設定することが可能です。
ProxyCommand オプションと ProxyJump オプションの主な違いは、後者は踏み台ホスト上のシェルを必要としないところにあります。その結果、ユーザのログイン認証情報への踏み台サーバでのアクセスや SSH エージェントフォワーディングが必要なくなります。ProxyJump オプションでは、ssh クライアントは踏み台サーバを通して直接ターゲットのサーバへ接続し、エンドツーエンドの暗号化されたチャネルをクライアントとターゲットサーバとの間で確立します。
設定ファイルにも、-J
フラグと等価なものとして ProxyJump
オプションがあります。詳細は ssh_config(5) を見てください。
リレーを介したリバース SSH
アイデアとしては、クライアントは別のリレーを使ってサーバに接続し、サーバはリバース SSH トンネルを使って同じリレーに接続します。これは、サーバが NAT 内にあり、リレーが、ユーザがアクセス可能なプロキシとして使用されている、パブリックにアクセス可能な SSH サーバである場合に便利です。ゆえに、クライアントの鍵がリレーとサーバの両方に対して認可されていることが前提条件であり、サーバはリレーに対してもリバース SSH 接続に対しても認可されている必要があります。
以下の設定例では、user1 が client 上で使用されているユーザアカウントであり、user2 は relay 上のアカウント、user3 が server 上のアカウントであるとします。まず、以下のコマンドでサーバとリバーストンネルとの接続が確立している必要があります (2222番ポートを使うものとします):
ssh -R 2222:localhost:22 -N user2@relay
これは、スタートアップスクリプトや systemd サービス、autossh、sidedoorAUR を使って自動化することもできます。
クライアント側では、以下のコマンドで接続を確立させます:
ssh -t user2@relay ssh user3@localhost -p 2222
リバーストンネルとの接続を確立させるためのリモートのコマンドは、relay の ~/.ssh/authorized_keys
に以下のような command
フィールドを含めることで、定義できます:
command="ssh user3@localhost -p 2222" ssh-rsa KEY2 user1@client
この場合、接続は以下のコマンドで確立できます:
ssh user2@relay
または、RemoteCommand
と RequestTTY
を指定するエントリを ssh の設定に追加することもできます:
~/.ssh/config
Host jump-destination Hostname relay User user2 RemoteCommand ssh user3@localhost -p 2222 RequestTTY yes
この場合、以下のように簡単にできます:
ssh jump-destination
マルチプレクス
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-hpnAUR パッケージをインストールしてください。
SSHFS でリモートファイルシステムをマウントする
sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は SSHFS の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に shfs よりも sshfs を使用することを推奨します。sshfs は shfs の新しいバージョンであり、元の shfs は2004年から更新されていません。
キープアライブ
デフォルトでは、SSH セッションが一定時間アイドルであった場合、自動的にログアウトします。一定時間データが受信されなかった場合にサーバにキープアライブシグナルを送信することで、セッションを開いたままにすることができます。あるいは対照的に、クライアントからデータが送られてこない場合にサーバが定期的にメッセージを送信することもできます。
- サーバ側:
ClientAliveInterval
はタイムアウトを秒単位で設定します。クライアントからデータが受信されずにその時間経過すると、sshd が応答を促すリクエストを送信します。デフォルトは0であり、メッセージは送信されません。例えば、60秒毎にクライアントに対して応答を要求するには、サーバ側の設定でClientAliveInterval 60
オプションを設定してください。ClientAliveCountMax
とTCPKeepAlive
オプションも参照してください。 - クライアント側:
ServerAliveInterval
は、クライアントからサーバに向けて送信されるリクエストの時間間隔を設定します。例えば、120秒毎にサーバに対して応答を要求するには、クライアント側の設定でServerAliveInterval 120
オプションを追加してください。ServerAliveCountMax
とTCPKeepAlive
オプションも参照してください。
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 デーモンが失敗した場合の代替サービス
SSH のみに依存するリモート或いはヘッドレスのサーバにおいて、(システムアップグレード後などに) SSH デーモンの起動に失敗すると、管理アクセスできなくなってしまう場合があります。systemd は、OnFailure
によるシンプルなソリューションを提供しています。
サーバ上で sshd
が実行されていて、telnet がフェイルセーフであるとしてます。以下のようにファイルを作成してください。ただし、telnet.socket
は有効化しないでください!
/etc/systemd/system/sshd.service.d/override.conf
[Unit] OnFailure=telnet.socket
これだけです。sshd
が実行中である場合、Telnet は実行されません。sshd
が起動に失敗した場合、telnet セッションがリカバリとして開かれます。
ホストに基づいてターミナル背景色を設定する
異なるホストに接続していることを簡単に判別できるようにするために、ホストの種類に応じて異なる背景色を設定することができます。
このソリューションは一般には適用できません (ZSH 限定)。
ネットワーク固有の設定
Match exec
を使うことで、接続先のネットワークに固有のホスト設定を使用することができます。
例えば、nmcli(1) を使用していて、接続が検索ドメインを使用するように (手動、あるいは DHCP で) 設定されている場合:
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
Match host ... exec "..."
の例: VPN に接続していない限り、internal.example.com
への接続に (ProxyJump
を用いた) 踏み台/プロキシが必要であるとしましょう。フラグメント !exec "host internal.example.com"
は、internal.example.com
が DNS を介して見つけられない場合にのみ、適用されます。様々な代替案が [4] で議論されています。
Match host internal.example.com !exec "host internal.example.com" ProxyJump bastion.example.com Host internal.example.com User foobar
プライベートネットワークのホスト鍵検証
あるネットワーク上のサーバとそれとは別のネットワーク上のサーバは、互いに同じプライベート IP アドレスを持つ可能性があるため、それらのサーバは異なる方法で処理する必要があるかもしれません。
最適なソリューションは、#ネットワーク固有の設定 を使用し、接続しているネットワークに応じて異なる UserKnownHostsFile
を使うことです。2つめのソリューションは、プライベートネットワークのホスト鍵を単に無視することです (新しい/プロトタイプのネットワークで作業する際にデフォルトで使用するのが最適です):
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
ログイン時にコマンドを実行
インタラクティブセッションを使用している場合、ログイン時にコマンドを実行する方法は複数存在します:
- リモートホスト上の
authorized_keys
ファイルを使用する (sshd(8) § AUTHORIZED_KEYS FILE FORMAT を参照) - サーバで
PermitUserRC
オプションが有効化されている場合、リモートホスト上の~/.ssh/rc
を使用する - リモートホスト上のシェル設定ファイルを使用する (例:
.bashrc
)
エージェントフォワーディング
SSH エージェントのフォワーディングにより、サーバに接続している状態でローカルの鍵を使用することができます。選択したホストのみに対してエージェントフォワーディングを許可することが推奨されます。
~/.ssh/config
Host myserver.com ForwardAgent yes
次に、SSH エージェントを構成し、ssh-add を使ってローカル鍵を追加してください。
これで、リモートサーバに接続する場合、あなたのローカル鍵を使用して他のサービスに接続できるようになりました。
新しい鍵の生成
新しいサーバの秘密鍵は以下で生成できます:
- すべての鍵を削除する。例えば:
# rm /etc/ssh/ssh_host_*_key*
sshdgenkeys.service
を再起動するか、ssh-keygen -A
を 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 go-w ~ $ chmod 700 ~/.ssh $ chmod 600 ~/.ssh/* $ chown -R $USER ~/.ssh
- クライアントの公開鍵 (例:
id_rsa.pub
) がサーバ上の~/.ssh/authorized_keys
内に記述されていることを確認する。 - サーバの設定の
AllowUsers
やAllowGroups
によって SSH のアクセスが制限されていないことを確認する。 - ユーザがパスワードを設定しているかを確認する。サーバにログインしたことのない新しいユーザは、パスワードを持っていないことがあります。
/etc/ssh/sshd_config
にLogLevel DEBUG
を追加してみる。journalctl -xe
を root として実行して、(エラー) メッセージの取得を試みる。sshd
を再起動し、クライアントとサーバの両方でログアウト/ログインする。
接続の拒否やタイムアウトの問題
ポートフォワーディング
NAT モードやルータを使っている場合 (VPS を使っていたりパブリックにアドレッシングされたホストを使用していない限り、あり得ます)、ルータが ssh の着信接続をマシンにフォワーディングしていることを確認してください。$ ip addr
を使ってサーバの内部 IP アドレスを見つけ、SSH ポートの TCP 接続をその IP にフォワーディングするようにルータを設定してください。portforward.com が役に立ちます。
SSH が動作していて、リッスンしているか?
ss ユーティリティは、以下のコマンドラインを使うことで、TCP ポートをリッスンしている全プロセスを表示します:
$ ss --tcp --listening
このコマンドの出力を見て、システムが ssh
ポートをリッスンしていないことが判明した場合、SSH が実行されていないことを意味します。Journal でエラーなどが出力されていないか確認してください。
接続をブロックするようなファイアウォールのルールが存在しないか?
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) をリッスンするサーバを立ち上げ、リモートから接続してみてください。
このようなエラーメッセージが出る場合:
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 トラフィックを拒否していることを意味します。そのポートはあなたのサーバー上のファイアーウォールか第三者 (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 が両方のポートをリッスンするようにします。
sshd.service
サーバを再起動すれば、あともう少しです。次に、デフォルトのポートではなくもう一つのポートを使用するようにクライアントを設定しなければなりません。その問題に対するソリューションは数多く存在しますが、ここではそれらのうち2つを扱っています。
Read from socket failed: connection reset by peer
最近のバージョンの OpenSSH は時々、古い ssh サーバに接続する際に上記のエラーメッセージで失敗することがあります。これは、そのホストに対する様々なクライアントオプションを設定することにより、回避可能です。以下のオプションに関する詳細は ssh_config(5) を見てください。
ecdsa-sha2-nistp*-cert-v01@openssh
楕円曲線ホスト鍵アルゴリズムが原因である可能性があります。このようなアルゴリズムは、HostKeyAlgorithms
にそれらのアルゴリズムを除いたリストを設定することにより、無効化できます。クライアント側では、HostKeyAlgorithms
のリストの前に -
をつけることで、指定したアルゴリズム (ワイルドカードも可) をデフォルトから外すことができます (ssh_config(5)
man ページを参照)。
実際に使用されているホスト鍵のアルゴリズムは、ssh -v server_to_connect_to
を実行して、kex: host key algorithm:
と書かれてある行を見ればわかります。
これでうまく行かない場合、暗号のリストが長過ぎる可能性があります。Ciphers
オプションのリストを短くしてください (80 文字未満であれば十分でしょう)。同じように、MACs
のリストも短くしてみてください。
OpenSSH のバグフォーラムにおける議論も参照してください。
"[シェル]: No such file or directory" / ssh_exchange_identification の問題
シェルのバイナリが $PATH
に登録されているディレクトリ内にあったとしても、特定の SSH クライアントは $SHELL
に絶対パスを設定する必要があります (パスは whereis -b [あなたのシェル]
で確認できます)。
"Terminal unknown" や "Error opening terminal" エラーメッセージ
ログイン時に上記のようなエラーが表示される場合、サーバがターミナルを認識できていないことを意味します。また、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 ハック
あるいは、TERM=xterm
環境変数をサーバ側で (例えば .bash_profile
で) 設定してしまうという方法もあります。これでエラーは出なくなり、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
のようなエラーは、サーバのサブシステムを設定することで修正できるかもしれません。sshd_config(5) § Subsystem のように設定します。サーバの設定は、以下の例のようにする必要があります:
/etc/ssh/sshd_config
... Subsystem subsystem-name /path/to/subsystem-executable ...
id_dsa が拒否される
OpenSSH 7.0 ではセキュリティ上の理由により DSA 公開鍵が非推奨となっており、OpenSSH 9.8 はデフォルトで DSA 鍵のサポート無しでビルドされています。2025年最初の OpenSSH リリースでは、DSA のサポートが完全になくなる予定です。今のところ、DSA 公開鍵をどうしても使わなくてはならない場合は、configure
に --enable-dsa-keys
フラグを渡して openssh をビルドする必要があります。[5]
OpenSSH 7.0 で No matching key exchange method found
OpenSSH 7.0 では、Logjam 攻撃からの理論上の脆弱性を理由に diffie-hellman-group1-sha1 鍵アルゴリズムが非推奨になっています (https://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
Match all IPQoS reliability
サービスタイプ reliability
(0x04
) は、0x00
や throughput
(0x08
) と同様に、このコマンドを解決するはずです。
応答のない SSH 接続を終了する
クライアントセッションが応答しなくなり、実行中のプログラム (例えば シェル) に終了を指示しても終了しない場合、Enter
、~
、そして .
をこの順番で次々に押すと、セッションを終了させることが可能です。
この ~
は疑似端末エスケープ文字 (ssh(1) § ESCAPE CHARACTERS 参照) であり、終了させるクライアントセッションに応じて複数回付加することが可能です。例えば、A から B へ接続し、B から C へ接続したときに B から C へのセッションがフリーズした場合、Enter
を押して ~~.
と入力すれば、B の作業セッションを残して B から C へのセッションを終了させることができます。
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
SSH サーバの鍵が変更されたという警告がクライアントで表示された場合、新しく提供された鍵が本当にサーバオペレータのものであるかどうかを、何らかの信頼された方法 (暗号化されている必要はありません) で確認する必要があります。確認したら、known_hosts
ファイルから古い鍵を ssh-keygen -R $SSH_HOST
で削除し、新しいサーバーに接続するときと同じように鍵を受理してください。
適切な terminfo エントリがないリモートに接続する場合
あなたのターミナルの terminfo エントリが無いホストに接続する場合 (例えば、ncurses に同梱されていない terminfo エントリのターミナルを使用している場合) や、terminfo データベースが限られているホストに接続する場合 (例えば、OpenWrt を実行しているシステム)、terminfo(5) に依存しているソフトウェアで様々な問題が発生します。
適切な解決策は、適切な terminfo エントリをホストに設置することです。それが不可能な場合は、リモートホストがサポートし、かつ端末と互換性のある値を TERM
に設定することで解決できます。
OpenSSH 8.7 以降、カスタムの TERM
環境変数をリモートホストに渡すには、簡単な設定スニペットを使用してください:
~/.ssh/config
Host example.com SetEnv TERM=xterm-256color
踏み台ホストを介する接続が "bash: No such file or directory" で失敗する
(踏み台のサーバで) SHELL
環境変数に有効な完全パスを設定していない場合、以下に似たエラーメッセージで接続は失敗します:
bash: No such file or directory kex_exchange_identification: Connection closed by remote host Connection closed by UNKNOWN port 65535
踏み台サーバにおいて有効なシェルの完全パスを SHELL
に設定するか、~/.ssh/config
で各サーバに対して特定の SHELL
を設定することで、この問題を解決できます。
参照
- Wikibooks:ja:OpenSSH
- Defending against brute force ssh attacks
- OpenSSH 鍵管理: IBM developerWorks の Part 1、funtoo.org の Part 2、Part 3
- Secure Secure Shell