2020年6月16日火曜日

リモートのサーバに対してリモートからコマンドを発行させる方法を考える

概要

リモートから外部のサーバに対してコマンドを発行する方法をいろいろと考えてみました
要するにわざわざリモートサーバにログインしてコマンドを発行しなくて済むような方法を考えてみます

環境

  • macOS 10.15.5 (client)
  • Ubuntu 16.04 (server)
    • golang 1.14.4

ノンパス ssh を使う方法

一番オーソドックスな方法かなと思います
ログインする側で公開鍵を作成します
作成のパスワードは空にします

  • ssh-keygen -t rsa
  • cat ~/.ssh/id_rsa.pub

生成された pub ファイルをログイン対象のサーバの authorized_keys に登録します

  • vim ~/.ssh/authorized_keys

これで ssh 経由でコマンドを発行できます

  • ssh vagrant@192.168.100.10 sudo gitlab-ctl status

また対象のサーバに対してダイレクトに実行するのが嫌だという場合は途中にプロキシなどを挟んで netcat 越しに実行しても良いと思います

メリット/デメリット

メリットは ssh なので暗号化はされています
また ssh 自体かなり使われている技術なので導入障壁は低いかなと思います
デメリットしてはサーバの ssh ポートを外部から LISTEN しておく必要があります
IP でアクセス制御したり ssh するユーザをある程度絞る必要があります

shell2http を使う

shell2http は登録したコマンドを http 経由で発行することができる Golang 製のツールです
Ubuntu へのインストールは以下のように行います

  • snap install shell2http

ただ一部権限がなく動作しないコマンドがあるようなので github にあるバイナリファイルを使いましょう (参考)

  • go get -u github.com/msoap/shell2http

例えば gitlab-ctl status というコマンドを /status のパスでコールするには以下のようにします

  • shell2http /status "gitlab-ctl status"
  • curl 192.168.100.10:8080/status

こんな感じで :8080/status にリクエストするとコマンドの実行結果が返ってきます
LISTEN させるポートや動作させるシェルなどオプションで様々な指定が可能です
--add-exit を指定すると /exit にアクセスした際に shell2http のプロセス自体を kill してくれます

  • shell2http --shell bash --port 8888 --add-exit /status "gitlab-ctl status"

--form オプションを使えばパラメータを受け取ることもできます
コマンド部分はシングルクォートで囲う必要があるので注意してください

  • shell2http--form /status 'gitlab-ctl $v_cmd'
  • curl "192.168.100.10:8080/status?cmd=status"

こんな感じでサブコマンドを変数にすると便利です

メリット/デメリット

メリットは ssh/22 をオープンしなくて良い点です
代わりに 8080 ポートをオープンしましょう
あとは curl なり HTTP プロトコルを使ってコマンドを実行できます
ssh 同様コマンドの結果はそのまま返ってくるのでパースなどは自分でやる必要があります

デメリットは shell2http のプロセス管理をする必要がある点です
また golang のインストールも必要になるので作業手順も若干増えます
暗号化に関してはオプションで証明書を指定可能なので https を使うことで通信を暗号化できます

Tips: No such file or directory や Cannot access などのエラーが出る場合

おそらく snap などでインストールしているのが原因です
go get を使って github から最新版を入手してください

その他案

その他使えそうな技術をピックアップしてみました

chef や ansible のプロビジョニングツールを使う

というのがモダンで良いとは思うのですが結局プロビジョニング対象のサーバに対して ssh できる必要があります
管理的なコストを考えるとソースに落とせるのでそれだけでメリットはありますが学習コストなどは増えてしまいます

クラウドサービスを使う

例えば GCP には gcloud コマンドという CLI が付属しておりこれをつかうことで簡単にリモートからコマンドを発行することができます
内部的には ssh を使っているのでプロトコル的には同じなのですがファイアウォールの設定やインスタンスの設定をしないで済むのは嬉しい点かなと思います

また AWS には AWS System Manager というサービスがありこれは画面からコマンドを実行することもできるのでかなり理想に近い感じはします
ちなみに SSM エージェントと呼ばれるエージェントをインストール必要がありこれはソースも公開されています

自作する

あとは気に入ったものがなかったり要件を満たさない場合には自作するしかないと思います
自作であればプロトコルやインタフェースは自由に選べるしエージェントを使って pull 側の仕組みを作ったりすることもできます

ですが当然開発コストやノウハウがそれなりに必要にはなるので障壁は一番高いかなと思います

最後に

リモートのサーバに対してログインせずにコマンドを実行する方法を考えてみました
over HTTP でコマンドを実行する方法は他にもいろいろとありそうだったので興味があれば調べてみてください

AWS のようにエージェント形式で気軽に使えるツールはあまりないようでやはりエージェント形式の場合はサーバも必須になるので構成も複雑になるかなと思います

0 件のコメント:

コメントを投稿