Well Architected Frameworkを意識して自分なりにアーキテクチャ設計・構築をしてみた。＜VPC、ELB編＞

#はじめに
この記事は、実務未経験者がロールプレイング形式でアーキテクチャの設計、構築を行うといった記事です。
よろしければ[＜準備編＞](https://qiita.com/mkoki0422/items/9fc0b5d44ff7367994f1
)[＜アーキテクチャ設計編＞](https://qiita.com/mkoki0422/items/33b60250527dbc92b518)もご覧くださいませ。


#前回までのあらすじ
前回は問題点を洗い出し、具体的な改善案を提案、アーキテクチャの設計を行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/f9c593aa-9fbb-fc07-39ba-48011c373741.png)


今現在のアーキテクチャはこれですので、どんどん構築していきます！
![スクリーンショット 2020-09-20 23.06.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/aa4a2711-c525-855f-fb7d-e5fc055def91.png)



#構築編
今回はVPCとALBの実装を行なっていきます。


##VPC / 通信の範囲に応じてSubnetを作成
セキュリテイ向上の為にもWebサーバーをプライベートサブネットに移行します。
また、WEBサーバーとデータベースのセキュリティグループを細かく分けて設定したいで、サブネットも分けてみました。

今回は以下の3種類のサブネットを作成します。

+ publicサブネット
    + NATゲートウェイ、ELB設置用のサブネット

+ privateサブネット（WEBサーバー用）
    + メインのWEBサーバー設置用サブネット

+ privateサブネット（RDS用）
    + RDS設置用サブネット
    + ElastiCacheを追加する際はここのサブネットに配置



publicサブネットとprivateサブネット（RDS用）は前回作成したサブネットをそのまま使用できるので、privateサブネット（WEBサーバー用）を各AZに作成しました。
一応Nameタグも変更しておきましょう！
![スクリーンショット 2020-09-23 16.55.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/d2820db0-ca55-0ba5-a9fd-052d72ee683c.png)

6つのサブネットの作成が完了したので、WEBサーバーを移行します。
最新のゴールデンイメージ（AMI）を作成後、インスタンスの起動を行います。

## Systems Manager / Session Managerを用いてSSHログインを行う
今回はWEBサーバーをプライベートサブネットに設置します。
SSH接続を行う為に、**SSM用のIAMロール**を作成しましょう。
IAMの「ロールの作成」→ユースケースから「EC2」を選択→ポリシーは「AmazonEC2RoleforSSM」を選択してください。
![スクリーンショット 2020-09-23 17.01.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/855f8965-243e-a62b-bfc8-b2be068fdb3e.png)

![スクリーンショット 2020-09-23 17.01.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/bca78088-8ee1-017e-ad4a-b89b28198fa5.png)

こちらのIAMロールをEC2に関連付けると、SSMのセッションマネージャーでSSH接続することが出来ます。

SSHキーも無しで大丈夫ですので、紛失の心配もありません。
（SSMを使用しない方法であれば、踏み台サーバーを設置する方法もありますが、冗長化や管理がめんどくさいのでマネージドサービスに任せましょう！）
![スクリーンショット 2020-09-23 17.05.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/40857ca2-f4e3-822e-1bb4-8abd8c960197.png)



一応、セッションマネージャーを利用してSSH接続の確認も行なってみます！

Systems Managerからセッションマネージャーを選択
![スクリーンショット 2020-09-23 17.14.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/e3a65a45-dc21-5d3a-9ecf-9081019b8983.png)

セッションの開始を選択
![スクリーンショット 2020-09-23 17.14.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/9fe8a67a-d2bc-649a-3cbb-4f76226a8827.png)

接続したいインスタンスを指定して、「セッションを開始する」
![スクリーンショット 2020-09-23 17.14.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/24ad745f-deb7-4451-c799-f876cae50ee4.png)

