「OpenSSH」の版間の差分
(→サーバの使用: 追加) |
(同期) |
||
(同じ利用者による、間の13版が非表示) | |||
1行目: | 1行目: | ||
− | {{Translateme|飜訳および編集が必要です。英語版を参照してください。}} |
||
[[Category:Secure Shell]] |
[[Category:Secure Shell]] |
||
[[Category:サーバー]] |
[[Category:サーバー]] |
||
42行目: | 41行目: | ||
クライアントは、共通のオプションとホストを保存するように設定することができます。全プションは、グローバルに、あるいは特定のホストに制限して宣言することができます。例えば: |
クライアントは、共通のオプションとホストを保存するように設定することができます。全プションは、グローバルに、あるいは特定のホストに制限して宣言することができます。例えば: |
||
− | {{hc|~/.ssh/config|# |
+ | {{hc|~/.ssh/config|# グローバルなオプション |
User ''user'' |
User ''user'' |
||
220行目: | 219行目: | ||
PermitRootLogin prohibit-password |
PermitRootLogin prohibit-password |
||
− | ==== authorized_keys ファイルの |
+ | ==== authorized_keys ファイルのロック ==== |
{{Warning|このファイルをロックしても、ユーザの間違いや特定の単純な対人攻撃からの保護しかできません。この方法は、悪意のあるプログラムや侵入に対するあらゆる保護も提供'''しません'''。多要素認証、ファイアウォール、そして縦深防御を用いて、侵入を未然に防いでください。}} |
{{Warning|このファイルをロックしても、ユーザの間違いや特定の単純な対人攻撃からの保護しかできません。この方法は、悪意のあるプログラムや侵入に対するあらゆる保護も提供'''しません'''。多要素認証、ファイアウォール、そして縦深防御を用いて、侵入を未然に防いでください。}} |
||
234行目: | 233行目: | ||
{{Tip|[[Audit フレームワーク#ファイルとディレクトリへのアクセスを監査する|auditd]] などを用いて、{{ic|authorized_keys}} ファイルの変更を記録することが推奨されます。}} |
{{Tip|[[Audit フレームワーク#ファイルとディレクトリへのアクセスを監査する|auditd]] などを用いて、{{ic|authorized_keys}} ファイルの変更を記録することが推奨されます。}} |
||
− | == |
+ | ==== SSH 証明書 ==== |
− | OpenSSH (OpenBSD Secure Shell) は ssh プロトコルを使ってコンピューターネットワークを介して暗号化通信セッションを提供するコンピュータープログラムのセットです。SSH Communications Security によるプロプライエタリの Secure Shell ソフトウェアスイートに代わるオープンのプログラムとして作成されました。OpenSSH は Theo de Raadt に率いられている OpenBSD プロジェクトの一環として開発されています。 |
||
+ | 一般的な SSH 鍵と手動でのフィンガープリントの検証は、一人の管理者によって管理されている少数のホストにおいては簡単でしょうが、この認証方法は拡張性が全くありません。一定数のサーバをいくつかのユーザが SSH を通してアクセスする必要がある場合、全てのホストの SSH 公開鍵フィンガープリントを手動でセキュアかつ確実に検証するのは、ほぼ不可能です。 |
||
− | 同じような名前の OpenSSL と OpenSSH が混同されることがときどきありますが、プロジェクトの目的・開発チームは異なります。 |
||
+ | これに対する解決策は、SSH 証明書を使うことです。SSH 証明書を使えば、SSH のデフォルトの Trust On First Use アプローチよりも拡張性の高い信用の鎖によって、公開鍵の正当性を自動で検証できます。SSH 証明書は、基本的には通常の SSH 公開鍵ですが、信頼されている認証局からの署名が付け加えられおり、これにより鍵の正当性を検証します。 |
||
− | === OpenSSH のインストール === |
||
− | [[公式リポジトリ]]から {{Pkg|openssh}} を[[pacman|インストール]]してください。 |
||
+ | ===== インフラストラクチャ用のホスト認証局の鍵を作成する ===== |
||
− | === SSH の設定 === |
||
− | ====クライアント==== |
||
− | SSH クライアントの設定ファイルは {{ic|/etc/ssh/ssh_config}} もしくは {{ic|~/.ssh/config}} です。 |
||
+ | $ ssh-keygen -t ed25519 -f ~/.ssh/ca_host_key -C 'Host certificate authority for *.example.com' |
||
− | {{ic|Protocol 2}} を明示的に設定する必要はありません。デフォルトの設定ファイルではコメントアウトされています。つまり明示的に有効にされない限り {{ic|Protocol 1}} は使われません。 (ソース: http://www.openssh.org/txt/release-5.4) |
||
+ | 認証局の秘密鍵はセキュアに保存されているべきです。鍵の抽出を防止する機構が備わっている [[Nitrokey]] や [[YubiKey]] といったスマートカードやハードウェアトークン上に保存するのが理想です。 |
||
− | ====デーモン==== |
||
− | SSH デーモンの設定ファイルは {{ic|/etc/ssh/ssh'''d'''_config}} です。 |
||
+ | ===== サーバの SSH ホスト公開鍵を署名する ===== |
||
− | 特定のユーザーにだけアクセスを許可するには次の行を追加してください: |
||
− | AllowUsers ''user1 user2'' |
||
+ | サーバの公開鍵を、認証局の秘密鍵が保存されているローカルのシステムにコピーし、サーバの公開鍵を署名してください: |
||
− | 特定のグループにだけアクセスを許可するには: |
||
− | AllowGroups ''group1 group2'' |
||
+ | $ ssh-keygen -h -s ~/.ssh/ca_key -I certLabel -n server01.example.com ./ssh_host_ed25519_key.pub |
||
− | SSH による root ログインを無効にするには、PermitRootLogin 行を次のように変更してください: |
||
− | PermitRootLogin no |
||
+ | ===== 新しい証明書を移動し、sshd にそれを使わせる ===== |
||
− | {{Note|1=バージョン 7.0p1 からは {{ic|PermitRootLogin prohibit-password}} がデフォルトになっています。{{ic|man sshd_config}} を参照。}} |
||
+ | 生成された証明書 {{ic|ssh_host_ed25519_key-cert.pub}} は、サーバの {{ic|/etc/ssh/}} にコピーする必要があります。 |
||
− | ウェルカムメッセージを追加するには {{ic|/etc/issue}} ファイルを編集して {{ic|Banner}} 行を次のように変更してください: |
||
− | Banner /etc/issue |
||
− | |||
− | ホスト鍵は sshd の systemd サービスによって自動的に生成されます。sshd に特定の鍵を使用させたい場合、手動で設定します: |
||
− | HostKey /etc/ssh/ssh_host_rsa_key |
||
− | |||
− | サーバーに WAN からアクセスできる場合、デフォルトのポートである 22 から別のランダムなポートに変更することが推奨されています: |
||
− | Port 39901 |
||
− | |||
− | {{Note|OpenSSH では設定ファイルに ''Port x'' 行を複数記述することで複数のポートを使うことができます。}} |
||
− | |||
− | パスワードによるログインを使わないようにすればセキュリティは大幅に向上します。詳しくは [[SSH 鍵#パスワードログインの無効化]] を見て下さい。 |
||
− | |||
− | === sshd デーモンの管理 === |
||
− | 次のコマンドで sshd デーモンを起動することができます: |
||
− | # systemctl start sshd.service |
||
− | |||
− | 次のコマンドで sshd デーモンを起動時に有効にすることができます: |
||
− | # systemctl enable sshd.service |
||
− | |||
− | 詳しくは [[systemd#ユニットを使う]] を見て下さい。 |
||
− | |||
− | {{Warning|Systemd は非同期にプロセスを実行します。SSH デーモンを特定の IP アドレス {{ic|ListenAddress 192.168.1.100}} に結びつけている場合、デフォルトの sshd.service ユニットファイルはネットワークインターフェイスが有効にされることに依存していないため、ブート中にロードが失敗する可能性があります。IP アドレスをバインドする時は、カスタムした sshd.service ユニットファイルに {{ic|1=After=network.target}} を追加してください。[[systemd#ユニットファイルの編集]] を参照。}} |
||
− | |||
− | また SSH デーモンソケットを有効にすることで初めて接続があったときにデーモンが起動するようにすることもできます: |
||
− | # systemctl start sshd.socket |
||
− | # systemctl enable sshd.socket |
||
− | デフォルトの22番以外のポートを使う場合、ユニットファイルを[[systemd#ユニットファイルの編集|編集]]する必要があります: |
||
− | {{hc|# systemctl edit sshd.socket|<nowiki> |
||
− | [Socket] |
||
− | ListenStream= |
||
− | ListenStream=12345 |
||
− | </nowiki>}} |
||
− | |||
− | {{Warning|{{ic|sshd.socket}} を使用すると {{ic|ListenAddress}} の設定が打ち消されて、どのアドレスからでも接続できるようになってしまいます。{{ic|ListenAddress}} の設定を適用するには、{{ic|ListenStream}} でポートと IP を指定する必要があります (例: {{ic|1=ListenStream=192.168.1.100:22}})。また、{{ic|[Socket]}} の下に {{ic|1=FreeBind=true}} を追加するようにしてください。そうしないと IP アドレスの設定が {{ic|ListenAddress}} の設定と同じように無効になってしまいます: ネットワークが立ち上がっていない場合にソケットの起動が失敗します。}} |
||
− | |||
− | {{Tip|ソケットアクティベーションを使う場合、{{ic|sshd.socket}} でもデーモンの標準の {{ic|sshd.service}} でもログの接続試行を監視することはできません。ただし {{ic|# journalctl /usr/bin/sshd}} を実行することで監視できます。}} |
||
− | |||
− | === サーバーに接続する === |
||
− | サーバーに接続するには、次を実行してください: |
||
− | $ ssh -p ''port'' ''user''@''server-address'' |
||
− | |||
− | === SSH の保護 === |
||
− | 管理業務のために SSH によるリモートログインを許可することは良いことですが、サーバーのセキュリティに脅威を及ぼすことにもなりえます。総当り攻撃の標的になりやすいので、SSH のアクセスは制限して、第三者がサーバーにアクセスできないようにする必要があります。 |
||
− | * わかりにくいアカウント名やパスワードを使う |
||
− | * 信頼できる国からの SSH 接続だけを許可する |
||
− | * [[fail2ban]] や [[sshguard]] をつかってブルートフォース攻撃を監視し、総当りを起こっている IP を閉め出す |
||
− | |||
− | ==== ブルートフォースアタックからの保護 ==== |
||
− | ブルートフォースは単純な攻撃方法です: ランダムなユーザー名とパスワードの組み合わせをとにかく沢山作ってウェブページや SSH などのサーバーログインプロンプトにログインを絶えず試行します。ブルートフォース攻撃からは [[fail2ban]] や [[sshguard]] などの自動スクリプトを使うことで攻撃者をブロックすることで身を守ることができます。[[Uncomplicated Firewall#ufw によるレート制限]]も参照。 |
||
− | |||
− | もしくは、公開鍵認証を使うことでブルートフォース攻撃を出来なくすることもできます。{{ic|sshd_config}} に次の設定を追加: |
||
− | |||
− | PasswordAuthentication no |
||
− | ChallengeResponseAuthentication no |
||
− | |||
− | 上の設定を適用する前に、SSH アクセスが必要な全てのアカウントで {{ic|authorized_keys}} ファイルに公開鍵認証の設定をするようにしてください。詳しくは [[SSH 鍵#リモートサーバーに公開鍵をコピー]] を参照。 |
||
− | |||
− | ==== 2段階認証 ==== |
||
− | |||
− | SSH 鍵のペアによる認証を使用していてパスワードによろうログインを無効化している場合に、2段階認証を使いたいときは [[Google Authenticator]] や [[SSH 鍵#2段階認証と公開鍵]] を見て下さい。 |
||
− | |||
− | ==== root ログインを制限する ==== |
||
− | 一般的に、SSH で無制限に root ログインを許可することは推奨されません。セキュリティの向上のために、SSH での root ログインを制限する方法は2つ存在します。 |
||
− | |||
− | ===== root ログインを拒否する ===== |
||
− | |||
− | Sudo を使うことで、root アカウントの認証を行うことなく、必要に応じて root 権限を選択的に付与することができます。このため SSH による root ログインを拒否して、攻撃者にパスワードに加えて (root でない) ユーザー名も推測させる必要を生じさせることで、ブルートフォース攻撃を困難にすることが可能です。 |
||
− | |||
− | {{ic|/etc/ssh/sshd_config}} の "Authentication" セクションを編集することで SSH からの root ログインを拒否するように設定できます。{{ic|#PermitRootLogin prohibit-password}} を {{ic|no}} に変更して行をアンコメントしてください: |
||
{{hc|/etc/ssh/sshd_config| |
{{hc|/etc/ssh/sshd_config| |
||
+ | HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub |
||
− | PermitRootLogin no |
||
− | ... |
||
}} |
}} |
||
+ | ===== 認証局を信頼するように全てのクライアントを設定する ===== |
||
− | そして、SSH デーモンを[[再起動]]してください。 |
||
+ | {{hc|~/.ssh/known_hosts| |
||
− | これで、SSH を使って root でログインすることはできなくなります。ただし、通常ユーザーでログインしてから [[su]] や [[sudo]] を使ってシステム管理を行うことは依然として可能です。 |
||
+ | @cert-authority *.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKL8gB/pjuff005YNazwMCqJpgsXAbQ3r4VStd/CRKwU Host certificate authority for *.example.com |
||
+ | }} |
||
+ | {{Warning|サーバが識別用の証明書を提供しないと、デフォルトで公開鍵認証がフォールバックとして使用されてしまいます。}} |
||
− | ===== root ログインを限定する ===== |
||
− | 自動的な作業の中にも、リモートによるフルシステムバックアップなど、root 権限を必要とするものがあります。セキュアな方法で root を許可したい場合、SSH による root ログインを無効化する代わりに、特定のコマンドだけ root ログインを許可することができます。{{ic|~root/.ssh/authorized_keys}} を編集して、以下のように特定のキーの前にコマンドを記述します: |
||
+ | ===== SSH ユーザ証明書 ===== |
||
− | command="/usr/lib/rsync/rrsync -ro /" ssh-rsa … |
||
+ | ユーザの数やデプロイ方法にもよりますが、SSH ユーザ鍵を証明書と共に使用することもできます。多くの ssh ユーザが存在する組織では、この方法でユーザ鍵のデプロイをセキュアに管理することが強く推奨されます。 |
||
− | 上記の設定で、特定の鍵を使ってログインした場合はクォートで囲ったコマンドを実行できるようになります。 |
||
+ | ユーザ証明書のデプロイは、基本的にはサーバの ID と同じように機能します。詳細と方法については [[Wikibooks:OpenSSH/Cookbook/Certificate-based Authentication]] で見られます。 |
||
− | ログイン時に root ユーザーの名前を出すことで攻撃する対象が増えてしまうことに対しては {{ic|sshd_config}} に以下を追加することで埋め合わせができます: |
||
+ | ===== 証明書のデプロイを自動化する ===== |
||
− | PermitRootLogin forced-commands-only |
||
+ | 多くのオープンソースなツールによって、SSH 証明書のデプロイを自動化する方法が提供されています。人気なものとしては例えば以下があります: |
||
− | 上記の設定は root が SSH で実行できるコマンドを制限するだけでなく、パスワードの使用も無効化して、root アカウントでは強制的に公開鍵認証を使うようになります。 |
||
+ | * [https://docs.ansible.com/ansible/latest/collections/community/crypto/openssh_cert_module.html Ansible - openssh_cert module] |
||
− | root で使えるコマンドは制限しないで公開鍵認証の強制だけをするという手もあり、それでもブルートフォース攻撃はほぼ不可能です。その場合、以下を設定: |
||
+ | * [https://www.privacyidea.org/ privacyIDEA - 認証サーバ] |
||
+ | * [https://theoapp.readthedocs.io/en/latest/ Theo App - 認可された鍵のマネージャ] |
||
+ | == ヒントとテクニック == |
||
− | PermitRootLogin without-password |
||
+ | === 暗号化 SOCKS トンネル === |
||
− | == 他の SSH クライアントとサーバー == |
||
− | OpenSSH の他にも、多数の SSH [[Wikipedia:Comparison of SSH clients|クライアント]] と[[Wikipedia:Comparison of SSH servers|サーバー]]が存在します。 |
||
+ | 暗号化トンネルは、安全でない様々なワイヤレス接続を使用するノートパソコンユーザにとって非常に有用です。必要なのは SSH サーバーが安全な場所 (家や仕事場など) で動作していることだけです。[https://dyn.com/dns/ DynDNS] などのダイナミック DNS サービスを利用すれば IP アドレスを覚える必要もありません。 |
||
− | === Dropbear === |
||
− | [[Wikipedia:Dropbear (software)|Dropbear]] は SSH-2 クライアント・サーバーです。{{Pkg|dropbear}} は[[公式リポジトリ]]から利用可能です。 |
||
+ | ==== 手順 1: 接続の開始 ==== |
||
− | コマンドラインの ssh クライアントは dbclient という名前が付けられています。 |
||
+ | 以下のコマンドを実行するだけで接続を開始できます: |
||
− | === Mosh === |
||
− | Mosh の [http://mosh.mit.edu/ ウェブサイト] より: |
||
+ | $ ssh -TND 4711 ''user''@''host'' |
||
− | ローミングが可能で、断続的な接続もサポートしているリモート端末アプリケーションです。ユーザーのキーストロークのローカルエコーと行編集を提供します。Mosh は SSH の代替です。SSH よりも強固でレスポンスが早く、特に Wi-Fi や携帯端末からの接続、長距離通信など通信速度が遅い場合に役に立ちます。 |
||
+ | {{Ic|''user''}} はユーザー名に、{{Ic|''host''}} は SSH サーバーが動作しているホストに置き換えてください。パスワードを入力すると接続が行われます。{{Ic|N}} フラグはインタラクティブプロンプトを無効化し、{{Ic|D}} フラグは listen するローカルポートを指定します (ポート番号は何でもかまいません)。{{Ic|T}} フラグは疑似 tty アロケーションを無効化します。 |
||
− | [[公式リポジトリ]]から {{Pkg|mosh}} を[[pacman|インストール]]するか [[Arch User Repository|AUR]] にある最新版 {{AUR|mosh-git}} を使って下さい。 |
||
− | |||
− | Mosh にはドキュメントに記載されていないコマンドラインオプション {{ic|1=--predict=experimental}} が存在し、よりアグレッシブにローカルのキーストロークのエコーを生成します。キーボード入力が遅延なく確認できるのに興味があるのであればこの prediction モードを使ってみて下さい。 |
||
− | |||
− | == ヒントとテクニック == |
||
− | |||
− | === 暗号化 SOCKS トンネル === |
||
− | 暗号化トンネルは信頼ができない様々なワイヤレス接続を使用するノートパソコンなどで非常に有用です。必要なのは SSH サーバーが安全な場所 (家や仕事場など) で動作していることだけです。[http://www.dyndns.org/ DynDNS] などのダイナミック DNS サービスを利用すれば IP アドレスを覚える必要もありません。 |
||
− | |||
− | ==== 手順 1: 接続の開始 ==== |
||
− | 以下のコマンドを実行することで接続を開始できます: |
||
− | $ ssh -TND 4711 ''user''@''host'' |
||
− | {{Ic|''user''}} はユーザー名に {{Ic|''host''}} は SSH サーバーが動作しているホストに置き換えてください。パスワードを入力すると接続が行われます。{{Ic|N}} フラグはインタラクティブプロンプトを無効化し、{{Ic|D}} フラグは listen するローカルポートを指定します (ポート番号は何でもかまいません)。{{Ic|T}} フラグは疑似 tty アロケーションを無効化します。 |
||
verbose ({{Ic|-v}}) フラグを追加することで、接続が成功していることを出力から確認することができます。 |
verbose ({{Ic|-v}}) フラグを追加することで、接続が成功していることを出力から確認することができます。 |
||
− | ==== 手順 2: ブラウザ ( |
+ | ==== 手順 2 (やり方 A): ブラウザ (或いはその他のプログラム) の設定 ==== |
− | 新しく作成した socks トンネルを使用するようにウェブブラウザ (や他のプログラム) を設定しないと上記の作業は無意味です。最新バージョンの SSH は SOCKS4 と SOCKS5 に対応しているため、どちらかを使うことができます。 |
||
+ | 新しく作成した SOCKS トンネルを使用するようにウェブブラウザ (や他のプログラム) を設定しないと上記の作業は無意味です。SSH は現在 SOCKS v4 と SOCKS v5 の両方をサポートしているため、使用するのはどちらでも構いません。 |
||
− | * Firefox の場合: ''編集 → 設定 → 詳細 → ネットワーク → 接続 → 接続設定'': |
||
− | : ラジオボタンの''手動でプロキシを設定する''にチェックを入れて、''SOCKS ホスト''テキストフィールドに {{ic|localhost}} と、次のテキストフィールドにポート番号を入力してください (上の例では {{ic|4711}})。 |
||
+ | * Firefox の場合: ''設定 > 一般'' を開き、ページ下部に移動し、ネットワーク設定の右にある ''接続設定...'' をクリックしてください。次に、セミウィンドウ内で、''手動でプロキシを設定する'' オプションにチェックを入れ、''SOCKS ホスト'' テキストフィールドに {{ic|localhost}} と入力し、''ポート'' テキストフィールドには SSH のポート番号 (上記の例では {{ic|4711}}) を入力してください。 |
||
− | Firefox はデフォルトでは DNS リクエストの作成に socks トンネルを使用しません。以下の手順で設定することでプライバシーを守ることができます: |
||
+ | : Firefox は自動的に SOCKS トンネルを介して DNS リクエストを行いません。この潜在的なプライバシーの問題は、インターネット接続の設定画面を更にスクロールし、''SOCKS v5 を使用するときは DNS もプロキシーを使用する'' にチェックを入れることで、軽減することができます。明らかに、この方法は SOCKS v4 ではなく SOCKS v5 を選んだ場合にしか適用できません。 |
||
+ | : これらの設定をアクティブ化するために Firefox を再起動してください。 |
||
+ | * Chromium の場合: SOCKS の設定を環境変数かコマンドラインオプションとして設定できます。以下の関数のうち1つを {{ic|.bashrc}} に追加することをおすすめします: |
||
− | # Firefox のロケーションバーに about:config と入力。 |
||
− | # network.proxy.socks_remote_dns を検索。 |
||
− | # 値を true に設定。 |
||
− | # ブラウザを再起動。 |
||
− | * Chromium の場合: 環境変数やコマンドラインオプションで SOCKS の設定ができます。以下の関数を {{ic|.bashrc}} に追加することを推奨します: |
||
function secure_chromium { |
function secure_chromium { |
||
port=4711 |
port=4711 |
||
409行目: | 314行目: | ||
exit |
exit |
||
} |
} |
||
+ | |||
− | もしくは: |
||
+ | あるいは |
||
+ | |||
function secure_chromium { |
function secure_chromium { |
||
port=4711 |
port=4711 |
||
416行目: | 323行目: | ||
} |
} |
||
− | ターミナル |
+ | そして、ターミナルを開いて、以下を実行してください: |
+ | |||
$ secure_chromium |
$ secure_chromium |
||
+ | |||
+ | セキュアトンネルを楽しみましょう! |
||
+ | |||
+ | ==== 手順 2 (やり方 B): ローカルの TUN インターフェイスをセットアップする ==== |
||
+ | |||
+ | このやり方は若干複雑ですが、SOCKS プロキシを使用するためにアプリケーションを1つずつ手動で設定する必要が無くなります。この方法には、ローカル TUN インターフェイスのセットアップと、そのインターフェイスを介したトラフィックのルーティングが含まれます。 |
||
+ | |||
+ | [[VPN over SSH#badvpn とトンネルインターフェイスをセットアップする]] を見てください。 |
||
=== X11 フォワーディング === |
=== X11 フォワーディング === |
||
− | X11 フォワーディングはリモートシステムで X11 プログラムを動作させて、グラフィカルインターフェイスをローカルのクライアントマシンで表示させるメカニズムです。X11 フォワーディングではリモートホストに X11 システムを完全にインストールさせる必要はなく、''xauth'' をインストールするだけで十分です。''xauth'' は |
+ | X11 フォワーディングは、リモートシステムで X11 プログラムを動作させて、グラフィカルインターフェイスをローカルのクライアントマシンで表示させるメカニズムです。X11 フォワーディングではリモートホストに X11 システムを完全にインストールさせる必要はなく、''xauth'' をインストールするだけで十分です。''xauth'' は、X11 セッションの認証を行うために必要なサーバーとクライアントによって使用される {{ic|Xauthority}} の設定を管理するユーティリティです ([http://xmodulo.com/2012/11/how-to-enable-x11-forwarding-using-ssh.html ソース])。 |
− | {{Warning|X11 フォワーディングにはセキュリティ的に重要な問題があります。{{ic|ssh}} |
+ | {{Warning|X11 フォワーディングにはセキュリティ的に重要な問題があります。{{ic|ssh}}、{{ic|sshd_config}}、そして {{ic|ssh_config}} のマニュアルページの該当するセクションを読んで最低限の知識をつけてください。[https://security.stackexchange.com/questions/14815/security-concerns-with-x11-forwarding この StackExchange の質問] も参照。}} |
==== セットアップ ==== |
==== セットアップ ==== |
||
429行目: | 345行目: | ||
===== リモート側 ===== |
===== リモート側 ===== |
||
− | * |
+ | * {{Pkg|xorg-xauth}} パッケージを[[インストール]]してください |
− | *{{ic|/etc/ssh/ssh'''d'''_config}} 内: |
+ | * {{ic|/etc/ssh/ssh'''d'''_config}} 内で: |
+ | ** {{ic|X11Forwarding}} を ''yes'' に設定してください |
||
− | **{{ic|AllowTcpForwarding}} と {{ic|X11UseLocalhost}} オプションを ''yes'' に設定し、{{ic|X11DisplayOffset}} を ''10'' に設定 (何も変更を加えてなければこの値がデフォルトになっています、{{ic|man sshd_config}} を参照) |
||
+ | ** {{ic|AllowTcpForwarding}} と {{ic|X11UseLocalhost}} オプションが ''yes'' に設定されおり、{{ic|X11DisplayOffset}} が ''10'' に設定されていることを確認してください (これらの設定は、何も変更していなければ、デフォルト値です。{{man|5|sshd_config}} を参照)。 |
||
− | **{{ic|X11Forwarding}} を ''yes'' に設定 |
||
− | * [[# |
+ | * そして、[[#デーモンの管理|''sshd'' デーモン]]を再起動してください。 |
===== クライアント側 ===== |
===== クライアント側 ===== |
||
+ | * {{Pkg|xorg-xauth}} パッケージを[[インストール]]してください。 |
||
− | クライアント側では、接続するたびにコマンドラインで {{ic|-X}} スイッチを指定して {{ic|ForwardX11}} オプションを有効にするか、[[#クライアント|openSSH クライアントの設定ファイル]]で {{ic|ForwardX11}} を ''yes'' に設定してください。 |
||
+ | * コマンドラインで日和見的な接続を行うための {{ic|-X}} スイッチを指定するか、或いは[[#設定|クライアントの設定]]で {{ic|ForwardX11}} を ''yes'' に設定して、{{ic|ForwardX11}} オプションを有効化してください。 |
||
{{Tip|GUI の描画がおかしい場合やエラーが表示されるときは {{ic|ForwardX11Trusted}} オプションを有効にできます (コマンドラインでは {{ic|-Y}} スイッチ)。X11 フォワーディングが [https://www.x.org/wiki/Development/Documentation/Security/ X11 SECURITY 拡張] の制御から外れるようになります。使用するときはセクション冒頭の[[#X11 フォワーディング|警告]]を読んでください。}} |
{{Tip|GUI の描画がおかしい場合やエラーが表示されるときは {{ic|ForwardX11Trusted}} オプションを有効にできます (コマンドラインでは {{ic|-Y}} スイッチ)。X11 フォワーディングが [https://www.x.org/wiki/Development/Documentation/Security/ X11 SECURITY 拡張] の制御から外れるようになります。使用するときはセクション冒頭の[[#X11 フォワーディング|警告]]を読んでください。}} |
||
443行目: | 360行目: | ||
==== 使用方法 ==== |
==== 使用方法 ==== |
||
− | 通常通り |
+ | 通常通りリモートマシンにログオンしてください。クライアントの設定ファイルで ''ForwardX11'' が有効化されていない場合は {{ic|-X}} スイッチを指定してください: |
+ | |||
$ ssh -X ''user@host'' |
$ ssh -X ''user@host'' |
||
+ | |||
− | グラフィカルなアプリケーションを実行しようとするとエラーが表示される場合、代わりに ''ForwardX11Trusted'' を試してみて下さい: |
||
+ | グラフィカルアプリケーションを実行しようとしてエラーが発生する場合は、代わりに ''ForwardX11Trusted'' を試してください: |
||
+ | |||
$ ssh -Y ''user@host'' |
$ ssh -Y ''user@host'' |
||
− | リモートサーバーで X プログラムが起動できるようになったら、出力がローカルセッションに転送されます: |
||
− | $ xclock |
||
+ | {{ic|X11 forwarding request failed}} と出力される場合、リモートマシンでセットアップをやり直してください。X11 フォワーディングのリクエストが成功したら、リモートサーバ上の任意の X プログラムを実行でき、プログラムがローカルセッションにフォワーディングされます: |
||
− | "Cannot open display" エラーが表示される場合、root 以外のユーザーで以下のコマンドを実行してみてください: |
||
− | $ xhost + |
||
+ | $ xclock |
||
− | 上記のコマンドは全てのユーザーに X11 アプリケーションの転送を許可します。特定のホストだけに転送を制限するには: |
||
− | $ xhost +hostname |
||
+ | {{ic|Can't open display}} という内容が含まれるエラーが出力される場合は、{{ic|DISPLAY}} が適切に設定されていないことを意味します。 |
||
− | hostname は転送先のホストの名前に置き換えてください。詳しくは {{ic|man xhost}} を参照。 |
||
+ | |||
+ | 一部のアプリケーションは、実行中のインスタンスのチェックをローカルのマシンで行うため、注意してください。[[Firefox]] がその例です: すでに実行中の Firefox を閉じるか、以下の起動パラメータを使用してリモートインスタンスをローカルマシン上で起動してください: |
||
− | 特定のアプリケーションではローカルマシンでインスタンスが動作しているかチェックが実行されます。例えば [[Firefox]] は以下の起動パラメータを使用してローカルマシンでリモートインスタンスを起動する必要があります: |
||
$ firefox --no-remote |
$ firefox --no-remote |
||
接続時に "X11 forwarding request failed on channel 0" と表示される場合 (サーバーの {{ic|/var/log/errors.log}} に "Failed to allocate internet-domain X11 display socket" と出力される場合)、{{Pkg|xorg-xauth}} パッケージがインストールされていることを確認してください。上手く機能しない場合、以下の設定を試してみてください: |
接続時に "X11 forwarding request failed on channel 0" と表示される場合 (サーバーの {{ic|/var/log/errors.log}} に "Failed to allocate internet-domain X11 display socket" と出力される場合)、{{Pkg|xorg-xauth}} パッケージがインストールされていることを確認してください。上手く機能しない場合、以下の設定を試してみてください: |
||
− | * サーバ |
+ | * ''サーバ''の {{ic|ssh'''d'''_config}} で {{ic|AddressFamily any}} オプションを有効にする。 |
− | * サーバ |
+ | * 或いは、''サーバ''の {{ic|ssh'''d'''_config}} で {{ic|AddressFamily}} オプションを inet に設定する。 |
− | IPv4 で Ubuntu クライアントを使っている場合は inet に設定することで問題が解決 |
+ | IPv4 で Ubuntu クライアントを使っている場合は inet に設定することで問題が解決する場合があります。 |
SSH サーバーの他のユーザーで X アプリケーションを実行するには SSH でログインしているユーザーの {{Ic|xauth list}} の認証行を {{Ic|xauth add}} する必要があります。 |
SSH サーバーの他のユーザーで X アプリケーションを実行するには SSH でログインしているユーザーの {{Ic|xauth list}} の認証行を {{Ic|xauth add}} する必要があります。 |
||
+ | |||
+ | {{Tip|{{ic|X11 Forwarding}} の問題をトラブルシューティングする有用なリンクをいくつか挙げます: [https://unix.stackexchange.com/a/12772]、[https://unix.stackexchange.com/a/46748]、[https://superuser.com/a/805060]。}} |
||
=== 他のポートのフォワーディング === |
=== 他のポートのフォワーディング === |
||
− | SSH は X11 をサポートしているだけでなく、TCP 接続のセキュアなトンネル化に使用することもできます。ローカルフォワーディングとリモートフォワーディングの両方が使えます。 |
||
+ | SSH の X11 の組み込みサポートに加えて、SSH には任意の TCP 接続をセキュアにトンネル化することもできます。ローカルフォワーディングとリモートフォワーディングの両方が使えます。 |
||
− | ローカルフォワーディングはローカルマシンのポートを開いて、リモートホストに接続が転送されます。転送先をリモートホストと同じにすることで、同一マシンでセキュアな VNC 接続などができます。ローカルフォワーディングは {{Ic|-L}} スイッチで利用することができ {{Ic|<tunnel port>:<destination address>:<destination port>}} という形式で転送先を指定します: |
||
+ | |||
+ | ローカルフォワーディングはローカルマシンのポートを開き、ローカルマシンに対する接続はリモートホストにフォワーディングされ、リモートホストから指定された宛先に転送されます。転送先をリモートホストと同じにすることで、同一マシンに対してセキュアシェルやセキュアな [[VNC]] 接続を提供します。ローカルフォワーディングは {{Ic|-L}} スイッチで利用することができ {{Ic|<トンネルポート>:<宛先アドレス>:<宛先ポート>}} という形式で転送先を指定します。 |
||
+ | |||
+ | ゆえに: |
||
$ ssh -L 1000:mail.google.com:25 192.168.0.100 |
$ ssh -L 1000:mail.google.com:25 192.168.0.100 |
||
− | 上記のコマンドは SSH で 192.168.0.100 にログインしてシェルを開き |
+ | 上記のコマンドは SSH で {{ic|192.168.0.100}} にログインしてシェルを開き、ローカルマシンの TCP ポート 1000 から mail.google.com のポート 25 へのトンネルが作成されます。接続が確立すると {{ic|localhost:1000}} への通信は Gmail の SMTP ポートに接続されます。Google から見ると、{{ic|192.168.0.100}} から接続が来ているように見えます (必ずしも接続と一緒にデータが運ばれるとは限りません)。データはローカルマシンと {{ic|192.168.0.100}} との間でセキュアに運ばれますが、{{ic|192.168.0.100}} と Google との間はセキュアではありません (他の方法を取らない限り)。 |
+ | 似たように: |
||
− | 同じように以下のコマンドは localhost:2000 に接続することができ、リモートホストのポート 6001 に透過的に送信されます: |
||
$ ssh -L 2000:192.168.0.100:6001 192.168.0.100 |
$ ssh -L 2000:192.168.0.100:6001 192.168.0.100 |
||
+ | このコマンドは、{{ic|localhost:2000}} に接続することができ、リモートホストのポート 6001 へ透過的に送信されます。前者の例は、vncserver ユーティリティ ([[tightvnc]] パッケージの一部) を使用して VNC 接続を行う際に便利です。便利とはいえ、セキュリティの問題があります。 |
||
− | 前者の例はセキュリティ上問題がある ({{AUR|tightvnc}} パッケージに含まれている) vncserver ユーティリティによる VNC 接続などで有用です。 |
||
+ | |||
+ | リモートフォワーディングは SSH トンネルとローカルマシンを通してリモートホストから任意のホストに接続できるようにします。ローカルフォワーディングとは逆の機能であり、ファイアウォールによってリモートホストの接続が限られている場合などに有用です。リモートフォワーディングは {{Ic|-R}} スイッチで使うことができ {{Ic|<トンネルポート>:<宛先アドレス>:<宛先ポート>}} という形式で転送先を指定します。 |
||
+ | ゆえに: |
||
− | リモートフォワーディングは SSH トンネルとローカルマシンを通してリモートホストから任意のホストに接続できるようにします。ローカルフォワーディングとは逆の機能であり、ファイアウォールによってリモートホストの接続が限られている場合などに有用です。リモートフォワーディングは {{Ic|-R}} スイッチで使うことができ {{Ic|<tunnel port>:<destination address>:<destination port>}} という形式で転送先を指定します: |
||
− | $ ssh -R 3000:irc. |
+ | $ 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 プログラムを利用することができるようになります。 |
+ | 上記のコマンドは {{ic|192.168.0.200}} にシェルを立ち上げて、{{ic|192.168.0.200}} からローカルホストの 3000 番ポートへの接続をトンネルを通して送信し、それから irc.freenode.net のポート 6667 に転送します。ポート 6667 がブロックされている場合でもリモートホストから IRC プログラムを利用することができるようになります。 |
ローカルフォワーディングとリモートフォワーディングはどちらもセキュアなゲートウェイとして使用することができます。{{Ic|<tunnel address>:<tunnel port>:<destination address>:<destination port>}} のようにバインドアドレスをつかうことで、SSH や SSH デーモンを動かしていなくても他のコンピュータが SSH トンネルを利用することが可能です。{{Ic|<tunnel address>}} はトンネルの入り口となるマシンのアドレスです: {{Ic|localhost}}, {{Ic|*}} (あるいは空)。特定のアドレス経由の接続、ループバックインターフェイス経由の接続、全てのインターフェイス経由の接続を許可します。デフォルトでは、フォワーディングはトンネルの入り口のマシンからの接続だけに制限されており {{Ic|<tunnel address>}} は {{Ic|localhost}} に設定されています。ローカルフォワーディングは特に設定が必要ありませんが、リモートフォワーディングはリモートサーバーの SSH デーモンの設定によって制限を受けます。詳しくは {{Ic|sshd_config(5)}} の {{Ic|GatewayPorts}} オプションを見てください。 |
ローカルフォワーディングとリモートフォワーディングはどちらもセキュアなゲートウェイとして使用することができます。{{Ic|<tunnel address>:<tunnel port>:<destination address>:<destination port>}} のようにバインドアドレスをつかうことで、SSH や SSH デーモンを動かしていなくても他のコンピュータが SSH トンネルを利用することが可能です。{{Ic|<tunnel address>}} はトンネルの入り口となるマシンのアドレスです: {{Ic|localhost}}, {{Ic|*}} (あるいは空)。特定のアドレス経由の接続、ループバックインターフェイス経由の接続、全てのインターフェイス経由の接続を許可します。デフォルトでは、フォワーディングはトンネルの入り口のマシンからの接続だけに制限されており {{Ic|<tunnel address>}} は {{Ic|localhost}} に設定されています。ローカルフォワーディングは特に設定が必要ありませんが、リモートフォワーディングはリモートサーバーの SSH デーモンの設定によって制限を受けます。詳しくは {{Ic|sshd_config(5)}} の {{Ic|GatewayPorts}} オプションを見てください。 |
||
494行目: | 418行目: | ||
=== 踏み台ホスト === |
=== 踏み台ホスト === |
||
− | 場合によっては、接続先の SSH デーモンに直接接続できず、踏み台サーバー (ジャンプサーバー) を使わざるを得ないことがあります。 |
+ | 場合によっては、接続先の SSH デーモンに直接接続できず、踏み台サーバー (ジャンプサーバー) を使わざるを得ないことがあります。2つ以上の SSH トンネルを接続して、それぞれのサーバーに対してローカルの鍵で認証します。SSH エージェントの転送 ({{ic|-A}}) と疑似端末の割当 ({{ic|-t}}) を使って以下のようにローカルの鍵を転送します: |
$ ssh -A -t -l user1 bastion1 \ |
$ ssh -A -t -l user1 bastion1 \ |
||
500行目: | 424行目: | ||
ssh -A -t -l user3 target |
ssh -A -t -l user3 target |
||
− | + | ProxyCommand オプションを使えばこれを自動化することができます: |
|
+ | |||
+ | $ ssh -o ProxyCommand="ssh -W %h:%p bastion.example.org" targetserver.example.org |
||
+ | |||
+ | {{ic|-J}} フラグで ProxyJump オプションを使用すれば、これをより簡単かつセキュアに行うことができます: |
||
$ ssh -J user1@bastion1,user2@intermediate2 user3@target |
$ ssh -J user1@bastion1,user2@intermediate2 user3@target |
||
{{ic|-J}} ディレクティブで指定するホストはカンマで区切り、指定された順番で接続されます。{{ic|user...@}} の部分は必須ではありません。{{ic|-J}} で指定したホストは ssh の設定ファイルを使うため、必要であればホスト毎にオプションを設定することが可能です。 |
{{ic|-J}} ディレクティブで指定するホストはカンマで区切り、指定された順番で接続されます。{{ic|user...@}} の部分は必須ではありません。{{ic|-J}} で指定したホストは ssh の設定ファイルを使うため、必要であればホスト毎にオプションを設定することが可能です。 |
||
+ | |||
+ | ProxyCommand オプションと ProxyJump オプションの主な違いは、後者は踏み台ホスト上のシェルを必要としないところにあります。その結果、ユーザのログイン認証情報への踏み台サーバでのアクセスや SSH エージェントフォワーディングが必要なくなります。ProxyJump オプションでは、ssh クライアントは踏み台サーバを通して直接ターゲットのサーバへ接続し、エンドツーエンドの暗号化されたチャネルをクライアントとターゲットサーバとの間で確立します。 |
||
+ | |||
+ | 設定ファイルにも、{{ic|-J}} フラグと等価なものとして {{ic|ProxyJump}} オプションがあります。詳細は {{man|5|ssh_config}} を見てください。 |
||
+ | |||
+ | === リレーを介したリバース SSH === |
||
+ | |||
+ | アイデアとしては、クライアントは別のリレーを使ってサーバに接続し、サーバはリバース SSH トンネルを使って同じリレーに接続します。これは、サーバが NAT 内にあり、リレーが、ユーザがアクセス可能なプロキシとして使用されている、パブリックにアクセス可能な SSH サーバである場合に便利です。ゆえに、クライアントの鍵がリレーとサーバの両方に対して認可されていることが前提条件であり、サーバはリレーに対してもリバース SSH 接続に対しても認可されている必要があります。 |
||
+ | |||
+ | 以下の設定例では、user1 が client 上で使用されているユーザアカウントであり、user2 は relay 上のアカウント、user3 が server 上のアカウントであるとします。まず、以下のコマンドでサーバとリバーストンネルとの接続が確立している必要があります: |
||
+ | |||
+ | ssh -R 2222:localhost:22 -N user2@relay |
||
+ | |||
+ | これは、スタートアップスクリプトや systemd サービス、[[#Autossh - SSH セッションとトンネルの自動再起動|autossh]] を使って自動化することもできます。 |
||
+ | |||
+ | クライアント側では、以下のコマンドで接続を確立させます: |
||
+ | |||
+ | ssh -t user2@relay ssh user3@localhost -p 2222 |
||
+ | |||
+ | リバーストンネルとの接続を確立させるためのリモートのコマンドは、relay の {{ic|~/.ssh/authorized_keys}} に以下のような {{ic|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 接続がブロックされてしまいます。すぐできる解決策として、許可されているポート |
+ | SSH デーモンは通常はポート 22 番をリッスンします。しかし、公共のインターネット・ホットスポットでは通常の HTTP/HTTPS のポート(80 と 443)以外のトラフィックをブロックしていることが一般的です。そのため SSH 接続がブロックされてしまいます。すぐできる解決策として、{{ic|sshd}} に許可されているポートをリッスンさせるという方法があります: |
{{hc|/etc/ssh/sshd_config| |
{{hc|/etc/ssh/sshd_config| |
||
515行目: | 471行目: | ||
}} |
}} |
||
− | しかしポート 443 番は HTTPS を提供する Web サーバにすでに使われていることが多いです。その場合は {{Pkg|sslh}} のようなマルチプレクサを使います。これは |
+ | しかしポート 443 番は HTTPS コンテンツを提供する Web サーバによってすでに使われていることが多いです。その場合は {{Pkg|sslh}} のようなマルチプレクサを使います。これは複数のポートをリッスンし、そこに来るパケットを複数のサービスに賢く振り分けることができます。 |
=== SSH の高速化 === |
=== SSH の高速化 === |
||
542行目: | 498行目: | ||
=== SSHFS でリモートファイルシステムをマウントする === |
=== SSHFS でリモートファイルシステムをマウントする === |
||
− | sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は [[Sshfs]] の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に shfs よりも sshfs を使用することを推奨します。sshfs は shfs の新しいバージョンであり、元の shfs は2004年から更新されていません。 |
||
+ | sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は [[SSHFS]] の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に ''shfs'' よりも ''sshfs'' を使用することを推奨します。''sshfs'' は ''shfs'' の新しいバージョンであり、元の ''shfs'' は2004年から更新されていません。 |
||
− | === Keep alive === |
||
+ | |||
− | 一定時間操作がないと ssh セッションは自動的にログアウトします。接続を維持するには以下をクライアントの {{ic|~/.ssh/config}} か {{ic|/etc/ssh/ssh_config}} に追加してください: |
||
+ | === キープアライブ === |
||
+ | デフォルトでは、SSH セッションが一定時間アイドルであった場合、自動的にログアウトします。一定時間データが受信されなかった場合にサーバにキープアライブシグナルを送信することで、セッションを開いたままにすることができます。あるいは対照的に、クライアントからデータが送られてこない場合にサーバが定期的にメッセージを送信することもできます。 |
||
− | ServerAliveInterval 120 |
||
+ | * '''サーバ'''側: {{ic|ClientAliveInterval}} はタイムアウトを秒単位で設定します。クライアントからデータが受信されずにその時間経過すると、''sshd'' が応答を促すリクエストを送信します。デフォルトは0であり、メッセージは送信されません。例えば、60秒毎にクライアントに対して応答を要求するには、[[#設定_2|サーバ側の設定]]で {{ic|ClientAliveInterval 60}} オプションを設定してください。{{ic|ClientAliveCountMax}} と {{ic|TCPKeepAlive}} オプションも参照してください。 |
||
− | これで120秒ごとに "keep alive" シグナルがサーバーに送信されます。{{ic|ServerAliveCountMax}} や {{ic|TCPKeepAlive}} オプションも参照してください。 |
||
+ | * '''クライアント'''側: {{ic|ServerAliveInterval}} は、クライアントからサーバに向けて送信されるリクエストの時間間隔を設定します。例えば、120秒毎にサーバに対して応答を要求するには、[[#設定|クライアント側の設定]]で {{ic|ServerAliveInterval 120}} オプションを追加してください。{{ic|ServerAliveCountMax}} と {{ic|TCPKeepAlive}} オプションも参照してください。 |
||
+ | {{Note|セッションを開いたままにするためにキープアライブリクエストを送信する必要があるのは、クライアントかサーバの一方のみです。サーバとクライアントの両方を制御できるならば、セッションを永続的にする必要のあるクライアントに対してのみ {{ic|ServerAliveInterval}} を正の値に設定し、その他のクライアントやサーバはデフォルトの設定するのが妥当な選択です。}} |
||
− | 反対に、外部からの接続を維持するには、次をサーバーの {{ic|/etc/ssh/sshd_config}} に設定します (数字は0より大きく): |
||
− | |||
− | ClientAliveInterval 120 |
||
=== systemd で SSH トンネルを自動的に再起動 === |
=== systemd で SSH トンネルを自動的に再起動 === |
||
− | [[systemd]] を使ってブート時/ログイン時に SSH 接続を自動的に開始して、接続が失敗した時に再起動させることができます。SSH トンネルの管理に役立つツールとなります。 |
+ | [[systemd]] を使ってブート時/ログイン時に SSH 接続を自動的に開始して、''さらに''接続が失敗した時に再起動させることができます。SSH トンネルの管理に役立つツールとなります。 |
− | 以下のサービスでは、[[# |
+ | 以下のサービスでは、[[#設定|ssh の設定]]に保存された接続設定を使って、ログイン時に SSH トンネルを開始します。接続が何らかの理由で閉じられた場合、10秒待機してから再起動します: |
{{hc|~/.config/systemd/user/tunnel.service|<nowiki> |
{{hc|~/.config/systemd/user/tunnel.service|<nowiki> |
||
572行目: | 527行目: | ||
</nowiki>}} |
</nowiki>}} |
||
− | 上記のユーザーサービスを[[有効化]]して[[起動]]してください。トンネルがタイムアウトするのを防ぐ方法は [[# |
+ | 上記の [[systemd/ユーザー]]サービスを[[有効化]]して[[起動]]してください。トンネルがタイムアウトするのを防ぐ方法は [[#キープアライブ]] を見て下さい。起動時にトンネルを開始したい場合、[[systemd#ユニットファイル|ユニットをシステムサービスとして書きなおして下さい]]。 |
=== Autossh - SSH セッションとトンネルの自動再起動 === |
=== Autossh - SSH セッションとトンネルの自動再起動 === |
||
+ | |||
ネットワークの状態が悪かったりしてクライアントが切断してしまい、セッションやトンネルの接続を維持できない場合、{{Pkg|autossh}} を使って自動的にセッションとトンネルを再起動できます。 |
ネットワークの状態が悪かったりしてクライアントが切断してしまい、セッションやトンネルの接続を維持できない場合、{{Pkg|autossh}} を使って自動的にセッションとトンネルを再起動できます。 |
||
使用例: |
使用例: |
||
+ | |||
$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" username@example.com |
$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" username@example.com |
||
+ | |||
− | [[sshfs]] を組み合わせる: |
||
+ | [[SSHFS]] と組み合わせる: |
||
+ | |||
$ sshfs -o reconnect,compression=yes,transform_symlinks,ServerAliveInterval=45,ServerAliveCountMax=2,ssh_command='autossh -M 0' username@example.com: /mnt/example |
$ sshfs -o reconnect,compression=yes,transform_symlinks,ServerAliveInterval=45,ServerAliveCountMax=2,ssh_command='autossh -M 0' username@example.com: /mnt/example |
||
+ | |||
− | [[プロキシ設定]]で設定した SOCKS プロクシを使って接続: |
||
+ | [[プロキシ設定]]で設定した SOCKS プロキシを使って接続: |
||
+ | |||
$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" -NCD 8080 username@example.com |
$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" -NCD 8080 username@example.com |
||
+ | |||
{{ic|-f}} オプションで autossh をバックグラウンドプロセスとして実行することができます。ただし対話式でパスフレーズを入力することができなくなります。 |
{{ic|-f}} オプションで autossh をバックグラウンドプロセスとして実行することができます。ただし対話式でパスフレーズを入力することができなくなります。 |
||
− | セッション中に {{ic|exit}} と入力したり autossh プロセスに SIGTERM |
+ | セッション中に {{ic|exit}} と入力したり autossh プロセスに SIGTERM、SIGINT、SIGKILL シグナルが送られるとセッションは終了します。 |
==== systemd を使ってブート時に自動的に autossh を起動する ==== |
==== systemd を使ってブート時に自動的に autossh を起動する ==== |
||
+ | |||
autossh を自動的に起動したい場合、以下の systemd ユニットファイルを作成します: |
autossh を自動的に起動したい場合、以下の systemd ユニットファイルを作成します: |
||
613行目: | 576行目: | ||
{{Tip|複数のautosshプロセスを維持し、複数のトンネルを存続させることも簡単です。名前の異なる複数のサービスファイルを作成するだけです。}} |
{{Tip|複数のautosshプロセスを維持し、複数のトンネルを存続させることも簡単です。名前の異なる複数のサービスファイルを作成するだけです。}} |
||
+ | === SSH デーモンが失敗した場合の代替サービス === |
||
− | == ソケットアクティベーションで SSH ポート番号を変更する (sshd.socket) == |
||
+ | SSH のみに依存するリモート或いはヘッドレスのサーバにおいて、(システムアップグレード後などに) SSH デーモンの起動に失敗すると、管理アクセスできなくなってしまう場合があります。[[systemd]] は、{{ic|OnFailure}} によるシンプルなソリューションを提供しています。 |
||
− | 次の内容で {{ic|/etc/systemd/system/sshd.socket.d/port.conf}} ファイルを作成: |
||
+ | サーバ上で {{ic|sshd}} が実行されていて、[[telnet]] がフェイルセーフであるとしてます。以下のようにファイルを作成してください。ただし、{{ic|telnet.socket}} は[[有効化]]'''しないでください'''! |
||
− | [Socket] |
||
− | # Disable default port |
||
− | ListenStream= |
||
− | # Set new port |
||
− | ListenStream=12345 |
||
+ | {{hc|/etc/systemd/system/sshd.service.d/override.conf|2= |
||
− | リロードすれば systemd は自動的に新しいポートを開きます: |
||
+ | [Unit] |
||
+ | OnFailure=telnet.socket |
||
+ | }} |
||
+ | これだけです。{{ic|sshd}} が実行中である場合、Telnet は実行されません。{{ic|sshd}} が起動に失敗した場合、telnet セッションがリカバリとして開かれます。 |
||
− | systemctl daemon-reload |
||
+ | |||
+ | === ホストに基づいてターミナル背景色を設定する === |
||
+ | |||
+ | 異なるホストに接続していることを簡単に判別できるようにするために、[https://bryangilbert.com/post/etc/term/dynamic-ssh-terminal-background-colors/ ホストの種類に応じて異なる背景色]を設定することができます。 |
||
+ | |||
+ | このソリューションは一般には適用できません (ZSH 限定)。 |
||
+ | |||
+ | === ネットワーク固有の設定 === |
||
+ | |||
+ | {{ic|Match exec}} を使うことで、接続先のネットワークに固有のホスト設定を使用することができます。 |
||
+ | |||
+ | 例えば、{{man|1|nmcli}} を使用していて、接続が検索ドメインを使用するように (手動、あるいは DHCP で) 設定されている場合: |
||
+ | |||
+ | {{bc|1= |
||
+ | 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 |
||
+ | }} |
||
+ | |||
+ | {{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= |
||
+ | Match host internal.example.com !exec "host internal.example.com" |
||
+ | ProxyJump bastion.example.com |
||
+ | Host internal.example.com |
||
+ | User foobar |
||
+ | }} |
||
+ | |||
+ | === プライベートネットワークのホスト鍵検証 === |
||
+ | |||
+ | あるネットワーク上のサーバとそれとは別のネットワーク上のサーバは、互いに同じプライベート IP アドレスを持つ可能性があるため、それらのサーバは異なる方法で処理する必要があるかもしれません。 |
||
+ | |||
+ | {{Accuracy|「最適な」ソリューションに、本番環境では別のものを使うべきという警告があるはずがない。}} |
||
+ | |||
+ | 最適なソリューションは、[[#ネットワーク固有の設定]] を使用し、接続しているネットワークに応じて異なる {{ic|UserKnownHostsFile}} を使うことです。2つめのソリューションは、プライベートネットワークのホスト鍵を単に無視することです (新しい/プロトタイプのネットワークで作業する際にデフォルトで使用するのが最適です): |
||
+ | |||
+ | {{bc|1= |
||
+ | 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 |
||
+ | }} |
||
+ | |||
+ | {{Accuracy|{{ic|known_hosts}} ファイルは、サーバにアクセスするためにホスト名を使用したとしても、IP アドレスを記録します。}} |
||
+ | |||
+ | {{Warning|本番環境では、ホスト名を使用してホストにアクセスしたり、ネットワーク固有の known_hosts ファイルを使用するようにしてください。}} |
||
+ | |||
+ | === ログイン時にコマンドを実行 === |
||
+ | |||
+ | インタラクティブセッションを使用している場合、ログイン時にコマンドを実行する方法は複数存在します: |
||
+ | |||
+ | * リモートホスト上の {{ic|authorized_keys}} ファイルを使用する ({{man|8|sshd}} の {{ic|AUTHORIZED_KEYS FILE FORMAT}} セクションを参照) |
||
+ | * サーバで {{ic|PermitUserRC}} オプションが有効化されている場合、リモートホスト上の {{ic|~/.ssh/rc}} を使用する |
||
+ | * リモートホスト上のシェル設定ファイルを使用する (例: {{ic|.bashrc}}) |
||
+ | |||
+ | === エージェントフォワーディング === |
||
+ | |||
+ | SSH エージェントのフォワーディングにより、サーバに接続している状態でローカルの鍵を使用することができます。選択したホストのみに対してエージェントフォワーディングを許可することが[https://security.stackexchange.com/questions/7480/risks-of-ssh-to-an-untrusted-host#7504 推奨]されます。 |
||
+ | |||
+ | {{hc|~/.ssh/config| |
||
+ | Host ''myserver.com'' |
||
+ | ForwardAgent yes |
||
+ | }} |
||
+ | |||
+ | 次に、[[SSH エージェント]]を構成し、''ssh-add'' を使ってローカル鍵を追加してください。 |
||
+ | |||
+ | これで、リモートサーバに接続する場合、あなたのローカル鍵を使用して他のサービスに接続できるようになりました。 |
||
+ | |||
+ | === 新しい鍵の生成 === |
||
+ | |||
+ | 新しいサーバの秘密鍵は以下で生成できます: |
||
+ | |||
+ | # すべての鍵を削除する。例えば: {{bc|# rm /etc/ssh/ssh_host_*_key*}} |
||
+ | # {{ic|sshdgenkeys.service}} を[[再起動]]するか、{{ic|ssh-keygen -A}} を root として実行する。 |
||
+ | |||
+ | === sshd を非特権ユーザとして実行 === |
||
+ | |||
+ | {{ic|sshd}} をコンテナ内で (或いはテスト目的などで) 非特権ユーザとして実行したい場合もあるでしょう。 |
||
+ | |||
+ | 非特権ユーザは {{ic|/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'' |
||
+ | |||
+ | {{ic|sshd_config}} を作成してください。以下の例では、1024 より大きい値のポート番号を使用し、ホスト鍵への新しいパスを提供し、PAM を無効化します: |
||
+ | |||
+ | {{hc|''/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'' を実行します。{{ic|-D}} フラグはデーモンモードを無効化し、{{ic|-e}} は出力を標準エラー出力にリダイレクトしてモニタしやすくします: |
||
+ | |||
+ | $ sshd -f ''/path/to/sshd_config'' -D -e |
||
== トラブルシューティング == |
== トラブルシューティング == |
||
+ | |||
=== チェックリスト === |
=== チェックリスト === |
||
− | + | まずは以下の単純な問題をチェックしましょう。 |
|
− | # 設定ディレクトリ {{ic|~/.ssh}} の |
+ | # 設定ディレクトリ {{ic|~/.ssh}} のコンテンツが対象ユーザによってのみアクセス可能である必要があります (クライアントとサーバの両方で確認してください)。かつ、対象ユーザのホームディレクトリがそのユーザによってのみ書き込み可能である必要があります: {{bc|<nowiki> |
+ | $ chmod go-w ~ |
||
$ chmod 700 ~/.ssh |
$ chmod 700 ~/.ssh |
||
$ chmod 600 ~/.ssh/* |
$ chmod 600 ~/.ssh/* |
||
$ chown -R $USER ~/.ssh |
$ chown -R $USER ~/.ssh |
||
</nowiki>}} |
</nowiki>}} |
||
− | # クライアントの公開鍵 (例: {{ic|id_rsa.pub}}) がサーバ |
+ | # クライアントの公開鍵 (例: {{ic|id_rsa.pub}}) がサーバ上の {{ic|~/.ssh/authorized_keys}} 内に記述されていることを確認する。 |
− | # [[# |
+ | # [[#設定_2|サーバの設定]]の {{ic|AllowUsers}} や {{ic|AllowGroups}} によって SSH のアクセスが制限されていないことを確認する。 |
− | # ユーザ |
+ | # ユーザがパスワードを設定しているかを確認する。サーバにログインしたことのない新しいユーザは、パスワードを持っていないことがあります。 |
+ | # {{ic|/etc/ssh/sshd_config}} に {{ic|LogLevel DEBUG}} を[[追加]]してみる。 |
||
− | # {{ic|sshd}} を再起動してクライアントとサーバーの両方で一度ログアウトをしてみる。 |
||
+ | # {{ic|journalctl -xe}} を root として実行して、(エラー) メッセージの取得を試みる。 |
||
+ | # {{ic|sshd}} を[[再起動]]し、クライアントとサーバの両方でログアウト/ログインする。 |
||
− | === 接続 |
+ | === 接続の拒否やタイムアウトの問題 === |
− | ==== |
+ | ==== ポートフォワーディング ==== |
− | NAT モードやルータ |
+ | NAT モードやルータを使っている場合 (VPS を使っていたりパブリックにアドレッシングされたホストを使用していない限り、あり得ます)、ルータが ssh の着信接続をマシンにフォワーディングしていることを確認してください。{{ic|$ ip addr}} を使ってサーバの内部 IP アドレスを見つけ、SSH ポートの TCP 接続をその IP にフォワーディングするようにルータを設定してください。[https://portforward.com portforward.com] が役に立ちます。 |
− | ==== SSH が動作しているか? ==== |
+ | ==== SSH が動作していて、リッスンしているか? ==== |
− | $ ss -tnlp |
||
+ | [[ss]] ユーティリティは、以下のコマンドラインを使うことで、TCP ポートをリッスンしている全プロセスを表示します: |
||
− | 上記のコマンドで SSH ポートが開いていると表示されない場合、SSH は動作していません。{{ic|/var/log/messages}} にエラーがないか確認してください。 |
||
+ | |||
+ | $ ss --tcp --listening |
||
+ | |||
+ | このコマンドの出力を見て、システムが {{ic|ssh}} ポートをリッスンしていないことが判明した場合、SSH が実行されていないことを意味します。[[Journal]] でエラーなどが出力されていないか確認してください。 |
||
==== 接続をブロックするようなファイアウォールのルールが存在しないか? ==== |
==== 接続をブロックするようなファイアウォールのルールが存在しないか? ==== |
||
664行目: | 738行目: | ||
==== トラフィックがコンピュータにまで到達しているか? ==== |
==== トラフィックがコンピュータにまで到達しているか? ==== |
||
+ | |||
以下のように問題のコンピュータのトラフィックを収集してみてください: |
以下のように問題のコンピュータのトラフィックを収集してみてください: |
||
671行目: | 746行目: | ||
==== ISP またはサードパーティによってデフォルトのポートがブロックされてないか? ==== |
==== ISP またはサードパーティによってデフォルトのポートがブロックされてないか? ==== |
||
+ | |||
{{Note|このステップは次のことを確認した後で実行してください。ファイアーウォールを何も起動していないこと。DMZ へのルーターを正しく設定している、またはコンピュータへポートを転送していること。それでもまだ動かない場合、ここで診断のステップと解決法が見つかるでしょう。}} |
{{Note|このステップは次のことを確認した後で実行してください。ファイアーウォールを何も起動していないこと。DMZ へのルーターを正しく設定している、またはコンピュータへポートを転送していること。それでもまだ動かない場合、ここで診断のステップと解決法が見つかるでしょう。}} |
||
− | ときどき ISP |
+ | ときどき ISP が SSH のデフォルトポート (22番) をブロックしている場合があります。この場合はあなたが何をしても (ポートを開ける、スタックを強化する、フラッドアタックを防御する、など) 無意味になります。ブロックされているかどうか確認するために、全てのインターフェイス (0.0.0.0) をリッスンするサーバを立ち上げ、リモートから接続してみてください。 |
このようなエラーメッセージが出る場合: |
このようなエラーメッセージが出る場合: |
||
+ | |||
ssh: connect to host www.inet.hr port 22: Connection refused |
ssh: connect to host www.inet.hr port 22: Connection refused |
||
− | これはそのポートが ISP にブロックされていないが、そのポートでサーバーの SSH が起動していないことを意味します ([[wikipedia: |
+ | これはそのポートが ISP にブロックされて'''いない'''が、そのポートでサーバーの SSH が起動していないことを意味します ([[wikipedia:Security through obscurity|security through obscurity]] を参照)。 |
しかし、次のようなエラーメッセージが出る場合: |
しかし、次のようなエラーメッセージが出る場合: |
||
+ | |||
ssh: connect to host 111.222.333.444 port 22: Operation timed out |
ssh: connect to host 111.222.333.444 port 22: Operation timed out |
||
− | これは何かがポート 22 での TCP トラフィックを拒否 |
+ | これは何かがポート 22 での TCP トラフィックを拒否していることを意味します。そのポートはあなたのサーバー上のファイアーウォールか第三者 (ISP など) のどちらかによってステルスされています。自分のサーバーでファイアーウォールが起動していないことが確かなら、また、ルーターやスイッチの中でグレムリンが育っていないことが確かなら、ISP がトラフィックをブロックしています。 |
ダブルチェックのために、サーバ上で Wireshark を起動してポート 22 でのトラフィックをリッスンしてみましょう。Wireshark はレイヤ 2 のパケット・スニファリング・ユーティリティであり、TCP/UDP はレイヤ 3 以上なので ([[wikipedia:ja:インターネット・プロトコル・スイート|IP ネットワークスタック]]を参照)、もしリモートから接続するときに何も受け取っていなければ、十中八九、第三者がブロックしています。 |
ダブルチェックのために、サーバ上で Wireshark を起動してポート 22 でのトラフィックをリッスンしてみましょう。Wireshark はレイヤ 2 のパケット・スニファリング・ユーティリティであり、TCP/UDP はレイヤ 3 以上なので ([[wikipedia:ja:インターネット・プロトコル・スイート|IP ネットワークスタック]]を参照)、もしリモートから接続するときに何も受け取っていなければ、十中八九、第三者がブロックしています。 |
||
===== 問題診断 ===== |
===== 問題診断 ===== |
||
+ | |||
− | {{Pkg|tcpdump}} または {{Pkg|wireshark-cli}} パッケージの Wireshark を[[インストール]]してください。 |
||
+ | {{Pkg|tcpdump}} または {{Pkg|wireshark-cli}} パッケージで Wireshark を[[インストール]]してください。 |
||
tcpdump の場合: |
tcpdump の場合: |
||
+ | |||
# tcpdump -ni ''interface'' "port 22" |
# tcpdump -ni ''interface'' "port 22" |
||
Wireshark の場合: |
Wireshark の場合: |
||
+ | |||
$ tshark -f "tcp port 22" -i ''interface'' |
$ tshark -f "tcp port 22" -i ''interface'' |
||
699行目: | 780行目: | ||
===== 解決方法 ===== |
===== 解決方法 ===== |
||
+ | |||
− | 解決方法は、単に ISP がブロックしていない他のポートを使うことです。{{ic|/etc/ssh/sshd_config}} を編集して他のポートを使うようにしましょう。例えば次を追加します: |
||
+ | 解決方法は、単に ISP がブロックしていない他のポートを使うことです。{{ic|/etc/ssh/sshd_config}} を編集して他のポートを使うようにしましょう。例えば次を追加します: |
||
Port 22 |
Port 22 |
||
706行目: | 788行目: | ||
そしてこのファイル中の他の Port 設定をコメントアウトします。「Port 22」をコメントにして「Port 1234」を追加するだけでは、sshd がポート 1234 しかリッスンしなくなるので、この問題は解決しません。この 2 行どちらも使用し、sshd が両方のポートをリッスンするようにします。 |
そしてこのファイル中の他の Port 設定をコメントアウトします。「Port 22」をコメントにして「Port 1234」を追加するだけでは、sshd がポート 1234 しかリッスンしなくなるので、この問題は解決しません。この 2 行どちらも使用し、sshd が両方のポートをリッスンするようにします。 |
||
+ | {{ic|sshd.service}} サーバを[[再起動]]すれば、あともう少しです。次に、デフォルトのポートではなくもう一つのポートを使用するようにクライアントを設定しなければなりません。その問題に対するソリューションは数多く存在しますが、ここではそれらのうち2つを扱っています。 |
||
− | あとは {{ic|systemctl restart sshd.service}} で sshd を起動するだけです。そして ssh クライアントでも同じポートに変更します。 |
||
==== Read from socket failed: connection reset by peer ==== |
==== Read from socket failed: connection reset by peer ==== |
||
− | 最近の openssh のバージョンでは、楕円曲線暗号関連のバグのせいで、上記のエラーメッセージで接続が失敗することがあります。その場合 {{ic|~/.ssh/config}} に次の行を追加してください: |
||
+ | 最近のバージョンの openssh は時々、古い ssh サーバに接続する際に上記のエラーメッセージで失敗することがあります。これは、そのホストに対する様々な[[#設定|クライアントオプション]]を設定することにより、回避可能です。以下のオプションに関する詳細は {{man|5|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 |
||
+ | {{ic|ecdsa-sha2-nistp*-cert-v01@openssh}} 楕円曲線ホスト鍵アルゴリズムが原因である可能性があります。このようなアルゴリズムは、{{ic|HostKeyAlgorithms}} にそれらのアルゴリズムを除いたリストを設定することにより、無効化できます。 |
||
− | openssh 5.9 では、上記の修正方法は働きません。代わりに、{{ic|~/.ssh/config}} に以下の行を記述してください: |
||
+ | これでうまく行かない場合、暗号のリストが長過ぎる可能性があります。{{ic|Ciphers}} オプションのリストを短くしてください (80 文字未満であれば十分でしょう)。同じように、{{ic|MACs}} のリストも短くしてみてください。 |
||
− | Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc |
||
− | MACs hmac-md5,hmac-sha1,hmac-ripemd160 |
||
− | openssh バグフォーラム |
+ | openssh のバグフォーラムにおける[https://www.gossamer-threads.com/lists/openssh/dev/51339 議論]も参照してください。 |
− | === "[ |
+ | === "[シェル]: No such file or directory" / ssh_exchange_identification problem === |
− | シェルのバイナリに {{Ic|$PATH}} が通っている場合でも、特定の SSH クライアントは {{Ic|$SHELL}} に絶対パスを設定する必要があります (パスは {{Ic|whereis -b [your shell]}} で確認できます)。 |
||
+ | シェルのバイナリが {{Ic|$PATH}} に登録されているディレクトリ内にあったとしても、特定の SSH クライアントは {{Ic|$SHELL}} に絶対パスを設定する必要があります (パスは {{Ic|whereis -b [あなたのシェル]}} で確認できます)。 |
||
− | ==="Terminal unknown" や "Error opening terminal" エラーメッセージ=== |
||
+ | |||
− | ssh でログイン時に "Terminal unknown" のようなエラーが表示されることがあります。これはサーバーがターミナルを認識できていないことを意味します。また、nano などの ncurses アプリケーションを実行すると "Error opening terminal" というメッセージが表示されます。 |
||
+ | === "Terminal unknown" や "Error opening terminal" エラーメッセージ === |
||
+ | |||
+ | ログイン時に上記のようなエラーが表示される場合、サーバがターミナルを認識できていないことを意味します。また、nano などの ncurses アプリケーションを実行すると "Error opening terminal" というメッセージが表示されることがあります。 |
||
クライアントで使用しているターミナルの terminfo ファイルをサーバーにインストールするのが正しい解決方法です。これによってサーバーのコンソールプログラムがターミナルを正しく扱えるようになります。{{ic|infocmp}} を実行してから[[Pacman#パッケージ・データベースに問い合わせる|パッケージを確認]]することで terminfo に関する情報を取得できます。 |
クライアントで使用しているターミナルの terminfo ファイルをサーバーにインストールするのが正しい解決方法です。これによってサーバーのコンソールプログラムがターミナルを正しく扱えるようになります。{{ic|infocmp}} を実行してから[[Pacman#パッケージ・データベースに問い合わせる|パッケージを確認]]することで terminfo に関する情報を取得できます。 |
||
− | 通常の方法で |
+ | 通常の方法で[[インストール]]できない場合、サーバーのホームディレクトリに terminfo をコピーしてください: |
$ ssh myserver mkdir -p ~/.terminfo/${TERM:0:1} |
$ ssh myserver mkdir -p ~/.terminfo/${TERM:0:1} |
||
735行目: | 817行目: | ||
サーバーから一度ログアウトしてからログインしなおすと問題が解決しているはずです。 |
サーバーから一度ログアウトしてからログインしなおすと問題が解決しているはずです。 |
||
− | ==== |
+ | ==== TERM ハック ==== |
+ | {{Note|これは最後の手段にするべきです。}} |
||
− | {{Warning|この方法はあくまで次善策であり、たまにしか接続しない ssh サーバーで使うようにしてください。}} |
||
− | {{ic| |
+ | あるいは、{{ic|1=TERM=xterm}} 環境変数をサーバ側で (例えば {{ic|.bash_profile}} で) 設定してしまうという方法もあります。これでエラーは出なくなり、ncurses アプリケーションを実行できるようになります。しかし、ターミナルの制御シーケンスが xterm のそれと正確に一致しない限り、奇妙な挙動やグラフィックのバグが発生する場合があります。 |
=== Connection closed by x.x.x.x [preauth] === |
=== Connection closed by x.x.x.x [preauth] === |
||
+ | |||
sshd のログでこのエラーが確認できる場合、HostKey が正しく設定されているか確認してください: |
sshd のログでこのエラーが確認できる場合、HostKey が正しく設定されているか確認してください: |
||
+ | |||
HostKey /etc/ssh/ssh_host_rsa_key |
HostKey /etc/ssh/ssh_host_rsa_key |
||
=== サブシステム要求の失敗 === |
=== サブシステム要求の失敗 === |
||
− | ''OpenSSH'' 8.8 以降、''scp'' はデータ転送のデフォルトプロトコルとして ''SFTP'' を使用し、{{ic|sftp}} というサブシステムを要求するようになりました。もし ''scp'' を冗長モード {{ic|scp -v}} で実行すれば、クライアントがどのサブシステムを使っているかがわかります (例: {{ic|Sending subsystem: <subsystem-name>}})。{{ic|subsystem request failed on channel 0}} のようなエラーは、サーバのサブシステムを設定することで修正できるかもしれません。{man|5|sshd_config|Subsystem}} のように設定します。サーバの設定は、以下の例のようにする必要があります |
+ | ''OpenSSH'' 8.8 以降、''scp'' はデータ転送のデフォルトプロトコルとして ''SFTP'' を使用し、{{ic|sftp}} というサブシステムを要求するようになりました。もし ''scp'' を冗長モード {{ic|scp -v}} で実行すれば、クライアントがどのサブシステムを使っているかがわかります (例: {{ic|Sending subsystem: <subsystem-name>}})。{{ic|subsystem request failed on channel 0}} のようなエラーは、サーバのサブシステムを設定することで修正できるかもしれません。{{man|5|sshd_config|Subsystem}} のように設定します。サーバの設定は、以下の例のようにする必要があります: |
{{hc|/etc/ssh/sshd_config| |
{{hc|/etc/ssh/sshd_config| |
||
757行目: | 841行目: | ||
=== OpenSSH 7.0 によって id_dsa が拒否される === |
=== OpenSSH 7.0 によって id_dsa が拒否される === |
||
− | OpenSSH 7.0 ではセキュリティ上の理由から |
+ | OpenSSH 7.0 ではセキュリティ上の理由から DSA 公開鍵が非推奨になっています。どうしても有効にする必要がある場合、[[#設定|設定]]オプション {{ic|PubkeyAcceptedKeyTypes +ssh-dss}} を設定してください (https://www.openssh.com/legacy.html はこれには言及していません)。 |
− | |||
− | PubkeyAcceptedKeyTypes +ssh-dss |
||
=== OpenSSH 7.0 で No matching key exchange method found === |
=== OpenSSH 7.0 で No matching key exchange method found === |
||
− | OpenSSH 7.0 では |
+ | 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. |
Unable to negotiate with 127.0.0.1: no matching key exchange method found. |
||
Their offer: diffie-hellman-group1-sha1 |
Their offer: diffie-hellman-group1-sha1 |
||
− | 古いアルゴリズムを使用しないようにサーバーをアップグレード |
+ | 古いアルゴリズムを使用しないようにサーバーをアップグレード/設定することで上記のエラーは解決します。サーバー側の設定を変更できない場合、[[#設定|クライアント設定]]で {{ic|KexAlgorithms +diffie-hellman-group1-sha1}} オプションを使うことでアルゴリズムを有効化できます。 |
− | === SSH から切断したときに tmux/screen セッションが |
+ | === SSH から切断したときに tmux/screen セッションがキルされる === |
− | セッションの |
+ | セッションの終了時にプロセスがキルされる場合、ソケットアクティベーションを使っているために SSH セッションプロセスが終了したときに {{Pkg|systemd}} によって終了されている可能性があります。{{ic|ssh.socket}} の代わりに {{ic|ssh.service}} を使用してソケットアクティベーションを使わないことで解決できます。もしくは {{ic|ssh@.service}} の Service セクションで {{ic|1=KillMode=process}} を設定してください。 |
{{ic|1=KillMode=process}} は古典的な {{ic|ssh.service}} でも役に立つことがあります。サーバーが停止したり再起動したときに SSH セッションプロセスや {{Pkg|screen}} や {{Pkg|tmux}} のプロセスが終了されることを防ぐことができます。 |
{{ic|1=KillMode=process}} は古典的な {{ic|ssh.service}} でも役に立つことがあります。サーバーが停止したり再起動したときに SSH セッションプロセスや {{Pkg|screen}} や {{Pkg|tmux}} のプロセスが終了されることを防ぐことができます。 |
||
782行目: | 864行目: | ||
=== Broken pipe === |
=== Broken pipe === |
||
− | 接続を作ろうとして {{ic|packet_write_wait}} のレスポンスが {{ic|Broken pipe}} にな |
+ | 接続を作ろうとして {{ic|packet_write_wait}} のレスポンスが {{ic|Broken pipe}} になる場合、デバッグモードで接続を再試行し、出力がエラーで終わるかどうか確認する必要があります: |
{{bc|debug3: send packet: type 1 |
{{bc|debug3: send packet: type 1 |
||
packet_write_wait: Connection to A.B.C.D port 22: Broken pipe}} |
packet_write_wait: Connection to A.B.C.D port 22: Broken pipe}} |
||
− | 上記の {{ic|send packet}} の行は、応答パケットが受信されなかったことを示しています。つまり、これは ''QoS'' の問題であることがわかります。パケットを落とす可能性を減らすには、{{ic|IPQoS}} を設定してください |
+ | 上記の {{ic|send packet}} の行は、応答パケットが受信されなかったことを示しています。つまり、これは ''QoS'' の問題であることがわかります。パケットを落とす可能性を減らすには、{{ic|IPQoS}} を設定してください: |
{{hc|/etc/ssh/ssh_config|Host * |
{{hc|/etc/ssh/ssh_config|Host * |
||
IPQoS reliability}} |
IPQoS reliability}} |
||
− | サービスタイプ |
+ | サービスタイプ {{ic|reliability}} ({{ic|0x04}}) は、{{ic|0x00}} や {{ic|throughput}} ({{ic|0x08}}) と同様に、このコマンドを解決するはずです。 |
=== 再起動後デーモンの起動が遅い === |
=== 再起動後デーモンの起動が遅い === |
||
− | 特にヘッドレスサーバや仮想化サーバにおいて、再起動後のデーモン起動時間が過度に長くなる場合 |
+ | 特にヘッドレスサーバや仮想化サーバにおいて、再起動後のデーモン起動時間が過度に長くなる場合 (例: デーモンが接続を受け付け始めるまでに数分かかる)、エントロピー不足が原因かもしれません。[https://bbs.archlinux.org/viewtopic.php?id=241954] これは、あなたのシステムに適した [[Rng-tools]] や [[Haveged]] をインストールすれば改善することが可能です。ただし、それぞれのパッケージの wiki ページで説明されている、関連するセキュリティ上の影響に注意してください。 |
=== 応答のない SSH 接続を終了する === |
=== 応答のない SSH 接続を終了する === |
||
− | クライアントセッションが応答しなくなり、実行中のプログラム (例えば [[シェル]]) に終了を指示しても終了しない場合、 |
+ | クライアントセッションが応答しなくなり、実行中のプログラム (例えば [[シェル]]) に終了を指示しても終了しない場合、{{ic|Enter}}、{{ic|~}}、そして {{ic|.}} をこの順番で次々に押すと、セッションを終了させることが可能です。 |
− | この {{ic|~}} は疑似端末エスケープ文字 |
+ | この {{ic|~}} は疑似端末エスケープ文字 ({{man|1|ssh|ESCAPE CHARACTERS}} 参照) であり、終了させるクライアントセッションに応じて複数回付加することが可能です。例えば、A から B へ接続し、B から C へ接続したときに B から C へのセッションがフリーズした場合、{{ic|Enter}} を押して {{ic|~~.}} と入力すれば、B の作業セッションを残して B から C へのセッションを終了させることができます。 |
=== WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! === |
=== WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! === |
||
− | + | ssh サーバの鍵が変更されたことをクライアントが警告した場合、新しく提供された鍵が本当にサーバオペレータのものであるかどうかを確認する必要があります。確認したら、{{ic|known_hosts}} ファイルから古い鍵を {{ic|ssh-keygen -R $SSH_HOST}} で削除し、まるで新しく追加されたサーバであるかのように新しい鍵を追加してください。 |
|
=== 適切な terminfo エントリがないリモートに接続する場合 === |
=== 適切な terminfo エントリがないリモートに接続する場合 === |
||
− | + | あなたのターミナルの terminfo エントリが無いホストに接続する場合 (例えば、{{Pkg|ncurses}} に同梱されていない terminfo エントリのターミナルを使用している場合) や、terminfo データベースが限られているホストに接続する場合 (例えば、[[Wikipedia:ja:OpenWrt|OpenWrt]] を実行しているシステム)、{{man|5|terminfo}} に依存しているソフトウェアで様々な問題が発生します。 |
|
適切な解決策は、適切な terminfo エントリをホストに設置することです。それが不可能な場合は、リモートホストがサポートし、かつ端末と互換性のある値を {{ic|TERM}} に設定することで解決できます。 |
適切な解決策は、適切な terminfo エントリをホストに設置することです。それが不可能な場合は、リモートホストがサポートし、かつ端末と互換性のある値を {{ic|TERM}} に設定することで解決できます。 |
||
− | OpenSSH 8.7 以降、カスタムの {{ic|TERM}} 環境変数をリモートホストに渡すには、 |
+ | OpenSSH 8.7 以降、カスタムの {{ic|TERM}} 環境変数をリモートホストに渡すには、簡単な設定スニペットを使用してください: |
{{hc|~/.ssh/config|2= |
{{hc|~/.ssh/config|2= |
||
Host example.com |
Host example.com |
||
− | + | SetEnv TERM=xterm-256color |
|
}} |
}} |
||
+ | |||
+ | === 踏み台ホストを介する接続が "bash: No such file or directory" で失敗する === |
||
+ | |||
+ | (踏み台のサーバで) {{ic|SHELL}} 環境変数に有効な完全パスを設定していない場合、以下に似たエラーメッセージで接続は失敗します: |
||
+ | |||
+ | bash: No such file or directory |
||
+ | kex_exchange_identification: Connection closed by remote host |
||
+ | Connection closed by UNKNOWN port 65535 |
||
+ | |||
+ | 踏み台サーバにおいて有効なシェルの完全パスを {{ic|SHELL}} に設定するか、{{ic|~/.ssh/config}} で各サーバに対して特定の {{ic|SHELL}} を設定することで、この問題を解決できます。 |
||
== 参照 == |
== 参照 == |
||
+ | |||
− | *[http://www.la-samhna.de/library/brutessh.html Defending against brute force ssh attacks] |
||
+ | * [[Wikibooks:ja:OpenSSH]] |
||
− | *IBM developerWorks の [https://www.ibm.com/developerworks/jp/linux/library/l-keyc/ OpenSSH キー (鍵) の管理: 第 1 回] と [https://www.ibm.com/developerworks/jp/linux/library/l-keyc2/ 第 2 回] |
||
+ | * [https://www.la-samhna.de/library/brutessh.html Defending against brute force ssh attacks] |
||
+ | * OpenSSH 鍵管理: IBM developerWorks の [https://www.ibm.com/developerworks/library/l-keyc/index.html Part 1]、funtoo.org の [[Funtoo:OpenSSH Key Management, Part 2|Part 2]]、[[Funtoo:OpenSSH Key Management, Part 3|Part 3]] |
||
* [https://stribika.github.io/2015/01/04/secure-secure-shell.html Secure Secure Shell] |
* [https://stribika.github.io/2015/01/04/secure-secure-shell.html Secure Secure Shell] |
||
+ | |||
+ | {{TranslationStatus|OpenSSH|2023-06-24|781777}} |
2023年6月24日 (土) 17:14時点における版
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 problem
- 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 エントリがないリモートに接続する場合
- 5.16 踏み台ホストを介する接続が "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
オプションによって一部の署名アルゴリズムしか許可されていない場合でも、鍵が存在しない場合、再生成されます。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
から変更不可のビットを削除して一時的に書き込み可能にする必要があります。
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
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 証明書のデプロイを自動化する方法が提供されています。人気なものとしては例えば以下があります:
ヒントとテクニック
暗号化 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 上のアカウントであるとします。まず、以下のコマンドでサーバとリバーストンネルとの接続が確立している必要があります:
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.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年から更新されていません。
キープアライブ
デフォルトでは、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 を介して見つけられない場合にのみ、適用されます。様々な代替案が [5] で議論されています。
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
にそれらのアルゴリズムを除いたリストを設定することにより、無効化できます。
これでうまく行かない場合、暗号のリストが長過ぎる可能性があります。Ciphers
オプションのリストを短くしてください (80 文字未満であれば十分でしょう)。同じように、MACs
のリストも短くしてみてください。
openssh のバグフォーラムにおける議論も参照してください。
"[シェル]: No such file or directory" / ssh_exchange_identification problem
シェルのバイナリが $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 ...
OpenSSH 7.0 によって id_dsa が拒否される
OpenSSH 7.0 ではセキュリティ上の理由から DSA 公開鍵が非推奨になっています。どうしても有効にする必要がある場合、設定オプション PubkeyAcceptedKeyTypes +ssh-dss
を設定してください (https://www.openssh.com/legacy.html はこれには言及していません)。
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
Host * IPQoS reliability
サービスタイプ reliability
(0x04
) は、0x00
や throughput
(0x08
) と同様に、このコマンドを解決するはずです。
再起動後デーモンの起動が遅い
特にヘッドレスサーバや仮想化サーバにおいて、再起動後のデーモン起動時間が過度に長くなる場合 (例: デーモンが接続を受け付け始めるまでに数分かかる)、エントロピー不足が原因かもしれません。[6] これは、あなたのシステムに適した Rng-tools や Haveged をインストールすれば改善することが可能です。ただし、それぞれのパッケージの wiki ページで説明されている、関連するセキュリティ上の影響に注意してください。
応答のない 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