AWSでJupyterHub (HTTPS化)


概要
全体概要は， [AWSでJupyterHub (概要)](https://qiita.com/ryouka0122/items/af5004d17e0ac934e550) にあるので，参照してください．

今回は，前回のHTTP接続を，HTTPS化させようと思います．
また，セキュリティ的な絡みでWAFを少しやってみようと思います．
今回も例によって，画像を使った説明を多用しましたため眺めの記事となっております．

# おしながき
* ACMで証明書の発行
* ALBに証明書を追加
* ALB用にWAFを作成
* ALBﾆWAFを追加

# ACMで証明書の発行
さっそく，証明書を発行していきます．
まず，ACM(Amazon Certificate Manager)に行きます．
ここでは，各種証明書を一元管理できるようになっています．
パブリック証明書は無料で利用することができます．

![ACM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/a2cf6eda-0a48-4980-8915-6d592e70dfee.png)
この画像は，証明書3つある状態です．一番上は【使用中？】の項目が`いいえ`になっているので，どこからも使われていない状態になっています．逆にほかの2つは使われているということになります．
【証明書のリクエスト】のボタンを押して，証明書を作成します．
割と簡単に作成することが出来ます．
手順は
1. 「パブリック証明書」を選択
2. 前回Route53で登録したドメインを入力
3. 「DNSの検証」を選択
4. タグは何も触らず進む
5. 確認したら【確認とリクエスト】を押す
6. 検証中にRoute53にレコード追加

レコード追加は，以下の画像のように，ドメインの横にある▼を押して項目を開きます．開いた中に【Route53でのレコード作成】を押すだけです．追加先は，ドメインと同じホストゾーンになります．
![レコード追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/19549f89-0eaa-d41e-b24c-c5da839c9751.png)

# ALBに証明書を追加
出来上がった証明書をALBに追加していきます．
EC2のロードバランサーの画面に行き，前回作成したALBを選びます．
選んだら，以下の画像のように，リスナータブを選択し，HTTPのリスナーを選択します．
そうすると【編集】ボタンが活性化するので，押します．
![ALBに追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/059cdcab-2a6d-e24d-d11d-4716381ad2fa.png)

前回，HTTPプロトコルでALBを作成したため，リスナーがHTTPになっています．
以下の画像にある順番にHTTPSに変更，証明書の指定，更新，と操作していきます．
![証明書追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/38905672-3679-1103-6ff2-2e1e61d26122.png)

問題なく処理が出来れば，ボタンの横に「正常に変更されました」とメッセージが表示されます．

## セキュリティグループの変更
このままでは，HTTPSの接続がうまくいかないです．
前回のALBの作成時に新規追加したセキュリティグループはHTTPのみ設定しているので，HTTPS接続は弾かれてしまいます．
なので，HTTPからHTTPSに開放プロトコルを変更します．
セキュリティグループの一覧にいき，以下の順番で編集ダイアログを表示させます．
![HTTPS解放.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/7b382ac9-a3a3-f7da-0125-12bc97c899e9.png)
表示されたダイアログには2つレコードが出ていて，【タイプ】が`HTTP`となっています．
プルダウンメニューから`HTTPS`を選んで，【保存】ボタンを押します．
これで，許可される接続がHTTPからHTTPSに切り替わりました．

この状態で，前回アクセスした`http://{Route53に登録したドメイン}/hub/`にアクセスするとHTTPは許可していないため拒否されます．

かわりに`https://{Route53に登録したドメイン}/hub/`にアクセスすると以下の画像のように証明書が利いた状態でHTTPS接続が出来ていることが分かります．それまで出ていた，HTTP接続のワーニングメッセージも消えているのが分かります．
![名称未設定 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/161bdf90-ac36-de4a-9b5b-4bf3c8f9c5e0.png)

# ALB用にWAFを作成
次に，簡単なWAFを作っていきます．
IPアドレスやURLをベースにしてもいいのですが，今回は地域(geometory)を指定したものにします．
許可対象は，日本ということにします．（逆に日本を拒否とかできますが．．．）
気付いたら，新しくなっていたようなので，そちらを使ってみようと思います，

まず，以下の手順でweb ACL作成画面に遷移します．
まだ日本語対応していないようなので，UIがすべて英語になっています．（2019/12/13段階）
![newWAF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/3f86acf1-121a-65d9-acb6-3fc61ba4bdfd.png)

【Create web ACL】ボタンを押すと，以下のような画面が出てくるので，各項目に入力します．
`Name`と`Resource type`と`Region`にそれぞれ入力します．
`Name`は，管理用の名前です．わかりやすい名前を付けましょう．
CloudWatchにログを送ることが出来るため，自動的にCloudWatch用メトリクス名も入力されます．
`Resource Type`は今回ALBにつけたいので，`Regional resources`を選びます．
`Region`は，東京を選びます．
![create1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/f0e929f4-46cd-3417-0728-d9b48e9d7931.png)

次に関連するリソースの指定になります．
【Add AWS resources】を選んで以下のようなダイアログを表示させます．
そしてリソースはALBなので`Application load balancer`を選択して，前回作成したALBを選択します．
入力したら【Add】ボタンを押して，`Associated AWS resources`の一覧に追加させます．
追加が確認出来たら，【Next】ボタンを押します．
![selectALB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/f097b5fd-ba41-034f-bf16-6c576433d20f.png)

次は，アクセス時に適用させるルールを作っていきます．
「もしｘｘｘだったら～～～する」という感じでルールを組み立てていきます．
今回は「もし**日本からのアクセス**だったら**許可**する」という感じになります．
ルールの確認できるのかというと，ちょくちょく国外からのアクセスが確認できるので，IPアドレスやヘッダなどのルールよりも個人的に感動しました．

ということで，`Rules`の【Add rules】から`Add my own rules and rule groups`を選びます．
![addRule.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/b923832f-d326-a2da-20e5-ba0c8e84acc0.png)

では，ルールを作っていきます．
【Rule Builder】を選んで，`Name`に分かりやすく名前を決めます．今回は適当に`Japan`としました．
![rule1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/5f2d75f9-74fe-5be7-bee9-84960b7c6110.png)

次は，ルールを設定します．
先ほどの「もし**日本からのアクセス**だったら**許可**する」という部分です．
`Statement`に条件を指定します．**日本からのアクセス**というのは地域指定となるため，`Inspect`と`Country codes`を画像のように選択します．
そして，`Then`には，`Statement`の条件を満たしたときの動作を指定します．当然**許可**としたいので，`Allow`を選択します．
設定出来たら【Add rule】ボタンを押します．
![rule2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/57a7a564-bd7f-9cb3-97c4-3689f2c09881.png)


前の画面に戻ってくるので，作り立てのルールにチェックします．
そして，下のほうにある`Default web ACL action for requests that don't match any rules` を`Block`にします．
これは，すべてのルールに該当しないリクエストの動作を決める項目になります．ルールを許可形式にすることで，ホワイトリスト形式のACLが出来上がります．
出来たら，【Next】ボタンを押します．
![rule3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/e1538198-5a20-6d3f-e9b4-9ef90de1d7ad.png)

次の画面は，ルールの優先順なのですが，今回は１つだけのため，スルーします．
さらに次には，CloudWatchに連携するときのルールごとの名称を決められるようです．ここもルールが1つですので，そのままにしておきます．
そしたら，`Review and create web ACL`という画面にたどり着きます．
ここまで来たら，今までの設定を確認して問題なければ，【Create web ACL】ボタンを押します．
このボタン押すと，非活性状態になって，しばらく何も起きなくなります．（めっちゃ焦りました）

そのうち，最初の`Web ACLs`の画面に戻ってきて一覧にACLが追加されます．

ここで作ったACLは，ロードバランサーの【総合サービス】の`AWS WAF`には連動していないようです．（まだ対応してないのかな？）
でも，CloudWatchのACLログとロードバランサーのモニタリングを確認する限り連動してそうなのは確認できました．

実際に，ブラウザでF5とか何かでJupyterHubに連続してリクエストを投げるとわかると思います．
以上で，WAF周りの設定が完了となります．
あとは同じようにルールを拡張したり，CloudWatchログからSNSなりに連携することもできます．（ワーニングを出すなど）


# まとめ
今回は，セキュリティ周りとして，HTTPS接続に切り替えました．やっぱり，コードを通信しているので心配しますよね．
また，セキュリティグループを絞ればいいのですが，せっかくなのでALBにWAFを追加しました．
WAF自体新しくなっていたので，そちらを使ってACLを作りALBとつなげました．


# 総括して
今回，お題を設定して，自分なりに課題を見つけ，構成を考えて，分からないなりにもAWS上で環境を作ってみました．
dockerとかあるようなのですが，やはり最初は試行錯誤しながら自力で組み立ててみたかったので，全部自分で決めていきました．
「なんでつながらないの？」って数日考えたり，「JupyterHubでSudoSpawnerが機能しないのはなぜなのか？」で仕事が終わってからひたすら考えたり，疲れましたけど割と楽しかったですね．普段触らないような部分を直接いじることになるのでいい勉強になりました．

また，別のお題を立てて，今回のような複数回に分けて記事にするのも良いかな，と思います．
初めのほうから記事を読んでいただいた方々，つたない文章だったかもしれませんが，読んでいただきありがとうございました．
すこしでも参考になっていただけたら幸いです．