普通にコマンドを実行出来ますのでオススメです！（もちろん、スマートフォンやタブレットでもアクセス可能です！）
![スクリーンショット 2020-09-23 17.15.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/167c47d7-b8e1-4b0d-4ebd-45395e43cdc7.png)


スマートフォンでもSSH接続してみました。
![179045.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/09e95305-d62a-466a-967c-ab56e51bd351.jpeg)


##VPC / NAT Gatewayの作成、Route Tableの定義
Privateサブネットからインターネットへアクセスする時に必要となる要素です。
冗長化の為に、各AZに配置します。

Routeテーブルは

+ publicサブネット
→インターネットゲートウェイ

+ privateサブネット（WEBサーバー用）
→冗長化の為に**同じAZのNATゲートウェイ**にルーティング

+ privateサブネット（RDS用）
RDSを利用しているので、一旦VPC内のルーティングのみ

に設定しました。

サクッとNATゲートウェイを作成して、ルーティングも設定しましょう
![スクリーンショット 2020-09-23 17.24.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/f11771cc-7c64-1f88-7648-5a5cf4aaeb20.png)



##ALB / ターゲットグループの作成
前回までは、テストの為にRoute53の複数値ルーティングを使用していましたが、今後の拡張性も考えて（WAF,AutoScalingの導入など）ALBを実装していきます。

まずはターゲットグループを作成していきます
マネジメントコンソールの「EC2」→「ターゲットグループ」から作成します。
![スクリーンショット 2020-09-23 17.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/937a6983-85c6-e7d4-117f-c1c8ce929b2c.png)
HTTPS化をする場合はプロトコルをHTTPSにしてください。
ヘルスチェックはプロトコルと、実際にチェックを行うパスを指定することが出来ます。

インスタンスを指定して、ターゲットグループを作成しましょう。
![スクリーンショット 2020-09-23 17.29.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/67e5568c-a4c2-b4a1-42ff-db1a2ca27209.png)


ステッキーセッションの設定を行いたい場合は「属性」の方から設定することも出来ます。
![スクリーンショット 2020-09-23 17.30.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/867aa93b-22f8-a537-4295-5be0c4ab22aa.png)

「維持設定」を選択すると、1秒から〜7日間まで指定することができます。
![スクリーンショット 2020-09-23 17.34.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/7353135e-9332-1905-3635-e5a1be3eace3.png)

##ALB / ALBの作成

ターゲットグループの設定が終わったので、ロードバランサーを作成していきます。
今回はALBを選択しました。
HTTPS化をしたい場合は、「リスナー」からHTTPSを選択してください
VPCとサブネットの指定も行います。

「アドオンサービス」の「AWS Global Accelerator」を設定するとパフォーマンスが上がりますが、追加料金も掛かるので一旦スルーしておきます。
![スクリーンショット 2020-09-23 17.38.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/4353f061-e61c-f0cb-3bd2-5016b659e0e3.png)

セキュリティグループを選択しましょう。
ALBに関しては0.0.0.0/0のフルオープンでも問題ないでしょう
![スクリーンショット 2020-09-23 17.40.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/f618ef21-2362-8be0-9ee8-70e14df7b605.png)



ルーティングの設定で、先ほど作成したターゲットグループを指定してください。

![スクリーンショット 2020-09-23 17.41.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/670507b6-022c-bd9e-efd3-525e54c77bdb.png)

そのまま「作成」まで進むと、ALBの完成です。
一応DNS名からアクセス出来るかの確認もしましょう


##Cloudwatch / ELBのメトリクスを監視

ELBの監視については、モニタリングのタブからメトリクスの確認が出来ます。
Cloudwatchアラームも設定可能ですので、閾値を設定してサーバーダウンを通知することも可能です
![スクリーンショット 2020-09-23 17.46.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/2b2cb9a5-5b4c-1dfb-6b9b-4908540432cb.png)


主なメトリクスについて確認します。
こちらの記事が分かりやすいので確認しておきましょう
https://dev.classmethod.jp/articles/elb-and-cloudwatch-metrics-in-depth/

