はじめに
ここではリモートAPIの提供方法について、簡単なやり方がないか調査した内容を記載します。下記の記事を読んでSSHでのリモートAPI提供に感化されたのが始まりです。
SSHでのリモートAPI提供の実装例は下記です。作ってみた結果、うまくやればかなり短期間でリモートAPI(のプロトタイプ)を提供できるのではないかと思いました。
SSHでのリモートAPI提供のメリット
主に下記のメリットがあると思います。
- SSHの認証+セキュア通信の枠組みでAPIを提供できる
- リーン的な開発で、MVPのコンセプト検証に素早く取り掛かれる
- 性能要件などは一旦置いておいて
- 僕のような流行に疎い人でも簡単に実装できる
(パスワード認証だと逐一パスワードの入力が手間かもしれませんが)
公開鍵認証やシングルサインオンなどでSSHログインする仕組みがあれば素早くリモートAPIを提供できると思います。
ただ、多数のリクエストを受け付けたり長期運用したりするのは向かないかもしれません。
API呼び出しイメージ
利用側からはsshコマンドの引数でAPIの引数を与えてレスポンスを得ます。
- SSHの認証の結果によりユーザーごとに異なるレスポンスも可能
- テキスト形式だけでなくバイナリを返すことも可能
$ ssh -p 16039 usr1@rest-sshd-host GET text
→ user1 file.
$ ssh -p 16039 usr2@rest-sshd-host GET text
→ user2 file
$ ssh -p 16039 usr2@rest-sshd-host GET image > grp2-copy.jpg
### ==> then image can be opened
実現方法
下記のようにしてAPIサービスを立ち上げることで、SSHによるリモートAPIが提供できます。
sshd_configの設定(ForceCommand)
SSHログインを契機として適切なレスポンスを返すために、sshdの設定ファイル(sshd_config)の ForceCommand
を設定してあげます。
# in sshd_config (may be copied to another file)
ForceCommand sh /opt/rest-sshd/example/handler.sh
ForceCommand
の設定により、クライアントの指定したコマンドを無視して設定したコマンドを実行できます。ここで自作のプログラムを指定することで、SSHログインに対して様々なレスポンスが可能になります。
また、ログインユーザーがAPI呼び出し以外のこと(通常のSSHログインだったらできるようなこと)を実行するのを防ぐことができます。
引数の取得
もともとSSHで渡された引数は $SSH_ORIGINAL_COMMAND
に入っているので、これをForceCommandに指定したプログラム内で使用します。シェルスクリプトのプログラムから使う場合は、配列に直したり set
コマンドで引数の置き換えをしたりします。
args=(${SSH_ORIGINAL_COMMAND})
filetype=${args[1]}
新規にsshd起動
既存のsshdサービスと競合しないポートで待ち受けるようにしてAPIサービスを立ち上げることで、管理者のSSHログインも可能となります:
$ sudo /usr/sbin/sshd -p 16039 -f /opt/rest-sshd/rest_sshd_config
このとき、PIDファイルが競合しないようにsshd_configファイルの設定を変えておく必要があるかもしれません。
# in sshd_config (may be copied to another file)
PidFile /tmp/my-sshd.pid