LoginSignup
11
13

ProxyJumpでhostnameを解決しながら踏み台サーバーをジャンプ

Last updated at Posted at 2021-01-23

なにこれ

最近こんな案件に当たりました

  • サーバーの種類がかなりの台数ある上に、踏み台経由じゃないとアクセスできない
  • 認証鍵もポートもユーザー名も全部バラバラ
  • 踏み台サーバーは定期的に再生成されIPがたまに変わる

・・・お堅い仕事は結構ですが、とにかくサーバーあたりの情報指定が多くssh/confignが汚染されるのが嫌なので、別ファイルを使ってsshを叩けるようにしたい!と思ったのですが、適当にProxyCommand書いてもssh: Could not resolve hostnameが出て詰まったので調査がてら勉強しなおしました。
sshの基本についてもついでに書くので、本題にしか興味がない人は本題まで飛ばしてください。

最近忙しすぎて年単位で記事書けてなかった&保守もできてなかったので、記事を書くリハビリを兼ねます

sshでサーバーにアクセス

単純にsshコマンドでアクセスする

まずは基本に立ち返って地道にsshします(本題以前の話です。興味ない人は飛ばしてください)
Portが2222が空いているIP192.168.0.1のサーバーにmochisunaという名前でアクセスしたい場合、

  1. 公開鍵/秘密鍵を生成(クソ雑ネームssh_my_key
    例:ssh-keygen -t ed25519 -C "hirokazu.maruta@gmail.com" -f ssh_my_key
  2. 接続先サーバー(192.168.0.1)の~/.ssh/authorized_keysに公開鍵を追記

を設定して以下のようなコマンドを打つことで、そのサーバーにアクセスすることができるようになります。

ssh -i ~/.ssh/ssh_my_key mochisuna@192.168.0.1 -p 2222

-iオプションはどの認証情報を使うか(≒どの鍵の情報を使うか)というもので、事前に提供した公開鍵に合致する秘密鍵を指定する必要があります。
ただ、ssh-add ~/.ssh/ssh_my_keyとかしてあげれば毎回 -i オプションを入れなくともアクセスできるようになります。
ここまでは基本。

では192.168.0.1はただの踏み台で、ここを経由して他のサーバーにアクセスしたい場合はどうしましょうか?

多くの場合は次のように ProxyComannd をかけてアクセスするでしょう(192.168.0.3にアクセスすることを仮定)

ssh -i ~/.ssh/ssh_my_key -o ProxyCommand='ssh -i ~/.ssh/ssh_my_key mochisuna@192.168.0.1 -p 2222 -W %h:%p' mochisuna@192.168.0.3

内容的には-oオプションで踏み台サーバーにsshするコマンドを実行してから改めて目的のサーバーを叩くというようなことをやっているというもので、記法に慣れれば難しくないし便利です。

ただこのケース「ちょっと目的のサーバーにアクセスする」くらいならいいんですが、アクセス先のサーバーが増えてくると、管理・タイピング共にとても大変になってきます。
そこで .ssh/config を活用してアクセスします。

~/.ssh/configをカスタマイズしてアクセスする

~/.ssh/configにサーバーの情報を記載することでアクセス先の管理を大幅に簡略化できます。

~/.ssh/config
Host step
  User         mochisuna
  HostName     192.168.0.1
  IdentityFile ~/.ssh/ssh_my_key
  Port         2222

Host web1
  User         mochisuna
  HostName     192.168.0.3
  IdentityFile ~/.ssh/ssh_my_key
  ProxyCommand ssh mochisuna@192.168.0.1 -p 2222 -W %h:%p

Host web2
  User         mochisuna
  HostName     192.168.0.5
  IdentityFile ~/.ssh/ssh_my_key
  ProxyCommand ssh mochisuna@192.168.0.1 -p 2222 -W %h:%p

このようにsshコマンドで記述するパラメータを構造体のような形で書いてあげることで、ssh web2のような簡単なコマンドだけでアクセスできるようになります。
自動的に定義したパラメータで置換してアクセスしてくれるわけですね。便利ー。

ただ、この書き方はあまり良くありません

例えば毎週stepサーバーのIPが変わるような仕組みが取られていると、毎回書き直すのに絶望することになります。・・・まぁそんな設定入れることはないだろうけど、要は起点のIPが変わると保守が大変ということです。

なので以下のように書き換えます。

~/.ssh/config
Host step
  User         mochisuna
  HostName     192.168.0.1
  IdentityFile ~/.ssh/ssh_my_key
  Port         2222

Host web1
  User         mochisuna
  HostName     192.168.0.3
  IdentityFile ~/.ssh/ssh_my_key
  ProxyCommand ssh step -W %h:%p

Host web2
  User         mochisuna
  HostName     192.168.0.5
  IdentityFile ~/.ssh/ssh_my_key
  ProxyCommand ssh step -W %h:%p

こうすればstepサーバーの内容をいい感じに補填してくれるようになるので、stepサーバーのIP設定を変えるだけでssh web2のでアクセスできるようになります。
超便利。

ただ、僕は複数のプロジェクトに関わっているため、全てのプロジェクト設定を~/.ssh/configに盲目的に入れていくと大変なことになります。
stepだけだと、どのプロジェクトのどこのサーバーに行くかわかったもんじゃないのです。
そこでssh_configというようなファイルをプロジェクト毎に定義します。
そしてssh -F sugoi-project/ssh_config web1のように指定してあげれば、任意の定義ファイルでアクセスができるようになる・・・ハズですが、実はそのままではやろうとすると ssh: Could not resolve hostname が出てアクセスできません。
ファイルの記載をさらに改造しましょう。

(2023/05/12追記)
@fumiyasさんからこういうアプローチがあるというご意見いただきました。

プロジェクト毎に接頭辞をつけることで補完が効くようになって便利という話

確かにこれは賢い。

ProxyJumpを使って踏み台サーバー経由でアクセスする

本題です
~/.ssh/configの汚染を避けるためsugoi-projectプロジェクト配下のssh_configのというファイル(~/.ssh/configと同じ記法)を利用することを前提にします。
この時、HOSTの記載がProxyCommand ssh step -p 2222 -W %h:%p のように記載されていた場合ssh -F sugoi-project/ssh_config web1 のようにしても以下のようなエラーが出てアクセスできないかと思います。

$ ssh -F sugoi-project/ssh_config
ssh: Could not resolve hostname step: nodename nor servname provided, or not known
kex_exchange_identification: Connection closed by remote host

これはProxyCommandが実行される際にsshのプロセスには「sugoi-project/ssh_configファイルからサーバー設定を読み取った」という情報が渡されることがないため ~/.ssh/configの中からstepサーバー情報を探してしまうことが原因です。
そこでProxyJumpを利用した形に書き換えます(OpenSSH 7.3以降に限り)

Host step
  User         mochisuna
  HostName     192.168.0.1
  IdentityFile ~/.ssh/ssh_my_key
  Port         2222

Host web1
  User         mochisuna
  HostName     192.168.0.3
  IdentityFile ~/.ssh/ssh_my_key
  ProxyJump    step

Host web2
  User         mochisuna
  HostName     192.168.0.5
  IdentityFile ~/.ssh/ssh_my_key
  ProxyJump    step

このように定義してあげることでssh -F sugoi-project/ssh_config web2というような形でアクセスできるようになります。
僕はさらに手を抜いてsshcとかいう適当なコマンドでアクセスできる仕組みを作ってます
sshc ssh_configって打つだけでほぼ脳死でアクセスできるのでオススメです。

グループにしてコピペを減らす(2023/05/12追記)

これまでの方法ですでにある程度便利になったのですが、物事は突き詰めたくなるものです。
例えば、特定のグループ毎に同じユーザー名やポート番号を利用したいケースの場合では、上述の方法でも何度もコピペが発生しファイルの巨大化や管理の面倒さなどが発生してしまいます。
そこで、これまでの条件に以下のようにケースを追加して考えたいと思います。

  • ユーザー名やポートは特定の機能毎に同じものが利用される
    • アプリケーションサーバー(app1 ~ app4)
    • NTPサーバー(ntp1 ~ ntp3)
    • NMSサーバー(nms1 ~ nms2)
    • syslogサーバー(syslog)

このような場合、以下の書き換えてあげることで記述事項の使い回しができるようになります。

Host app1
  HostName     192.168.0.1
Host app2
  HostName     192.168.0.2
Host app3
  HostName     192.168.0.3
Host app4
  HostName     192.168.0.4

Host ntp1
  HostName     192.168.2.1
Host ntp2
  HostName     192.168.2.2
Host ntp3
  HostName     192.168.2.3

Host nms1
  HostName     192.168.0.15
Host nms2
  HostName     192.168.0.16

Host syslog
  HostName     192.168.1.123
  User         logger
  Port         12322

Host app?
  User         ubuntu
  Port         2022
  IdentityFile ~/.ssh/ssh_app

Host nms?
  User         centos
  Port         2222

Host ntp?
  User         rocky
  Port         1022

Host *
  IdentityFile ~/.ssh/ssh_default
  ProxyJump    step

よく見ると app?nms? のように定義済みのホストを参照した記述と * のように、いかにもワイルドカードな記述があるのがわかるかと思います。
このように記述すると

  • app1 ~ app4はIPは各々のものを利用し、それ以外はユーザー名: ubuntu 、Port: 2022 、IdentityFile: ~/.ssh/ssh_app を利用する
  • nms、 ntpなどもappと同様にそれぞれのユーザー名とPortを利用するが、デフォルトとして ~/.ssh/ssh_default を利用する

という処理が実行されるようになります。
規模が大きくなってくる場合は共通化・一般化してあげるようと便利そうですね。

まとめ

  1. ssh-add 使うとsshコマンドの-iオプションを省略できるけど、それやるくらいなら.ssh/configを利用したほうが楽
  2. ProxyCommandを使うなら外部ファイルではなく~/.ssh/configで使う
  3. ProxyCommandProxyJumpは定義済のHost情報を利用できるのでIPとかはベタ書きしない
  4. ProxyJumpを使えば sshコマンドの-Fオプションでも定義済Host情報を使えるので便利

stackoverflowでもちょくちょく上がる内容ぽいので、知っておくと便利かもしれません。

11
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13