Amazon EMR 上の WebUI群 ( Hue や Zeppelin ) をSSHトンネルなしでブラウザ表示する方法

## 概要
EMR で構築したクラスタ上の WebUI をブラウザ表示するには SSH トンネリングを利用した接続が推奨されていますが、この方法は不便が多いため、より気軽な方法を模索しました

最終的に **リバースプロキシ をおいて接続する方法** が良かったので共有します

- Amazon EMR とは 
http://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-what-is-emr.html

- Amazon EMR クラスターでホストされているウェブサイトの表示
http://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-web-interfaces.html


## 構成
検証環境 : [EMR-Release 5.2.1](http://docs.aws.amazon.com/ja_jp/emr/latest/ReleaseGuide/emr-5.2.1/emr-release-components.html)

### SSH トンネリングによる構成
 
<img src="https://qiita-image-store.s3.amazonaws.com/0/35755/360a9116-c260-8f23-4799-82cd8325e261.png" width="300px">

- この図では `master-public-dns-name` に対してインターネット経由で SSH トンネルを作成しています  
（VPN 接続がある場合は、Local Netowark 内を通します） 
- EMR Master インスタンスのある SecurityGroup で SSH のポート（デフォルト22）を接続元指定で開け、各クライアントマシンと EMR Master インスタンス間で SSH トンネルを作成して、ポートフォワーディングによってブラウザで任意のWebUIと通信を行います

#### 問題点
- 各クライアント（各個人PC）マシン上で設定が必要になる（非エンジニアでは作業負荷が高い）
- SSHで繋ぐため、クライアント(各個人PC)にEMR master への秘密鍵をばらまく必要がある（秘密鍵は隠したい）
- 都度 SSHトンネル接続＆Webブラウザアクセスの手順が面倒

Hue や Zeppelin などの分析ツールは大勢の非エンジニアが利用するケースもありえます
その場合各個人クライアントに鍵を配ったりターミナルでSSHトンネルを作成させたりする操作は煩雑でつらいものがあります


### リバースプロキシをおく構成

<img src="https://qiita-image-store.s3.amazonaws.com/0/35755/039ddda8-923e-6e60-531f-3137a86e394a.png" width="300px">

- プロキシサーバ に対してインターネット経由で接続します  
（SSHトンネルの例と同様、VPN 接続がある場合は Local Netowark 内を通します）
- EMR Master とは別インスタンスでプロキシサーバを稼動させます
- プロキシサーバまでは https、プロキシサーバから EMR master は private network 内を http で通信させます  
（個別のWebUIはSSL設定しなくて良い）
- 各クライアント（各個人PC）マシンは追加設定不要  
（ブラウザアクセスするだけでOK）

EMRとは別にプロキシサーバを構築するため追加コストがかかりますが、個別クライアントは何の設定も要らず、ブラウザアクセスするだけで、Hue や Zeppelin などお好みの WebUI を参照できるようになります


## 構築手順

### 1. リバースプロキシを配置するサーバの Security Group 設定
外部から（またはLocalNetwork内）の https リクエストを許可します
ポートは、[利用したい WebUI](http://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-web-interfaces.html) にあわせて必要な個数分開けます
（[後述](http://qiita.com/yaiwase/items/907589155d90722533dc#%E5%AF%BE%E8%B1%A1%E3%81%A8%E3%81%AA%E3%82%8B-webui-%E7%BE%A4) しますが、ドキュメントに載っていないポートが参照される場合があるので、適宜追加します）

```
タイプ    ： カスタム TCP ルール　
プロトコル ： TCP
ポート範囲 ： 8888
ソース    ： <アクセス元の Public IP （またはLocalNetwork内のアクセス元 Private IP )>
```

### 2. EMR Master の Security Group 設定
EMR Master の Security Group では、リバースプロキシ (private ip) からの http リクエストを許可します

```
タイプ    ： すべてのトラフィック
プロトコル ： すべて
ポート範囲 ： すべて
ソース    ： (Private Network のIP範囲) 
```

### 3. DNS設定
お好みのドメイン名を決め、そのドメインへのアクセスをプロキシサーバへ誘導するよう DNSレコード を設定します

```
ラベル : emr.your-site.com(管理下のお好みのドメイン名)
TTL   : 任意の時間 Time To Live
クラス : IN
タイプ : A
リソース : <リバースプロキシサーバの Public IP >
```

Route53などであれば次のような感じです（イメージ）
<img src="https://qiita-image-store.s3.amazonaws.com/0/35755/bac167e7-d08e-16e4-5311-af6c3ac4d4ac.png" width="300px">


### 4. リバースプロキシの構築
プロキシサーバ上では、特定のドメイン／ポート指定でアクセスがきた場合に、EMR Master サーバの指定ポートへ代理アクセスするよう設定します
今回は EC2 で適当なインスタンスを確保し、Nginx を使ってプロキシさせます

#### Nginx インストール
リバースプロキシを配置するサーバにNginx をインストールします
（環境にあわせて、安定動作するものを選んでセットアップします）
https://www.nginx.com/resources/wiki/start/topics/tutorials/install/


#### SSL証明書の配置
SSL証明書を配置して、Nginx で https リクエストがきた場合に参照させます
（証明書は必要に応じて入手します）

```
ls /path/to/cert/*
/path/to/cert/your-site-ssl-certificate.crt
/path/to/cert/your-site-ssl-key.pem
```

Nginx 設定例（後でまとめて書きます）

```
ssl on;
ssl_certificate     /path/to/your-site-ssl-certificate.crt;
ssl_certificate_key /path/to/your-site-ssl-key.pem;
```

#### コンテンツ書き換え
WebUI群の中には、リンクを生成する際に 自身の名前 `master-private-dns-name` を使う場合があるため、ブラウザアクセスした場合に表示されるページ内のリンクが飛べない（名前解決できない）ケースが発生します
これを回避するために、Webサーバのコンテンツ書き換え機能を使って `master-private-dns-name` を名前解決できるドメイン（先ほどDNS登録した管理下のお好みのドメイン）に書き換える処理をはさんでおくとストレスなく使えるようになります

Nginx 設定例（後でまとめて書きます）


```
sub_filter '(master-private-dns-name)' 'emr.your-site.com(管理下のお好みのドメイン名)';
sub_filter_once off;
```

#### Nginx設定
利用したいWebUIのポートに対して、それぞれプロキシ設定を追加します
この際、上記で紹介したSSL設定とコンテンツ書き換えを加えて下記のように設定します

```
/path/to/nginx/nginx.conf

# hue wabapp
server {
    listen 8888 ssl;
    server_name emr.your-site.com;
    access_log /path/to/proxy-your-site.com.access.log main;

    ssl on;
    ssl_certificate     /path/to/your-site-ssl-certificate.crt;
    ssl_certificate_key /path/to/your-site-ssl-key.pem;

    location / {
        proxy_pass http://<master-private-ip>:8888/;
        sub_filter 'ip-xx-xx-xx-xx.region.compute.internal' 'emr.your-site.com';
        sub_filter_once off;
    }
}

# 
server {
    listen 8080 ssl;
..............(同様)
}

..............(必要なポート分設定)

```

この例では 共通のドメイン `emr.your-site.com` に対して ポートごとに振り分けさせていますが、もし個別のWebUIごとに別ドメインを割り当てるほうがお好みであれば、そのように設定することももちろん可能です
（`hue.your-site.com` へのアクセスで `<master-private-ip>:8888` へ誘導する など）
ただしURLの書き換えルールが複雑になってしまうので、そのあたり検討する必要がでてきます

##### 対象となる WebUI 群

設定対象となる WebUI 群のリストは、[Amazon EMR のドキュメント](http://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-web-interfaces.html) を参照します

なお利用するWebUIによってドキュメントに載っていないポートも参照されるため、状況に応じて必要なポートを登録します
（一応個人的に必要だったものを羅列します）

| Web UI Name      | uri |
|:-----------------|:------------------------------------------------------|
| Hue | master-public-dns-name:8888/ |
| Tez UI | master-public-dns-name:8080/tez-ui/ |
| Zeppelin | master-public-dns-name:8890/ |
| Yarn Web Proxy | master-public-dns-name:20888/ |
| YARN ResourceManager | master-public-dns-name:8088/ |
| Yarn ResourceManager? | master-public-dns-name:8032/ |
| Hadoop HDFS NameNode | master-public-dns-name:50070/ |
| Yarn timeline-service Webapp | master-public-dns-name:8188/ |
| Spark HistoryServer | master-public-dns-name:18080/ |

設定を書き終えたら、Nginxのプロセスを起動させます


### 5. 動作確認
設定は以上です、実際にブラウザで 個別の WebUI を開いてみます

Hue 
http:// emr.your-site.com :8888/ 
<img src="https://qiita-image-store.s3.amazonaws.com/0/35755/a3f7fcbe-4a02-01f2-3a3c-4f187797c484.png" width="300px">


無事に個別のWebUIが開く ＆ 表示されてるリンクへ正しく遷移できれば、設定完了です！ :thumbsup:



## まとめ
Amazon EMR 上の WebUI 群へのアクセスを リバースプロキシ経由 にすることで、以下の利点が得られます

- WebUIへアクセスする **チームメンバーの負担を大幅減できる**  
（クライアントマシンの設定不要で、ブラウザアクセスですぐ使える）  
（SSHトンネル設定のように接続が切れることもない）
- **SSH秘密鍵をばらまかなくてよい**  
（余計なリスクを負わなくてよい）
- リバースプロキシで **SSL設定をまとめて行うことができる**   
（個別WebUIでSSL対応させなくてよく、設定を一元的に行える）
- コンテンツ書き換え処理によって、 **すべてのリンクをたどれるようにできる**   
（単体の WebUI でなく、複数同時に公開可能）

ぜひおためしください！


## 参考資料
- [securely-access-web-interfaces-on-amazon-emr-launched-in-a-private-subnet](https://aws.amazon.com/jp/blogs/big-data/securely-access-web-interfaces-on-amazon-emr-launched-in-a-private-subnet/)
- [emr-what-is-emr](http://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-what-is-emr.html)
- [emr-web-interfaces](http://docs.aws.amazon.com/ja_jp/emr/latest/ManagementGuide/emr-web-interfaces.html)
- [ngx_http_sub_module](http://nginx.org/en/docs/http/ngx_http_sub_module.html)