集中力が10分しか持たないハチワレ先生

集中力が10分しか持たないハチワレ先生

技術メインの雑記ブログ

10 分で入門する SSH(中級編)

こんにちわ、krkettleです
この記事では多段 SSH、ポートフォワードなどの SSH の中級者向けの内容について紹介します

前提条件

  • macOS 、OpenSSH(8.1p1)で稼働確認をしています
  • キーペアは ECDSA を利用して作成しています(鍵のパスを適宜読み変えてください)
  • SSH で使われている技術(公開鍵認証・電子署名など)は説明しません
  • キーペア作成やワンライナーでの SSH 接続は説明しません

プロキシを経由する

社内ルール等でプロキシを経由する必要がある場合は以下のように設定します
LinuxWindows では設定が異なる場合があります

認証がない場合

Host remote
    (中略)
    ProxyCommand nc -X connect -x [proxy-ip]:[proxy-port] %h %p
  • proxy-ip: プロキシの IP アドレス
  • proxy-port: プロキシのポート番号

認証がある場合

Host remote
    (中略)
    ProxyCommand env CONNECT_USER=[proxy-user] CONNECT_PASSWORD=[proxy-pass] connect -H [proxy-ip]:[proxy-port] %h %p
  • proxy-user: プロキシ認証のユーザ名
  • proxy-pass: プロキシ認証のパスワード

多段 SSH

SSH 接続先で直接対象のサーバに接続するのではなく
踏み台サーバを経由することがあると思います

ローカル → 踏み台 → 目的のサーバ
ローカル → 踏み台 → 目的のサーバ

ローカル → 踏み台 → 目的のサーバで 2 回 SSH コマンドを打つことなく
1 回の ssh コマンドでローカルから目的のサーバに接続する設定をします

Host bastion
    ()

Host remote
    (中略)
    ProxyCommand ssh -CW %h:%p bastion
# 一回のコマンドでOK
ssh remote

言われてみれば当然ですが、踏み台サーバに秘密鍵をおく必要があります
ただ、踏み台サーバに重要なデータ(秘密鍵など)を置いておくのは好ましくないです
これはssh-agentを利用することで回避可能です

ssh-agent

ssh-agent を使うと以下のメリットがあります

  • パスフレーズの入力回数を減らすことができる
  • 認証情報を接続先に引き継ぐことができる (踏み台に秘密鍵情報をおく必要がない)

ssh-agent 実行の流れ

ssh-agent を起動する

eval `ssh-agent`

ssh-agent に秘密鍵を登録する

ssh-add -K ~/.ssh/id_ecdsa
Enter passphrase for ~/.ssh/id_ecdsa: # パスワードを入力してください

ssh-agent を用いて SSH 接続をする

# remote-user: アクセス先のユーザ名
# server-ip: アクセス先の(グローバル)IPアドレス
# -A: 認証情報の転送機能を有効化
ssh -A [remote-user]@[remote-ip]

ssh-agent を終了する

# ※SSH接続が終わった後に実行
eval `ssh-agent -k`

~/.ssh/config で 転送機能を有効化

~/.ssh/config でForwardAgentを設定しておけば
転送機能の引数(-A)を省略できます

Host remote
    (中略)
    FowardAgent yes
ssh remote

ssh-agent を自動終了する

ssh-agent を利用した後に毎回明示的に終了するのは面倒ですが
~/.zlogout に記述しておくことで、これを回避することができます

echo "$(which ssh-agent) -k" >> ~/.zlogout

ssh ポートフォワーディング

SSH 接続先で開いているポートをローカルで開きたい場合があります
Juypter Notebookを簡単な例にとってみましょう

Jupyter Notebook の具体例

Jupyter Notebook はブラウザで Python などのプログラムを実行したり、
分析結果を可視化できるツールで、以下のような手順で利用します

  1. Jupyter Notebook を起動する
  2. ブラウザを起動し、localhost の指定のポート番号にアクセスする

しかし、SSH 接続先で Jupyter Notebook を起動した場合はどうでしょうか
こんな時に役立つ機能が ssh ポートフォワーディングです

ssh ポートフォワーディングとは

ssh ポートフォワーディングには 2 種類存在します

  • ローカルフォワード
    • リモートから(認証なしで)アクセスできる環境に、ローカルからアクセスする
  • リモートフォワード
    • ローカルから(認証なしで)アクセスできる環境に、リモートからアクセスする

今回はローカルフォワードについてのみ設定方法を紹介します

ローカルフォワード

ローカルフォワードの流れは以下の通りです

ローカルフォワード設定をして SSH 接続する

# local-port: ローカルからアクセスするポート番号
# target-ip: 目的サーバのIPアドレス or ドメイン名
# target-port: 目的サーバのポート番号
ssh -L [local-port]:[target-ip]:[target-port] [remote-user]@[remote-ip]

ローカルのポートにアクセスする
(Chrome などのブラウザからでも、ターミナルから curl でも OK)

SSHポートフォワーディング
SSHポートフォワーディング

ここで注意事項があります
リモートマシン(remote)と目的のサーバ(target)は必ずしも別である必要はありません
(remote と target が同じ場合はtarget-ipの部分にlocalhostを設定すれば OK です)

~/.ssh/config で ローカルフォワードを有効化

~/.ssh/config でLocalForwardを設定しておけば
ローカルフォワードの引数(-L)を省略できます
※LocalForward は複数設定できるため、複数組のポートに対して設定可能です

Host remote
    (中略)
    LocalForward 8080 localhost:8888
ssh remote

上記の例では、ローカルの 8080 番ポートにアクセスすることで、 リモートマシン(remote)の 8888 番ポートにアクセスできます

具体例

これまでの内容を元に~/.ssh/config の具体例を紹介します
構成図と各種設定は以下の通りです

  • ユーザ名: sample-user
  • 秘密鍵のパス: ~/.ssh/id_ecdsa
  • SSH 用ポート番号: 50022

具体例の全体構成図
具体例の全体構成図

ServerAliveInterval 60

Host bastion
    HostName bastion-ip
    User sample-user
    Port 50022
    ProxyCommand env CONNECT_USER=sample-user CONNECT_PASSWORD=password connect -H proxy-ip:proxy-port %h %p
    ForwardAgent yes

Host remote
    HostName remote-ip
    User sample-user
    Port 50022
    ProxyCommand ssh -CW %h:%p bastion
    LocalForwad 8080 localhost:8888

※今回の例では踏み台 - リモートマシン間が SSH 接続の必要があるため、 LocalForawrd では remote 内で localhost を利用しました

echo "$(which ssh-agent) -k" >> ~/.zlogout
eval `ssh-agent`
ssh-add -K ~/.ssh/id_ecdsa
ssh remote