+ ELBがバックエンドのステータスコードをそのまま返す場合（HTTPCode_Backend_*）
    + 2XX~5XXまであります
    + 主にバックエンド側でのエラー
+ ELBが独自の判断によりステータスコードを返す場合（HTTPCode_ELB_*）
    + 2XX~5XXまであります
    + ELB側でのエラー
+ RequestCount
    + リクエストの合計値です。
    + HTTPCode_Backend_*の合計がRequestCount
+ SurgeQueueLength
    + ELBで処理出来ず、待機中のリクエスト
    + 基本的に0を目指しましょう（ELBのキャパシティを確認できますね）
+ SpilloverCount
    + ELBのキャパシティ（surge queue）を完全に超えてELBがエラーを返した数になります


ターゲットグループで確認出来るメトリクスもあります。

+ HealthyHostCount
    + ELBから見た正常なEC2インスタンス数の数
+ UnHealthyHostCount
    + ELBから見た異常なEC2インスタンス数の数
    
具体例を挙げてみます
2つのEC2インスタンスがあると仮定します。
2つとも正常な場合は
HealthyHostCount→2
UnHealthyHostCount→0

2つのインスタンスのサービスが停止している場合は
HealthyHostCount→0
UnHealthyHostCount→2

EC2自体が停止した場合に関しては**注意**が必要です。
2つのEC2インスタンスが停止している場合
HealthyHostCount→No Data
UnHealthyHostCount→No Data

となってしまいます。
ですので、「ロードバランシング対象サービスに異常がある場合」にも「EC2自体が停止した場合」にもどちらでもCloudWatchアラームを発報させるには、CloudWatchアラームの設定で、

+ ステータスがALARM(閾値を上回った場合、以下の設定ではHealthyHostsが1以下になった場合)
+ ステータスがINSUFFICIENT(データが不足している場合)

のどちらもアクション対象として設定してあげる必要があります。







##VPC / VPC FlowLogの作成、S3にログの収集
事前にVPCフローログの出力先となるS3バケットを作成しておきます（今後のログ収集における出力先をこちらのバケットに設定しておくと、その後の分析等が楽になります。）

マネジメントコンソールの「VPC」→「アクション」→「フローログの作成」から作成画面に進んでください
![スクリーンショット 2020-09-24 5.34.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/519667be-5aaa-183d-71fe-da9970f8df8f.png)


VPCフローログはCloudwatchLogs、S3で出力先を選ぶことが出来ますが、「Athenaで一括管理を行いたい」、「コスト」の観点からS3を出力先として指定します。
その他の設定はデフォルトのままでも大丈夫でしょう。
![スクリーンショット 2020-09-24 5.35.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/2f2dffb6-1cbb-1181-29dd-3b011f8c4b17.png)

S3への出力を確認してみましょう
![スクリーンショット 2020-09-24 5.41.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/cea7d7a3-ad1d-06e5-8da8-95d5c3c114a9.png)

ログ自体は圧縮されたファイルで、尚且つめちゃくちゃ見にくいです。
普通はAthanaなどで分析、閲覧を行います。
![スクリーンショット 2020-09-24 5.42.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/1364f1dd-76e7-ef7f-07b3-f3f112bafbc2.png)

後ほどAthenaを使ってログの分析を行います！


##VPC / Security Groupで必要最小限のアクセスのみを許可
基本的に、ネットワークにアクセスさせるリソース以外のセキュリティグループは最小限にしましょう。
例えば、ELBはフルオープンにせざるを得ないとしても、EC2のセキュリティグループは、ELBのみに制限する などです。

セキュリティグループはアクセス元として、IPアドレス以外にもアクセス元のリソースに関連付けられているセキュリティグループを指定することもできます。
管理も楽ですし、セキュリティグループをソースとして指定する方法をオススメします。


ちなみに補足としてネットワークACLによるアクセス制御も出来ますが、NACLはステートレスである為に**一時ポートを考慮する必要**があり、管理が大変です。

