ikasama over technology

忘れたくないことを忘れないために

踏み台サーバ経由でいろいろ (Web, Git, MySQL) アクセスしたい

社外から社内システムに接続しようと奮闘した記録です。 以下の前提でやっていきます。

  • エンドポイントは変えない
    • アプリケーションに手を入れなくて良い
    • ブラウザのブックマークなどがそのまま使える
  • Windows + Git Bash + Docker

Web アクセスしたい

使うものは以下。

  • SSH トンネリング (ダイナミックポートフォワード)
  • プロキシの自動構成

1. トンネルを掘る

ssh stepserver -f -N -D 1080
  • -f: バックグラウンドで実行
  • -N: コマンドを実行しない
  • -D 1080: ダイナミックポートフォワード。localhost:1080 に SOCKS プロキシをたてる。

これでlocalhost:1080 にプロキシとしてアクセスすると、stepserver 経由で通信ができます。

2. プロキシの設定

まずはプロキシの自動構成スクリプト (proxy.pac) を準備します。

function FindProxyForURL(url, host) {
  if (shExpMatch(host, "stg.*.example.com") || dnsDomainIs(host, "git.example.com")) {
    return "SOCKS5 localhost:1080; DIRECT";
  } else {
    return "DIRECT";
  }
}
  • 上の例はステージング環境のアプリケーションと GitLab に Web アクセスしたい場合のサンプルです。
  • stg.*.example.comgit.example.com にマッチする URL は SOCKS プロキシでアクセスし、他は直接アクセスします。
  • 細かい構文なんかは、以下を参考にすると良いです。

docs.microsoft.com

ブラウザに設定

今回は proxy.pac をローカルに置いてますが、踏み台に Web サーバを立てて、そこに置いてもいいかもしれません。

f:id:ikasamak503:20180311195200p:plain

ChromeIE とかは共通ですけど、Firefox は独自の設定です。お使いのブラウザに合わせて設定してください。

Git アクセスしたい

1. SSH でアクセスする場合

SSH フォワーディングします。

~/.ssh/config

Host stepserver
  HostName ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com
  User ec2-user
  Identityfile ~/.ssh/stepserver.pem

Host git.example.com
    HostName git.example.com
    IdentityFile ~/.ssh/git_id_rsa
    ProxyCommand ssh -W %h:%p stepserver

さっきの SOCKS プロキシを使うこともできます。その場合は ProxyCommand を書き換えます。

 ProxyCommand connect -S localhost:1080 %h %p

-S オプションで SOCKS です。

2. HTTP/HTTPS でアクセスする場合

Git にプロキシの設定をします。 SOCKS プロキシ経由でいけるはずなんですが、今回の環境だとうまく動きませんでした。 Git サーバ側の設定が関係しているかも?

$ git config --global http.proxy localhost:1080
$ git config --global https.proxy localhost:1080
$ git config --list | grep proxy
http.proxy=localhost:1080
https.proxy=localhost:1080
$ git clone http://git.example.com/ikasamak/test.git
Cloning into 'test'...
fatal: unable to access 'http://git.example.com/ikasamak/test.git/': Empty reply from server

MySQL アクセスしたい

ちょっと特殊な環境だったので、ちゃんと説明するとこんな感じです。

Windows 上 の Docker コンテナ (複数) のアプリケーションから MySQL 接続したい。

この場合、複数のコンテナからポートフォワーディングするのはしんどいし、 まずアプリケーションに手を入れたくないので、次の構成にしました。

  • Windows ホストからローカルポートフォワードする *1
  • 各コンテナ内のアプリケーションはホスト上のフォワーディングしたポートに MySQL 接続しに行く

やっていきます。

1. コンテナからアクセスするためのホスト側 IP アドレスを確認する

DockerNAT となっているものはコンテナから出てくるインタフェースなので、そこにはコンテナから繋がりません。 それ以外なら何でもいいようです。 今回は 192.168.11.2 とします。

2. トンネルを掘る

ssh stepserver -f -N -L 192.168.11.2:3306:mysql.example.com:3306
  • -L [bind_address:]port:host:hostport: ローカルポートフォワーディング
    • bind_address: ローカルで待ち受けるアドレス。0.0.0.0 にするとどこからでも受け付けるようになる。
    • port: ローカルで待ち受けるポート
    • host: 接続先のホスト。今回の場合は MySQL サーバのエンドポイント。
    • hostport: 接続先のポート。今回の場合は MySQL のデフォルトなので 3306

3. ホストの hosts で無理やり名前解決する

192.168.11.2  mysql.example.com

試しにコンテナから ping を打ってみると、ちゃんと hosts に書いた IP に飛んでいることが分かります。

$ winpty docker-compose exec db ping -c 1 mysql.example.com
PING mysql.example.com (192.168.11.2): 56 data bytes
64 bytes from 192.168.11.2: icmp_seq=0 ttl=37 time=10.231 ms
--- mysql.example.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 10.231/10.231/10.231/0.000 ms

このやり方は、Docker の DNS 設定が Automatic じゃないと出来ないかもしれません。

f:id:ikasamak503:20180312015837p:plain

4. コンテナから接続確認

$ winpty docker-compose exec db bash
root@0258fd400317:/# mysql -h mysql.example.com -u user -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 376064
Server version: 5.5.34-log MySQL Community Server (GPL) by Remi

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

これでうまくいってれば、コンテナ上のアプリケーションもうまく MySQL 接続できると思います!

まとめ

やっていることはどれもだいたい一緒です。

  1. 踏み台に SSHフォワーディング
  2. トラフィックをなんとかフォワーディング先に乗せる

ダイナミックポートフォワーディングは便利なんですが、アプリケーション側が SOCKS プロキシに対応していないと使えないのが難点です。 そこを吸収してくれるソフトウェアもあるっぽいんですが、今回はそこまで踏み込まずにやりました。

あと、Docker for Windows の情報が無さすぎて泣きそうになりました。

参考

*1:ここで SOCKS を使わないのは、アプリケーション側での対応が必要になるからです