「OpenSSH」の版間の差分

提供: ArchWiki
ナビゲーションに移動 検索に移動
320行目: 320行目:
   
 
$ ssh -Y ''user@host''
 
$ ssh -Y ''user@host''
 
Given the output {{ic|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:
 
   
 
{{ic|X11 forwarding request failed}} と出力される場合、リモートマシンでセットアップをやり直してください。X11 フォワーディングのリクエストが成功したら、リモートサーバ上の任意の X プログラムを実行でき、プログラムがローカルセッションにフォワーディングされます:
 
{{ic|X11 forwarding request failed}} と出力される場合、リモートマシンでセットアップをやり直してください。X11 フォワーディングのリクエストが成功したら、リモートサーバ上の任意の X プログラムを実行でき、プログラムがローカルセッションにフォワーディングされます:
389行目: 387行目:
 
=== リレーを介したリバース SSH ===
 
=== リレーを介したリバース SSH ===
   
  +
アイデアとしては、クライアントは別のリレーを使ってサーバに接続し、サーバはリバース SSH トンネルを使って同じリレーに接続します。これは、サーバが NAT 内にあり、リレーが、ユーザがアクセス可能なプロキシとして使用されている、パブリックにアクセス可能な SSH サーバである場合に便利です。ゆえに、クライアントの鍵がリレーとサーバの両方に対して認可されていることが前提条件であり、サーバはリレーに対してもリバース 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.
 
   
  +
以下の設定例では、user1 が client 上で使用されているユーザアカウントであり、user2 は relay 上のアカウント、user3 が server 上のアカウントであるとします。まず、以下のコマンドでサーバとリバーストンネルとの接続が確立している必要があります:
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
 
ssh -R 2222:localhost:22 -N user2@relay
   
  +
これは、スタートアップスクリプトや systemd サービス、[[#Autossh - SSH セッションとトンネルの自動再起動|autossh]] を使って自動化することもできます。
Which can also be automated with a startup script, systemd service or [[#Autossh - automatically restarts SSH sessions and tunnels|autossh]].
 
 
{{Expansion|Explain why {{ic|ssh user3@relay -p 2222}} is not sufficient.}}
 
   
  +
クライアント側では、以下のコマンドで接続を確立させます:
At the client side, the connection is established with:
 
   
 
ssh -t user2@relay ssh user3@localhost -p 2222
 
ssh -t user2@relay ssh user3@localhost -p 2222
   
  +
リバーストンネルとの接続を確立させるためのリモートのコマンドは、relay の {{ic|~/.ssh/authorized_keys}} に以下のような {{ic|command}} フィールドを含めることで、定義できます:
The remote command to establish the connection to reverse tunnel can also be defined in relay's {{ic|~/.ssh/authorized_keys}} by including the {{ic|command}} field as follows:
 
   
 
command="ssh user3@localhost -p 2222" ssh-rsa KEY2 user1@client
 
command="ssh user3@localhost -p 2222" ssh-rsa KEY2 user1@client
   
  +
この場合、接続は以下のコマンドで確立できます:
In this case the connection is established with:
 
   
 
ssh user2@relay
 
ssh user2@relay
   
  +
注意点として、client の SCP の自動補完関数は機能せず、SCP 転送自体も特定の構成においては機能しません。
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.
 
   
 
=== マルチプレクス ===
 
=== マルチプレクス ===
452行目: 448行目:
 
sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は [[SSHFS]] の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に ''shfs'' よりも ''sshfs'' を使用することを推奨します。''sshfs'' は ''shfs'' の新しいバージョンであり、元の ''shfs'' は2004年から更新されていません。
 
sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は [[SSHFS]] の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に ''shfs'' よりも ''sshfs'' を使用することを推奨します。''sshfs'' は ''shfs'' の新しいバージョンであり、元の ''shfs'' は2004年から更新されていません。
   
  +
=== キープアライブ ===
=== セッションを生かし続ける ===
 
   
  +
デフォルトでは、SSH セッションが一定時間アイドルであった場合、自動的にログアウトします。一定時間データが受信されなかった場合にサーバにキープアライブシグナルを送信することで、セッションを開いたままにすることができます。あるいは対照的に、クライアントからデータが送られてこない場合にサーバが定期的にメッセージを送信することもできます。
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.
 
   
  +
* '''サーバ'''側: {{ic|ClientAliveInterval}} はタイムアウトを秒単位で設定します。クライアントからデータが受信されずにその時間経過すると、''sshd'' が応答を促すリクエストを送信します。デフォルトは0であり、メッセージは送信されません。例えば、60秒毎にクライアントに対して応答を要求するには、[[#設定_2|サーバ側の設定]]で {{ic|ClientAliveInterval 60}} オプションを設定してください。{{ic|ClientAliveCountMax}} と {{ic|TCPKeepAlive}} オプションも参照してください。
* On the '''server''' side, {{ic|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 the {{ic|ClientAliveInterval 60}} option in your [[#Configuration_2|server configuration]]. See also the {{ic|ClientAliveCountMax}} and {{ic|TCPKeepAlive}} options.
 
* On the '''client''' side, {{ic|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 the {{ic|ServerAliveInterval 120}} option to your [[#Configuration|client configuration]]. See also the {{ic|ServerAliveCountMax}} and {{ic|TCPKeepAlive}} options.
+
* '''クライアント'''側: {{ic|ServerAliveInterval}} は、クライアントからサーバに向けて送信されるリクエストの時間間隔を設定します。例えば、120秒毎にサーバに対して応答を要求するには、[[#設定|クライアント側の設定]]で {{ic|ServerAliveInterval 120}} オプションを追加してください。{{ic|ServerAliveCountMax}} {{ic|TCPKeepAlive}} オプションも参照してください。
   
  +
{{Note|セッションを開いたままにするためにキープアライブリクエストを送信する必要があるのは、クライアントかサーバの一方のみです。サーバとクライアントの両方を制御できるならば、セッションを永続的にする必要のあるクライアントに対してのみ {{ic|ServerAliveInterval}} を正の値に設定し、その他のクライアントやサーバはデフォルトの設定するのが妥当な選択です。}}
{{Note| To ensure a session is kept alive, only one of either the client or the server needs to send keep alive requests. If ones control both the servers and the clients, a reasonable choice is to only configure the clients that require a persistent session with a positive {{ic|ServerAliveInterval}} and leave other clients and servers in their default configuration.}}
 
   
 
=== systemd で SSH トンネルを自動的に再起動 ===
 
=== systemd で SSH トンネルを自動的に再起動 ===
478行目: 474行目:
 
</nowiki>}}
 
</nowiki>}}
   
上記の [[systemd/ユーザー]]サービスを[[有効化]]して[[起動]]してください。トンネルがタイムアウトするのを防ぐ方法は [[#セッションを生かし続ける]] を見て下さい。起動時にトンネルを開始したい場合、[[systemd#ユニットファイル|ユニットをシステムサービスとして書きなおして下さい]]。
+
上記の [[systemd/ユーザー]]サービスを[[有効化]]して[[起動]]してください。トンネルがタイムアウトするのを防ぐ方法は [[#キープアライブ]] を見て下さい。起動時にトンネルを開始したい場合、[[systemd#ユニットファイル|ユニットをシステムサービスとして書きなおして下さい]]。
   
 
=== Autossh - SSH セッションとトンネルの自動再起動 ===
 
=== Autossh - SSH セッションとトンネルの自動再起動 ===
529行目: 525行目:
 
=== SSH デーモンが失敗した場合の代替サービス ===
 
=== SSH デーモンが失敗した場合の代替サービス ===
   
  +
SSH のみに依存するリモート或いはヘッドレスのサーバにおいて、(システムアップグレード後などに) SSH デーモンの起動に失敗すると、管理アクセスできなくなってしまう場合があります。[[systemd]] は、{{ic|OnFailure}} によるシンプルなソリューションを提供しています。
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 {{ic|OnFailure}} option.
 
   
  +
サーバ上で {{ic|sshd}} が実行されていて、[[telnet]] がフェイルセーフであるとしてます。以下のようにファイルを作成してください。ただし、{{ic|telnet.socket}} は[[有効化]]'''しないでください'''!
Let us suppose the server runs {{ic|sshd}} and [[telnet]] is the fail-safe alternative of choice. Create a file as follows. Do '''not''' [[enable]] {{ic|telnet.socket}}!
 
   
 
{{hc|/etc/systemd/system/sshd.service.d/override.conf|2=
 
{{hc|/etc/systemd/system/sshd.service.d/override.conf|2=
538行目: 534行目:
 
}}
 
}}
   
  +
これだけです。{{ic|sshd}} が実行中である場合、Telnet は実行されません。{{ic|sshd}} が起動に失敗した場合、telnet セッションがリカバリとして開かれます。
That's it. Telnet is not available when {{ic|sshd}} is running. Should {{ic|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 [https://bryangilbert.com/post/etc/term/dynamic-ssh-terminal-background-colors/ different background color based on the kind of host].
+
異なるホストに接続していることを簡単に判別できるようにするために、[https://bryangilbert.com/post/etc/term/dynamic-ssh-terminal-background-colors/ ホストの種類に応じて異なる背景色]を設定することができます。
   
  +
このソリューションは一般には適用できません (ZSH 限定)。
This solution works, but is not universal (ZSH only).
 
   
 
=== ネットワーク固有の設定 ===
 
=== ネットワーク固有の設定 ===
   
  +
{{ic|Match exec}} を使うことで、接続先のネットワークに固有のホスト設定を使用することができます。
You can use host configuration specific to the network you are connected to using a {{ic|Match exec}}.
 
   
  +
例えば、{{man|1|nmcli}} を使用していて、接続が検索ドメインを使用するように (手動、あるいは DHCP で) 設定されている場合:
For example, when using {{man|1|nmcli}}, and the connection is configured (manually or through DHCP) to use a search-domain:
 
   
 
{{bc|1=
 
{{bc|1=
561行目: 557行目:
 
}}
 
}}
   
Another example for {{ic|Match host ... exec "..."}}: Consider that connecting to {{ic|internal.example.com}} requires a bastion/proxy (via {{ic|ProxyJump}}) unless you are already connected via VPN. The fragment {{ic|!exec "host internal.example.com"}} applies only when {{ic|internal.example.com}} cannot be looked up via DNS. Various alternatives are discussed at [https://serverfault.com/q/536043/117525].
+
{{ic|Match host ... exec "..."}} の例: VPN に接続していない限り、{{ic|internal.example.com}} への接続に ({{ic|ProxyJump}} を用いた) 踏み台/プロキシが必要であるとしましょう。フラグメント {{ic|!exec "host internal.example.com"}} は、{{ic|internal.example.com}} DNS を介して見つけられない場合にのみ、適用されます。様々な代替案が [https://serverfault.com/q/536043/117525] で議論されています。
   
 
{{bc|1=
 
{{bc|1=
572行目: 568行目:
 
=== プライベートネットワークのホスト鍵検証 ===
 
=== プライベートネットワークのホスト鍵検証 ===
   
  +
あるネットワーク上のサーバとそれとは別のネットワーク上のサーバは、互いに同じプライベート IP アドレスを持つ可能性があるため、それらのサーバは異なる方法で処理する必要があるかもしれません。
Because different servers on different networks are likely to share a common private IP address, you might want to handle them differently.
 
   
  +
{{Accuracy|「最適な」ソリューションに、本番環境では別のものを使うべきという警告があるはずがない。}}
{{Accuracy|The best solution would not need a warning to use something else in practice.}}
 
   
  +
最適なソリューションは、[[#ネットワーク固有の設定]] を使用し、接続しているネットワークに応じて異なる {{ic|UserKnownHostsFile}} を使うことです。2つめのソリューションは、プライベートネットワークのホスト鍵を単に無視することです (新しい/プロトタイプのネットワークで作業する際にデフォルトで使用するのが最適です):
The best solution is to use the [[#Network specific configuration]] to use a different {{ic|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:
 
   
 
{{bc|1=
 
{{bc|1=
589行目: 585行目:
 
}}
 
}}
   
  +
{{Accuracy|{{ic|known_hosts}} ファイルは、サーバにアクセスするためにホスト名を使用したとしても、IP アドレスを記録します。}}
{{Accuracy|The {{ic|known_hosts}} file records an IP address even when you use hostname to access the server.}}
 
   
  +
{{Warning|本番環境では、ホスト名を使用してホストにアクセスしたり、ネットワーク固有の known_hosts ファイルを使用するようにしてください。}}
{{Warning|In a production environment, make sure to either use the hostname to access the host and/or to use network specific known_hosts files.}}
 
   
 
=== ログイン時にコマンドを実行 ===
 
=== ログイン時にコマンドを実行 ===
   
  +
インタラクティブセッションを使用している場合、ログイン時にコマンドを実行する方法は複数存在します:
If you are using an interactive session, there are multiple ways to execute a command on login:
 
   
* use the {{ic|authorized_keys}} file on the remote host (see {{ic|AUTHORIZED_KEYS FILE FORMAT}} in {{man|8|sshd}})
+
* リモートホスト上の {{ic|authorized_keys}} ファイルを使用する ({{man|8|sshd}} {{ic|AUTHORIZED_KEYS FILE FORMAT}} セクションを参照)
  +
* サーバで {{ic|PermitUserRC}} オプションが有効化されている場合、リモートホスト上の {{ic|~/.ssh/rc}} を使用する
* use {{ic|~/.ssh/rc}} on the remote host if the server has enabled the {{ic|PermitUserRC}} option
 
  +
* リモートホスト上のシェル設定ファイルを使用する (例: {{ic|.bashrc}})
* use your shell configuration file on the remote host, e.g. {{ic|.bashrc}}
 
   
 
=== エージェントフォワーディング ===
 
=== エージェントフォワーディング ===
   
  +
SSH エージェントのフォワーディングにより、サーバに接続している状態でローカルの鍵を使用することができます。選択したホストのみに対してエージェントフォワーディングを許可することが推奨されます。
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.
 
   
 
{{hc|~/.ssh/config|
 
{{hc|~/.ssh/config|
610行目: 606行目:
 
}}
 
}}
   
  +
次に、[[SSH エージェント]]を構成し、''ssh-add'' を使ってローカル鍵を追加してください。
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.: {{bc|# rm /etc/ssh/ssh_host_*_key*}}
+
# すべての鍵を削除する。例えば: {{bc|# rm /etc/ssh/ssh_host_*_key*}}
# [[Restart]]ing {{ic|sshdgenkeys.service}} or running {{ic|ssh-keygen -A}} as root.
+
# {{ic|sshdgenkeys.service}} を[[再起動]]するか、{{ic|ssh-keygen -A}} root として実行する。
   
 
=== sshd を非特権ユーザとして実行 ===
 
=== sshd を非特権ユーザとして実行 ===
641行目: 637行目:
 
}}
 
}}
   
新しく作成した設定で ''sshd'' を実行します。{{ic|-D}} フラグはデーモンモードを無効化し、{{ic|-e}} は出力を標準出力にリダイレクトしてモニタしやすくします:
+
新しく作成した設定で ''sshd'' を実行します。{{ic|-D}} フラグはデーモンモードを無効化し、{{ic|-e}} は出力を標準エラー出力にリダイレクトしてモニタしやすくします:
   
 
$ sshd -f ''/path/to/sshd_config'' -D -e
 
$ sshd -f ''/path/to/sshd_config'' -D -e

2023年4月26日 (水) 06:37時点における版

この記事あるいはセクションは翻訳の途中です。
ノート: 飜訳および編集が必要です。英語版を参照してください。 (議論: トーク:OpenSSH#)

関連記事

OpenSSH (OpenBSD Secure Shell) は、Secure Shell (SSH) プロトコルを用いてコンピュータネットワーク経由の暗号化された通信セッションを提供するコンピュータプログラム群です。OpenSSH は、SSH Communications Security によって提供されているプロプライエタリな Secure Shell ソフトウェアスイートのオープンソースな代替として作成されました。OpenSSH は OpenBSD プロジェクトの一部として開発されており、Theo de Raadt によって率いられています。

OpenSSH は、似た名前の OpenSSL と混同されることがあります。しかし、これらのプロジェクトの目的は異なり、開発チームも異なります。この似たような名前は、ただ単にゴールが似ているからです。

目次

インストール

openssh パッケージをインストールしてください。

クライアントの使用

サーバに接続するには、以下を実行してください:

$ 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
ヒント:
  • 一般的なサービスにまだ割り当てられていない代替ポートを探すには、TCP と UDP のポート番号一覧を見てください。また、/etc/services にあるローカルのポート番号情報を見ることもできます。デフォルトのポート 22 番からポートを変更すると、自動化された認証試行によるログエントリ数が減るでしょう。しかし、そのような攻撃を排除することはできません。関連する情報は ポートノッキング を参照してください。
  • パスワードログインを完全に無効化することが推奨されます。そうすることで、セキュリティが格段に向上します。詳細は #公開鍵認証を強制する を参照してください。他の推奨されるセキュリティ手法については #保護 を参照してください。
  • 設定ファイル内に複数の Port port_number 行を記述することにより、OpenSSH に複数のポートをリッスンさせることができます。
  • 新しい (或いは存在しない) ホスト鍵ペアは、置き換えたいペアを /etc/ssh から削除し ssh-keygen -A を root として実行することで、生成することができます。

デーモンの管理

sshd.service起動/有効化してください。これは、SSH デーモンを永続的にアクティブ状態に保ち、各着信接続に対してフォークします。[1]

ノート: Systemd のソケットアクティベーションを使用する sshd.socket は、DOS (サービス拒否) の影響を受けやすいため、openssh 8.0p1-3 で削除されました。詳細は FS#62248 を参照してください。openssh 8.0p1-3 に更新する時に sshd.socket が有効化されていた場合、sshd.socketsshd@.service ユニットは /etc/systemd/system/ にコピーされ、再有効化されます。これは、既存のセットアップを破壊しないためだけに行われるのであって、ユーザは依然として sshd.service に移行することが推奨されます。
警告: sshd.socket の使用を継続するならば、このユニットの問題に注意してください:
  • sshd.socket ユニットは (例えばメモリ不足の状況などにより) 失敗する場合があり、Restart=always はソケットユニットに対しては指定できません。systemd issue 11553 を参照。
  • ソケットアクティベーションの使用は、接続が多すぎるとサービスのアクティブ化が拒否される可能性があるため、サービス拒否を引き起こす可能性があります。FS#62248 を参照。
ノート: sshd.socket を使用すると ListenAddress の設定が無効化され、任意のアドレスを介して接続できるようになってしまいます。ListenAddress の設定に効力を持たせるには、sshd.socket編集して、ポートと IP の両方ListenStream で設定しなければなりません (例: ListenStream=192.168.1.100:22)。また、[Socket] セクションに FreeBind=true も追加しなければなりません。さもないと、IP アドレスを設定した時に ListenAddress を指定した時と同じ欠点が生じます: ネットワークが時間内に立ち上がっていない場合、ソケットは起動に失敗します。
ヒント: ソケットアクティベーションを使用すると、各接続に対して sshd@.service の一時的なインスタンスが (異なるインスタンス名で) 開始されます。ゆえに、sshd.socket もデーモンの通常の sshd.service も、接続試行をログでモニタできません。ソケットアクティベートされた SSH インスタンスのログは、journalctl -u "sshd@*" を root として実行するか、journalctl /usr/bin/sshd を root として実行することで、確認することができます。

保護

SSH によるリモートログインを許可することは管理業務においては良いことですが、サーバーのセキュリティに脅威を及ぼすことにもなりえます。総当り攻撃の標的になりやすいので、SSH のアクセスは制限して、第三者がサーバーにアクセスできないようにする必要があります。

ssh-audit は、サーバとクライアントの設定の自動化された解析を提供します。このトピックに関して、いくつか他のガイドやツールが利用できます。例えば:

公開鍵認証を強制する

デフォルトでは、クライアントが公開鍵で認証できない場合、SSH サーバはパスワード認証にフォールバックします。なので、悪意のあるユーザがパスワードのブルートフォースによるアクセスを試みることができてしまいます。このような攻撃から保護する最も効果的な方法の1つが、パスワードログインを完全に無効化し、SSH 鍵の使用を強制することです。これは、デーモンの設定ファイルで以下のオプションを設定することで可能です:

/etc/ssh/sshd_config
PasswordAuthentication no
AuthenticationMethods publickey
警告: これを設定に追加する前に、SSH アクセスを必要とする全アカウントが、対応する authorized_keys ファイルで公開鍵認証をセットアップしていることを確認してください。詳細は SSH 鍵#リモートサーバーに公開鍵をコピー を参照してください。

二要素認証と公開鍵

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 によるレート制限シンプルなステートフルファイアウォール#ブルートフォース攻撃 を参照してください。

あるいは、fail2bansshguard などの自動スクリプトを使うことで攻撃者をブロックすることでブルートフォース攻撃から身を守ることができます。

  • 信頼された場所からの着信 SSH 接続のみを許可する。
  • fail2bansshguard を使用して、パスワード認証に失敗しすぎた IP アドレスを自動的にブロックする。
  • pam_shield を使用して、特定の時間内に多くのログイン試行を行った IP アドレスをブロックする。fail2bansshguard とは対照的に、このプログラムはアカウントへのログイン成功や失敗を考慮しません。

root ログインの制限

この記事またはセクションは情報が古くなっています。
理由: 現在のバージョンでは、root ログインは上流でデフォルトで無効化されています。 (Discuss)

一般的に、root ユーザが制限無しで SSH を介してログインできることはバッドプラクティスだと考えられています。セキュリティを向上させるために SSH の root アクセスを制限する方法は2つあります。

拒否

Sudo を使うことで、root アカウントの認証を行うことなく、必要に応じて root 権限を選択的に付与することができます。このため SSH による root ログインを拒否して、攻撃者にパスワードに加えて (root でない) ユーザー名も推測させる必要を生じさせることで、ブルートフォース攻撃を困難にすることが可能です。

デーモンの設定ファイルで "Authentication" セクションを編集することで SSH からの root ユーザのログインを拒否するように設定できます。PermitRootLoginno に設定してください:

/etc/ssh/sshd_config
PermitRootLogin no

次に、SSH デーモンを再起動してください。

これで、SSH を使って root でログインすることはできなくなります。ただし、通常ユーザーでログインしてから susudo を使ってシステム管理を行うことは依然として可能です。

制限

自動的な作業の中にも、リモートによるフルシステムバックアップなど、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 から変更不可のビットを削除して一時的に書き込み可能にする必要があります。

ヒント: auditd などを用いて、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 の設定を管理するユーティリティです (ソース)。

警告: X11 フォワーディングにはセキュリティ的に重要な問題があります。sshsshd_config、そして ssh_config のマニュアルページの該当するセクションを読んで最低限の知識をつけてください。この StackExchange の質問 も参照。

セットアップ

リモート側
  • xorg-xauth パッケージをインストールしてください
  • /etc/ssh/sshd_config 内で:
    • X11Forwardingyes に設定してください
    • AllowTcpForwardingX11UseLocalhost オプションが yes に設定されおり、X11DisplayOffset10 に設定されていることを確認してください (これらの設定は、何も変更していなければ、デフォルト値です。sshd_config(5) を参照)。
  • そして、sshd デーモンを再起動してください。
クライアント側
  • xorg-xauth パッケージをインストールしてください。
  • コマンドラインで日和見的な接続を行うための -X スイッチを指定するか、或いはクライアントの設定ForwardX11yes に設定して、ForwardX11 オプションを有効化してください。
ヒント: GUI の描画がおかしい場合やエラーが表示されるときは ForwardX11Trusted オプションを有効にできます (コマンドラインでは -Y スイッチ)。X11 フォワーディングが X11 SECURITY 拡張 の制御から外れるようになります。使用するときはセクション冒頭の警告を読んでください。

使用方法

通常通りリモートマシンにログオンしてください。クライアントの設定ファイルで 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_configAddressFamily any オプションを有効にする。
  • 或いは、サーバsshd_configAddressFamily オプションを inet に設定する。

IPv4 で Ubuntu クライアントを使っている場合は inet に設定することで問題が解決する場合があります。

SSH サーバーの他のユーザーで X アプリケーションを実行するには SSH でログインしているユーザーの xauth list の認証行を xauth add する必要があります。

ヒント: X11 Forwarding の問題をトラブルシューティングする有用なリンクをいくつか挙げます: [2][3][4]

他のポートのフォワーディング

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

アイデアとしては、クライアントは別のリレーを使ってサーバに接続し、サーバはリバース SSH トンネルを使って同じリレーに接続します。これは、サーバが NAT 内にあり、リレーが、ユーザがアクセス可能なプロキシとして使用されている、パブリックにアクセス可能な SSH サーバである場合に便利です。ゆえに、クライアントの鍵がリレーとサーバの両方に対して認可されていることが前提条件であり、サーバはリレーに対してもリバース SSH 接続に対しても認可されている必要があります。

以下の設定例では、user1 が client 上で使用されているユーザアカウントであり、user2 は relay 上のアカウント、user3 が server 上のアカウントであるとします。まず、以下のコマンドでサーバとリバーストンネルとの接続が確立している必要があります:

ssh -R 2222:localhost:22 -N user2@relay

これは、スタートアップスクリプトや systemd サービス、autossh を使って自動化することもできます。

クライアント側では、以下のコマンドで接続を確立させます:

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

注意点として、client の SCP の自動補完関数は機能せず、SCP 転送自体も特定の構成においては機能しません。

マルチプレクス

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.comaes256-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 を使用することを推奨します。sshfsshfs の新しいバージョンであり、元の shfs は2004年から更新されていません。

キープアライブ

デフォルトでは、SSH セッションが一定時間アイドルであった場合、自動的にログアウトします。一定時間データが受信されなかった場合にサーバにキープアライブシグナルを送信することで、セッションを開いたままにすることができます。あるいは対照的に、クライアントからデータが送られてこない場合にサーバが定期的にメッセージを送信することもできます。

  • サーバ側: ClientAliveInterval はタイムアウトを秒単位で設定します。クライアントからデータが受信されずにその時間経過すると、sshd が応答を促すリクエストを送信します。デフォルトは0であり、メッセージは送信されません。例えば、60秒毎にクライアントに対して応答を要求するには、サーバ側の設定ClientAliveInterval 60 オプションを設定してください。ClientAliveCountMaxTCPKeepAlive オプションも参照してください。
  • クライアント側: ServerAliveInterval は、クライアントからサーバに向けて送信されるリクエストの時間間隔を設定します。例えば、120秒毎にサーバに対して応答を要求するには、クライアント側の設定ServerAliveInterval 120 オプションを追加してください。ServerAliveCountMaxTCPKeepAlive オプションも参照してください。
ノート: セッションを開いたままにするためにキープアライブリクエストを送信する必要があるのは、クライアントかサーバの一方のみです。サーバとクライアントの両方を制御できるならば、セッションを永続的にする必要のあるクライアントに対してのみ ServerAliveInterval を正の値に設定し、その他のクライアントやサーバはデフォルトの設定するのが妥当な選択です。

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
ヒント: 複数のautosshプロセスを維持し、複数のトンネルを存続させることも簡単です。名前の異なる複数のサービスファイルを作成するだけです。

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 を介して見つけられない場合にのみ、適用されます。様々な代替案が [5] で議論されています。

Match host internal.example.com !exec "host internal.example.com"
  ProxyJump bastion.example.com
Host internal.example.com
  User foobar

プライベートネットワークのホスト鍵検証

あるネットワーク上のサーバとそれとは別のネットワーク上のサーバは、互いに同じプライベート IP アドレスを持つ可能性があるため、それらのサーバは異なる方法で処理する必要があるかもしれません。

この記事またはセクションの正確性には問題があります。
理由: 「最適な」ソリューションに、本番環境では別のものを使うべきという警告があるはずがない。 (議論: トーク:OpenSSH#)

最適なソリューションは、#ネットワーク固有の設定 を使用し、接続しているネットワークに応じて異なる 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
この記事またはセクションの正確性には問題があります。
理由: known_hosts ファイルは、サーバにアクセスするためにホスト名を使用したとしても、IP アドレスを記録します。 (議論: トーク:OpenSSH#)
警告: 本番環境では、ホスト名を使用してホストにアクセスしたり、ネットワーク固有の known_hosts ファイルを使用するようにしてください。

ログイン時にコマンドを実行

インタラクティブセッションを使用している場合、ログイン時にコマンドを実行する方法は複数存在します:

  • リモートホスト上の authorized_keys ファイルを使用する (sshd(8)AUTHORIZED_KEYS FILE FORMAT セクションを参照)
  • サーバで PermitUserRC オプションが有効化されている場合、リモートホスト上の ~/.ssh/rc を使用する
  • リモートホスト上のシェル設定ファイルを使用する (例: .bashrc)

エージェントフォワーディング

SSH エージェントのフォワーディングにより、サーバに接続している状態でローカルの鍵を使用することができます。選択したホストのみに対してエージェントフォワーディングを許可することが推奨されます。

~/.ssh/config
Host myserver.com
    ForwardAgent yes

次に、SSH エージェントを構成し、ssh-add を使ってローカル鍵を追加してください。

これで、リモートサーバに接続する場合、あなたのローカル鍵を使用して他のサービスに接続できるようになりました。

新しい鍵の生成

新しいサーバの秘密鍵は以下で生成できます:

  1. すべての鍵を削除する。例えば:
    # rm /etc/ssh/ssh_host_*_key*
  2. 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

トラブルシューティング

チェックリスト

以下は最初に行うべきトラブルシューティングのチェックリストです。何かする前に以下の問題をチェックすることを推奨します。

  1. 設定ディレクトリ ~/.ssh の中身がユーザーからアクセスできることを確認する (クライアントとサーバーの両方で確認してください):
    $ chmod 700 ~/.ssh
    $ chmod 600 ~/.ssh/*
    $ chown -R $USER ~/.ssh
    
  2. クライアントの公開鍵 (例: id_rsa.pub) がサーバーの ~/.ssh/authorized_keys に存在することを確認する。
  3. サーバーの設定AllowUsersAllowGroups によって SSH によるアクセスが制限されていることを確認する。
  4. ユーザーにパスワードが設定されていることを確認する。新しいユーザーにはパスワードが設定されていない可能性があります。
  5. 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 またはサードパーティによってデフォルトのポートがブロックされてないか?

ノート: このステップは次のことを確認した後で実行してください。ファイアーウォールを何も起動していないこと。DMZ へのルーターを正しく設定している、またはコンピュータへポートを転送していること。それでもまだ動かない場合、ここで診断のステップと解決法が見つかるでしょう。

ときどき 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 変数を設定する解決策

警告: この方法はあくまで次善策であり、たまにしか接続しない ssh サーバーで使うようにしてください。

.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 セッションプロセスや screentmux のプロセスが終了されることを防ぐことができます。

SSH セッションが応答しなくなる

SSH は Software flow control XONXOFF に反応します。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) で、0x00throughput (0x08) と同様に問題を解決できるはずです。

再起動後デーモンの起動が遅い

特にヘッドレスサーバや仮想化サーバにおいて、再起動後のデーモン起動時間が過度に長くなる場合(例:デーモンが接続を受け付け始めるまでに数分かかる)、エントロピー不足が原因かもしれません [7] これは、あなたのシステムに適した Rng-toolsHaveged をインストールすれば改善することが可能です。ただし、それぞれのパッケージの 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 に同梱されていない端末エミュレータを使用する場合などです。(例えば kittyrxvt-unicode) terminfo データベースが制限されているホスト (例えば OpenWrt が動いているシステム) に接続する場合、terminfo(5) に依存しているソフトウェアで様々な問題が発生する可能性があります。

適切な解決策は、適切な terminfo エントリをホストに設置することです。それが不可能な場合は、リモートホストがサポートし、かつ端末と互換性のある値を TERM に設定することで解決できます。

OpenSSH 8.7 以降、カスタムの TERM 環境変数をリモートホストに渡すには、 簡単な設定スニペットを使います。

~/.ssh/config
Host example.com
  SendEnv TERM=xterm-256color

参照