ELBでssl転送してnginxでクライアント認証とssl終端してProxyProtocolで送信元IPを取得する

こんにちは。
タイトル長いですがだいたい成功して時がたったので需要があるかはわかりませんが記録しておきます。

お時間あるときにどうぞ。

目的としては、以下のとおりです
外部ELB→nginx(ssl終端かつクライアント認証)→内部ELB→app

つまり、クライアント認証したいけどELBにその機能はないのでtcp443転送してnginxでやるが上位サーバでとれる送信元IPがELBのIPになってしまう為
ELBでProxyProtocolを有効化してnginxでssl終端しつつProxyProtocolをListenして送信元IPをログに出したいという話です。

securityGroupやインスタンス作るなどの部分は省略します。

1.elbをawscliで作成、proxy-protocol設定

参考:

AWS ELBのProxy Protocolを触ってみた
Enable or Disable Proxy Protocol Support – Elastic Load Balancing
今更 VPC で 複数の AZ をまたいだ ELB を試す(2)〜 awscli を使って 〜 – ようへいの日々精進 XP

・elb作成

※外部ELBはTCP443からTCP443に転送するだけで証明書を入れない感じの設定にします

・helthcheck設定

・インスタンス登録

・プロキシプロトコル有効化

ポリシーを作成する

ポリシーを確認する

無効にする場合は、--policy-names [] という空の指定をすると無効になります

プロキシプロトコルが有効になっていることを確認する

2.nginxの設定について

chefでばらまいてますが細かいことは省略しまして、関係する設定内容だけのせます。
proxy-protocol設定反映はreloadではなくrestartする必要があるのでログイン確認の際にnginxのrestartを実施する必要があります。

参考:

Using Proxy Protocol With Nginx | chris lea
Module ngx_http_realip_module
#355(プロキシのプロトコルサポート) – nginx

実際のnginxの設定ファイル

(成功当時のバージョンは1.7.4-1です)

$remote_addrでなく$proxy_protocol_addrに変更
※関係あるところだけ抜粋(http_x_sessionkeyなどマスタリングNginxからのコピペですが余計であれば外してください)

※上記のうちProxyProtocol関係あるディレクティブは、以下のとおりです
listen
set_real_ip_from
real_ip_header

※<%= .. %>で囲んであるところはアトリビュート(変数)になっていて
 chefレシピ実行時に設定しておいた値に差し替えられ、実際の値とは異なりますのでお察しください。
 @の変数はroleとenvironmentで吸収しきれずdata_bagsから引っ張ってきたりなど。
set_real_ip_from は、vpcのセグメントアドレス(例:10.0.0.0/17)を指定してます。
 ELBの実際のアドレスを書いとく必要があるけども特定できないし自動で振られるため。
ssl_crl(破棄証明リスト)コメントにしてるのは、無期限的な事情によります。

※※ProxyProtocolを解釈できるバージョンは1.5.12以上です。それ以下はconfigtestでエラーでます。
※※1.4系で--with-proxy-protocolをつけてソースからビルドする必要は全然ありませんし、
 1.7ですが特にビルドしたりせず素のパッケージをつかって実現できました。
※upstreamやめてresolver 追加しました。
 nginxの名前解決はマスタリングNginxのP94みたらsetで変数に入れると毎回名前解決し、
 それ以外resolverのvaridで指定したttlのタイミングで聞きに行くそうです。
 upstreamと*_passで指定した名前を解決するのは最初の一回だけでresolver必要だそう。

nginxの1.7系(mainlineのやつ)を入れるためのyumリポジトリ

中身は以下のような感じです。
chef的にはepelから入るのを防ぐoptions "--disablerepo=epel"をpackageリソースに書く必要があったりなど。

3.アクセスログの送信元IPを確認する

ログイン

確認

elbに追加後にInServiceになったらブラウザからアクセスしてログを確認

こんな感じに接続元のグローバルIPが出ていたのでProxyProtocol的には成功のようです。
クライアント認証のことはここではこれ以上のことは触れられませんがあしからずご了承ください。

個人的に苦労したのは記事中にリンクのってるchris leaさんのページに書いてあるとおりにやればいいだけというのを理解するまでの紆余曲折と
ELBのプロトコルの指定が間違ってたところですかね。合わせて解説してる記事は特に見つからなかったので書いてみました。
nginxユーザー会のイベントで開発者のイゴールさんがSSLつかうなら新しいバージョンを推奨していた意味の一部分を身を以て知ったのでした。
特定デバイスからかぎっ子したい時に役立つかもしれません。

では読んでいただいてありがとうございました。どなたかの役に立ったら嬉しいです。

おすすめ記事