AWSで簡易なWebアプリをデプロイ ~ ネットワーク・セキュリティ編 ~

お疲れ様です．Tomです．

AWSで簡易なWebアプリをデプロイ【ネットワーク編】です．

:::note info
全体概要編は[こちら](https://qiita.com/tomtech_2024/items/fc14e5fe845b7d7d5712)をご覧ください．
:::

スタックを示した構成図でいうところの赤で囲った箇所が今回のトピックになります．

![network01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918716/1862f6eb-c4e1-7778-c604-d37d7059ae19.png)


ネットワークが一番入り組んだことをやりました．
したがって今回は詳細にはあまり触れず，「大まかにはこんだけのことをやってなんとなくインターネットにWebアプリをデプロイしたよ」というテイストにしたいと思います．

`ネットワークの目的は言うまでもなく，【サービスを提供しているサーバどうしを連動させることや不正なアクセスや意図しない挙動を防ぐこと】です．`

:::note warn
ぶっちゃけた話，今回数ヶ月前に行ったことをやっと時間が取れて書き起こすといった恰好なので，今までに比べて特に忘れてしまっており，ふわっとしているところがあります．詳細な作業は別の方の記事や公式ドキュメント，ChatGPT等をご活用ください．
:::

# 概要
やったことは以下のとおりです．

・ VPCでのサブネットの定義
・ Security GroupでサーバやデータベースのアクセスをL3,L4レベルで制御
・ Route 53にてドメインを取得し，DNSレコードの設定
・ 証明書の取得
・ ALBの構築とその証明書をALBへApply

が挙げられます．なお，インターネットゲートウェイに関してはEC2へのSSH接続などの管理用のルートとして残しました．（商用の環境でこんなことはできないので，踏み台サーバを建てるなりの工夫が必要かと思います）

今回は勉強も兼ねて，インスタンスを２台構成にして，冗長化やリクエスト処理の効率を意識してみました．

# 盛り込んだサービスと全体像

もう一度アーキテクチャを載せます．

![Screenshot from 2024-06-09 15-03-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918716/e0009b5f-d12d-2647-aa2e-d36be6219477.png)

1.**Route 53**
いわゆるドメインの取得です．想定よりもかなり簡単で驚きました．

![Screenshot from 2024-09-14 14-26-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918716/7acbc505-e091-d9b1-d256-74d17d3927d5.png)

Dashboardの`Register domain`から行います．
ドメインの入れたい文字列を入力すると在庫やそのドメインごとに異なる値段が表示されます．僕が第一希望だったドメイン名は売り切れでした．ネットで何に使われているのかを調べてみると案外面白いです．`Status`が`In progress`から`Domain registration successful`となれば取得完了です．
注意が必要なのは”Auto-renew”です．期限が来ると自動で延長してくれるようなのですが，暫定的に遊びで作るだけの人はオフにしておくと良いかと思います．
またDNSのAレコードとして`*.<作成したドメイン>`と正規表現を使用し，ドメインに特定の文字列があった際はALBのVIPを返すように設定しました．ひととおり設定が終われば，`dig`コマンドや実際にアクセスするなどで動作確認してみてください．とてもドメインを所有している感と表示される満足感があります．

```:digコマンド
$ dig www.<ドメイン名>.com

; <<>> DiG 9.18.26 <<>> www.<ドメイン名>.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17893
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;www.<ドメイン名>.com.		IN	A

;; ANSWER SECTION:
www.<ドメイン名>.com.	60	IN	A	XXX.XXX.XXX.XXX<IPアドレス>

;; Query time: 175 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Sun Jun 02 19:42:21 JST 2024
;; MSG SIZE  rcvd: 63

# Answer Sectionが返ってきていればOK
```

2.**証明書** (ACM)
`Certificate Manager`からドメインの情報をもとに，証明書を発行します．Validation methodは`DNS validation`を使用した記憶があります．Amazonが自動で署名を行ってくれ，時間もそこまでかからずに終了しました．この証明書をALBに適用することでHTTPS接続が実現します．出来上がった証明書はStatusが`Pending validation`から`Issued`になり，DNSのCNAMEレコードに追加されたはずです．
（NLBはトランスポート層で動作するので，便利ですが証明書が適用できません）

3.**Load Balancer** (EC2)
Security groupでインターネットから来る443番ポートと80番ポート向けのアクセスを受け付けていました．80番ポートにはここに来たアクセスを443番ポートにリダイレクトさせる設定を施しています．またこのとき，2で作成した証明書を`Default SSL/TLS server certificate`で選択し，適用することでHTTPS接続を実現させることができます．
```Config:Config
# Protocol:Port
HTTP:80
# Default action
Redirect to HTTPS://www.<取得したドメイン名>.com:443/#{path}?#{query}
```
ロードバランシングの設定で指定しているポートがすべての接続先で動作していることを確認してください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2918716/0ab1b133-e3eb-9f1a-e7a3-759504d89dc8.png)
※ここ（設定画面後半くらい）で証明書の設定

:::note warn
本当の企画当初，シングルノードで構成を考えていました．ラクにHTTPSを利用するにはALBが最適で，それを実装する際はバランシング先は2つ以上なければならない決まりになっていました．大変お恥ずかしい話ですが，もう一方にRDSを指定していたのです．するとランダムにあるリクエストだけはちゃんとレスポンスが返ってくるのに，あるリクエストに対しては返ってこないという事象が起こりました．そこで勉強の意味も込めてマルチノードに舵を切った背景がございます．
:::

4.**他のSecurity Group** (EC2)
構成を文字に起こすと下記のようになっています．
```:構成図を文字化したもの
Internet -(443)-> ALB -(8080)-> EC2 -(3306)-> DB
```
ALBをWebアプリのエンドポイントとして機能させ，今回EC2上のWebアプリは8080番ポートで動作させていました．Webサービス提供に必要な上記のルートはSecurity groupで制御し，余計なトラフィックが入ってこないように意識します．Security groupはステートフルだった認識なので，一つ書いておけば戻りは別途書かなくても良かったはずです．

# ネットワークを俯瞰すると
上記のセットアップによって起こる一連のネットワークの挙動を考えてみます．

1.DNS側で`*.<作成したドメイン>`ドメインへのアクセスがあった際，ALBのVIPを返す
2.ALBに接続があったとき，クライアントとALBは証明書交換を行い，HTTPSセッションを開始
3.ネゴシエーション完了後，バランシングしている各ノードにリクエストを振り分ける
4.ユーザの操作に応じてサーバからDBへの接続があったり，ユーザに画面遷移を返す動きをする

といった具合かなと思っています．ここには図がなくて文字だけで申し訳ないのですが，上に戻ってアーキテクチャを眺めると想像つきやすいかと思います．

# 実装を終えて（所感）
ネットワークはいままでとは少し毛色が異なり，考慮すべきこと・設定することが多いと思いました．
私自信アプリ側のセキュリティにそこまで詳しくなく，ネットワーク側で最低限のものを実装するにとどまりましたが，次の機会ではちゃんと実装した上で，Kali Linuxでペネトレーションテストもやってみようと思います．

ネットワークはサーバやアプリに比べて，地味かつ責任が重大だと思っているのですがその分パズルや論理的な面白さを感じます．またネットワークをわかっている人は普段から肝が座っていて，どこか男らしい強さを感じていたのですが，その理由が少しわかり，改めてリスペクトを持てました．

お読みいただき，ありがとうございました！