##Config / セキュリティグループのSSH全開放をAWS Configによる自動修復によって修正する
よくやってしまいますが、SSHの全開放（0.0.0.0/0）もあまり好ましくありません。
今回はSystems Managerを使用しておりますので、WEBサーバーのセキュリティグループでSSHポートを開くことは無いと思いますが、AWS Config Rulesでコンプライアンスに非準拠となった時に自動修復が出来るようになりましたので、実装してみようと思います。

仕組みとしては
「ConfigがSSHの全開放を検知」→「Systems ManagerのAutomationによって修正」
という流れになっております。Config側でAutomationは起動してくれるので、SSM用のIAMロールを作成するだけで出来ます。

IAMロールを作成する前に今回必要なIAMポリシーを作成します。
「ポリシーの作成」からJSON形式を指定して、こちらのポリシーを作成して下さい。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:RevokeSecurityGroupIngress",
            "Resource": "*"
        }
    ]
}
```
ビジュアルエディタの場合はサービスとしてSSMではなくEC2を選択してください。アクションは「RevokeSecurityGroupIngress」です。
![スクリーンショット 2020-09-24 6.57.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/2d99708e-496e-4e9f-fd9b-6f491ddd58b9.png)

IAMロールを作成後、Configの設定でIAMロールを関連づけるので、ARNをコピーしておきましょう。
![スクリーンショット 2020-09-24 7.00.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/d6d90037-17ee-cd68-f589-6191ef972f45.png)


また、作成時にはサービスでEC2を選択して作成しましたが、SSMから利用するロールのため「信頼関係」から**ec2.amazonaws.com**を**ssm.amazonaws.com**に変更します。
この手法はちょいちょい使いますので、覚えておくと良いでしょう
![スクリーンショット 2020-09-24 7.00.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/c84ceddf-f1f7-7053-fe79-ba583317fb76.png)


Configの「ルールの追加」からルールを作成していきます。
マネージドルールの検索欄から**「restricted-ssh」**を指定して下さい。
![スクリーンショット 2020-09-24 7.04.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/c67d8772-cdaa-7a2d-45ae-3b085261706e.png)

リソースは「AWS EC2 SecurityGroup」を指定します。
![スクリーンショット 2020-09-24 7.11.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/d14c0cdd-ba2f-3070-b09e-1e1fb527bb61.png)

ルールの作成が完了したら、「アクション」→「修復の管理」を選択します。
![スクリーンショット 2020-09-24 7.12.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/bf79535f-5d6b-b675-46f1-ed404526bb15.png)

修復アクションは「AWS-DisablePublicAccessForSecurityGroup」を選択。
リソースIDパラメーターは「GroupID」を選択して、先ほど作成したIAMロールのARNを入力したら完成です！
![スクリーンショット 2020-09-24 7.13.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/0c6f209b-1865-3e1c-d31c-8361b741cfc9.png)

「restricted-ssh」以外にも様々なマネージドルールがありますし、カスタムルールも作成可能ですので
「コンプライアンスに非準拠を検知」→「自動修復」のパターンが色々出来そうですね！

#最後に
現時点でのアーキテクチャはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666664/270bd368-f76f-4aa0-b846-f348ef422501.png)


#参考
「セキュリティグループのSSH全開放をAWS Configで自動修復したら3分くらいで直ったからみんな使ってほしい件」
https://dev.classmethod.jp/articles/auto-recovery-restricted-ssh-without-lambda/

「VPCフローログをAmazon Athenaで分析する」
https://dev.classmethod.jp/articles/vpc-flow-logs-athena/

「ELB + CloudWatchアラームを使ったEC2サービス監視プラクティス」
https://dev.classmethod.jp/articles/elb-using-cloudwatch-alarm/

「ELBの挙動とCloudWatchメトリクスの読み方を徹底的に理解する」
https://dev.classmethod.jp/articles/elb-and-cloudwatch-metrics-in-depth/