いつものアプリケーションサーバに対して HTTPS でアクセス可能にする気軽な方法


やりたかったこと

  • 社外への AJAX 通信が必要だった
  • 先方の開発サーバで CORS (*) が設定されており、https://example.com/ の URL でブラウザからアクセスすることが必要
    • ブラウザの仕様として、Access-Control-Allow-Origin などのヘッダにより、リクエスト元の URL が限定されている
  • 開発しているアプリケーションサーバはいつも localhost:3000 で HTTP をリッスンしているが、外部に AJAX リクエストのテストもやりたい
  • あまり特別な設定ファイルなどは面倒なのでやだ

予備知識

  • HTTPS を終端した上で、HTTP として 3000番ポートに転送したい
  • この処理を実現するソフトウェアは総称して、TLS Termination Proxy という
  • TLS Termination Proxy の代表例として Apache HTTP ServerNginxPoundhitch などがある

今回での手法について

  • 前提としていつもローカルの PC で開発している
  • Pound は設定ファイルが必要でちょっと面倒。
  • hitch も良い候補だが、英語も含めてドキュメントが足りない
  • 今回はソケットを扱うときの swiss army knife である socat を利用

サーバ証明書の準備

下記の手順でサーバ証明書を準備しておく。

$ openssl genrsa -out server.key 1024 # RSA 秘密鍵の生成
$ openssl req -new -key server.key -x509 -days 3653 -out server.crt # サーバ証明書の生成。いろいろ聞かれるので答える
$ cat server.key server.crt > server.pem # 秘密鍵とサーバ証明書を連結して1つのファイルにする
$ openssl dhparam -rand - 2048 >> server.pem # DH パラメータを追記(これをしないと後でうまくいかなかった)

socat を TLS Termination Proxy として動作させる

socat とは

  • netcat を進化させたもの
  • さまざまなチャネル間を双方向にリレーできる
  • 標準入出力、フォークしたプロセスへのパイプ、UDP、TCP、SCTP、ユニックスドメインソケットなどを扱える
  • 踏み台、プロキシとかに仕込むと結構いろいろ便利なことができる
  • libev などは使っておらず、スケーラビリティは低い

コマンド例

$ sudo socat -vv openssl-listen:443,reuseaddr,fork,verify=0,cert=server.pem TCP4:localhost:3000 
  • 443 番ポートをリッスンするには sudo が必要
  • openssl-listen:443 と指定すると SSL ソケットを終端して次の処理を行える
  • fork があると繰り返し、プロキシ処理ができる。(逆につけないと1回のリクエストにだけ処理を行う)
  • verify=0 を指定すると、クライアント証明書を確認しない。
  • 転送先はローカルホスト 127.0.0.1 の 3000番ポート。

動作確認

wget で動作確認する

$ wget -d https://localhost/ --no-check-certificate -O -
  • 作ったばかりの適当な証明書なので、 --no-check-certificate をつけないと怒られる

example.com でアクセスする

あとは、単純に /etc/hosts を編集すると完成

/etc/hosts
127.0.0.1   example.com
$ wget -d https://example.com/ --no-check-certificate -O -

まとめ

  • HTTPS を終端した上で、HTTP として転送するには TLS Termination Proxy が必要
  • NginxPound などでもできるが、設定ファイルが必要で、ちと面倒
  • socat はさまざまなチャネルをリレーしたいときの swiss army knife
  • socat で HTTPS を終端し、うしろのアプリケーションサーバに転送できる
  • HAPPY HACKING!