続 カッコの付け方

AWSを始めとしたクラウドコンピューティング全般と、唯一神emacsにおける()の付け方についてだらだら書きます

sshで手元のコードをサーバ上で動かす(proxychains-ng)

インフラ屋を辞めたので、それなりにコードを書いて走らせる機会が増えました。ローカル上のコードをぱっとサーバ上で動かしたい場合の解決方法を書きます。

tl;dr

  • ssh のポートフォワーディング(ローカルフォワード)には、フォワード先のポートを動的(不定)にするモードあり -D
  • httpには http_proxy環境変数があるが、socks5にはそれほど汎用的なものが無い、特に非http。それをプロセスを1枚かぶせる事によって socks5経由に曲げる proxychain4
  • http proxyが proxyするのはあくまで httpだけ、dnsへの問い合わせなどは、proxy経由とならないが、それすらproxy経由にできる。特にAWSの route53 private hosted zone などを使っているときに効果絶大。

Trampですか?

TRAMP (Transparent Remote Access, Multiple Protocols) emacsサーバー上のファイルをローカルのemacsで編集するものです。 大昔から存在するもので、あくまで emacsでの名称ですが、sublimeでもやっている人がいたので、他のeditorでも実現できるはず。

ただ、これだけローカル開発dockerでテスト&しょっちゅう自動デプロイの時代にサーバー上のファイルを直接いじるってどうなの? インフラ屋だってサーバ上の設定ファイルを直接いじんなって言われてるのに。

というふうに、今もまだ使えるし・使っている人も居ると思うが、時代の流れ的に、もはや多数派にとっても不要なものだとおもう。

ポートフォワードですか?

はい、ポートフォワードです。が、一般的なローカルフォワードだとDNSまで曲げることはできません。それと1本1本接続先を貼ることになるので、そのアプリが触る他のサーバ(DBとか)が1個ならそれほどでもですが、複数なら大変です。

それと、何より面倒なのはローカルフォワードは個人でバインドするポートを色々買えていると思うので、環境変数とかで抽象化して、チームメンバ全員で一致させるのも結構大変やとおもいます。

能書きはこれぐらいで、ズバリどうやるかといえば ssh -D です。sockサーバとして動かすという手法です。ここまでなら結構知名度あるはず

Poor man's VPN via ssh socks proxy

ssh -D と tsocks — 京大マイコンクラブ (KMC)

本題 proxychains-ng について

上記のリンクを見てもらえば解ると思いますが、WebブラウザとかはSock5を通すことができるので楽勝ですが、ブラウザ以外で通すとなると、基本的にアプリ側の実装でSock5を通す設定を作っておく必要が有ります。 早い話、ブラウザ以外でsock5を通すのは自作プログラムしかほぼ無いとなります。

そこでproxychains-ng です。

github.com

その手の界隈では有名だったらしいですが、しばらく更新は途絶えていて Next? Generation として作られたらしい、コマンドは proxychains4 先に上げたとおりDNSも曲げます。

インストールとか設定とか

macなら brewで入ります。Linuxもだいたいパッケージで入りますが、 stretchはちょっとバージョンが古いので、ソースからビルドします。依存がほとんどないので、説明しません。(あとでdockerイメージ晒します)

設定も楽勝です。

strict_chain
proxy_dns 
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000

[ProxyList]
socks5  127.0.0.1 1080

重要な点は最後のIPアドレスとポートです。この場合はsshで立てるsocks5の穴は1080でListenしていることが前提です。 つまり、ssh <host> -D 1080

使い方

proxychains4 curl ifconfig.meとかで使います。 打ちたいコマンドの頭に proxychains4 と書くだけでOK

http-client以外で試してみる

http通信ならブラウザで方がつくので、ほとんどの人がやりたいのはこっちのはず。例えばmysqlとかなら proxychains4 mysql -u <user> -h <ssh接続先絡みたFQDN> -p のような感じで単純に前に proxychains4と入れて呼び出します。これだけでOK

macの場合はbrewのバイナリに注意

ライブラリアクセスに割り込んで、接続先を曲げるという方法を取っているので、brew由来でないものを、brewのproxychainsで曲げることはできないです。ズバリのパターンは rbenvとかでmac上でソースビルドしたrubyとかは通りません。

マニアックなのだとubuntuのsnapとかも無理です。Windowsは知りませんが、msysでビルドしたものを別経由でビルドしたproxychainsで通すことはできないでしょう。ともかく動かそうとするアプリのバイナリと、proxychainsのバイナリが同じシステム(厳格な意味で)に居ないとだめです。

dockerで使うには

同一システムにproxychainsと実行したいバイナリを載せる = コンテナ分離はできないとなります。sshは分離可能で、ホストのsshを使う方法とssh-clientだけ分離する方法があります。ssh-client, proxychains, 対象アプリを全部1コンテナに突っ込む方法もありはありです。 まとめて3パターン

  • 全部1コンテナに突っ込む
  • proxychains + 対象アプリ で1コンテナ、ssh-clientで1コンテナ でコンテナ間通信
  • proxychains + 対象アプリ で1コンテナ、ssh-clientはホストのものをつかう

proxychains install

debianベースはbusterからはaptで普通に入ります。stretchはとりあえずビルドしたバイナリが入ったのを晒します。マルチステージビルドとかで適当につかってください。/usr/localとかに入っているはず https://hub.docker.com/repository/docker/himaoka/proxychains-ng/general

alpineもapkで普通に入ります。

設定・というよりホストのさし方

設定ファイルは上の方で書いたのとほぼ同じですが、コンテナの中からみたホストのIPアドレスmac固有の問題、そしてsshのローカル側Listenに考慮が必要です。 まず -D だけでsshでトンネル貼ると、127.0.0.1のみListenします。このままだとコンテナから/コンテナ間では突けないので、 手っ取り早く0.0.0.0 でListenする

続いてコンテナからのさし方は、Linuxの場合はホストのIPアドレスか、コンテナ内絡みたGatewayになります。Macの場合は192.168.65.2あたりになるはず、調べてください。
コンテナ間通信するなら、ssh-clientを名前解決で指せるのでここは楽勝。
1コンテナで攻めるならそもそも127.0.0.1のlistenで問題なし。

走らせ方とか

ソースコードの差し替えはバインドマウントでやります。 docker-compose使っていると思うので docker-compose exec <service> bash とかで入って泥臭くコマンド叩きます(いてます)。

AWSでの利用

AWSで使う場合は、いやGCEでも、もっと強烈な利用価値があります。感のいい人ならわかるかもしれないですが、この方法を使うとEC2ロールを今から走らせようとしているローカルのソースに踏襲できます。また、さらにprivate hosted zone は ECSのサービスディスカバリにも使われているので色々捗るはず。