Laravelを本番環境時のみSSL化し、Route53とACMを利用してhttps接続を可能にする

## はじめに
この記事はプログラミング初学者による備忘録用の記事であり、また、少しでも他の初学者のお役に立てればと思い書いています。

今回は、AWSのEC2へデプロイしたLaravelアプリケーションを本番環境時のみSSL化し、Route53とACMを利用してhttpsでLaravelアプリケーションに接続する作業を行いましたので、備忘録としてまとめておきたいと思います。

間違いなどがございましたら、ご指摘のほどよろしくお願い致します。

## 環境変数の設定
AWSのEC2インスタンスへデプロイしたLaravelの``.env``ファイルの**APP_ENV**を確認してください。

```.env
 APP_ENV=production
```
**APP_ENV**は、ローカル環境（開発環境）の場合は``local``、本番環境（デプロイ済）の場合は``production``である必要があります。


## https化に対応する(Laravel側)
下記の手順に従って、https化してください。

### 1.AppServiceProvider.phpを編集する
AppServiceProvider.phpを下記のように編集して、本番環境時のみURLがhttpsになるようにしてください。

```app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL; //追記

class AppServiceProvider extends ServiceProvider
{
    //略

    public function boot()
    {
        // 追記
        if (config('app.env') === 'production') {
            URL::forceScheme('https');
        }
    }
}
```

### 2.httpで接続された場合にhttpsにリダイレクトさせる
全ページをhttpsで接続されるようにするために、``Middleware``を利用してhttpでの接続を全てhttpsにリダイレクトさせます。

``php artisan``コマンドを実行してリダイレクト用のmiddlewareを作成後、下記のように編集してください。

```app/Http/Middleware/xxxx.php
<?php

namespace App\Http\Middleware;

use Closure;

class xxxx
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // 追記
        if (!$this->is_ssl() && config('app.env') === 'production') {
            return redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
        }

        return $next($request);
    }

    // 追記
    //Webサーバー毎にキーと値で判別する
    public function is_ssl()
    {
        if (isset($_SERVER['HTTPS']) === true) { // Apache
            return ($_SERVER['HTTPS'] === 'on' or $_SERVER['HTTPS'] === '1');
        }
        elseif (isset($_SERVER['SSL']) === true) { // IIS
            return ($_SERVER['SSL'] === 'on');
        }
        elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) === true) { // Reverse proxy
            return (strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https');
        }
        elseif (isset($_SERVER['HTTP_X_FORWARDED_PORT']) === true) { // Reverse proxy
            return ($_SERVER['HTTP_X_FORWARDED_PORT'] === '443');
        }
        elseif (isset($_SERVER['SERVER_PORT']) === true) {
            return ($_SERVER['SERVER_PORT'] === '443');
        }

        return false;
    }
}
```

### 3.Kernel.phpに登録する
作成したmiddlewareの内容を反映させるために、Kernel.phpの``protected $middleware``に追記します。

```app/Http/Kernel.php
protected $middleware = [
        // 略
        \App\Http\Middleware\xxxx::class, // 追記
    ];
```

### 4.全プロキシを信用する
全プロキシを信用するために、``TrustProxies.php``に``*``を追記します。

```app\Http\Middleware\TrustProxies.php
protected $proxies = '*';
```

>Amazon AWSや他の「クラウド」ロードバランサプロバイダを使用している場合は、実際のバランサのIPアドレスは分かりません。このような場合、全プロキシを信用するために、*を使います。
``引用:``[Laravel6.x HTTPリクエスト](https://readouble.com/laravel/6.x/ja/requests.html#configuring-trusted-proxies)

## https化に対応する(AWS側)
AWS側の設定では、下記項目の設定を行う必要があります。

* ACMでSSL証明書を作成
* ターゲットグループの作成
* ターゲットグループにターゲットを紐付ける
* ロードバランサーの作成
* Route53でホストゾーンの設定を変更する

**※Route53を利用したドメイン等の設定は、[リンク先](https://qiita.com/kouki_o9/items/f6231c3837ff3545a09f)を確認してください。**


### ・1.ACMを利用してSSL証明書を作成する
#### 1-1.証明書をリクエストする
``パブリック証明書をリクエスト``を選択します。

![スクリーンショット 2022-03-17 21.34.48（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/3ecf9de4-37c1-9154-0698-5d26fc1fa824.png)

#### 1-2.パブリック証明書のリクエストの必須項目を入力しリクエストを送る

``~入力項目の説明~``

**・ドメイン名**:
お名前.com等で購入したドメイン名を指定します。 ex)example.com

**・検証方法を選択**:
ドメインの所有権を検証する方法を選択してください。

今回は、**DNS検証**を利用します。

[DNS検証](https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/dns-validation.html)を選択すると、DNSデータベースに追加する必要がある1つ以上の``CNAMEレコード``が自動生成されます。
これらのレコードは、ユーザーのドメインおよびアカウントに固有のものとして作成され、ドメインを制御する証拠となる一意のキーと値のペアが含まれています。
※レコードの値は、証明書を自動更新するためにACMが使用するAWSドメインを指すエイリアスです。

![スクリーンショット 2022-03-17 21.42.52（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/d448da68-94f3-94d8-f029-c1f912bd08ca.png)


リクエストを実行すると、下記のような``ステータスが保留中の検証``となっている証明書が発行されます。
この段階では、証明書のリクエストのみ完了しており、次のステップとして保留中の検証を実行します。

![スクリーンショット 2022-03-17 21.44.08（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/81fee6d1-fd59-5a48-ce2b-22e6bdd1c704.png)

#### 1-3.DNS検証を実行してステータスを発行済みにする

DNS検証を実行してステータスを``発行済み``に変更するために、先ほどの画面で**Route53でレコードを作成**を選択してください。

クリック後、下記のような画面が表示されるので、ドメイン、CNAME名、CNAME値に間違いがないか確認してください。
間違いがなければ**レコードを作成**を選択してください。

![スクリーンショット 2022-03-17 22.04.55（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/32ee7b81-a27b-83f6-1193-5035451a0c23.png)

DNSレコードを作成後、証明書のステータスが下記のように発行済みと成功に変わっていれば証明書の発行は完了です。

![スクリーンショット 2022-03-17 22.12.54（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/39a9e26a-ccc5-da68-444c-e0c9e02b6708.png)

### ・2.ターゲットグループを作成する

#### 2-1.ターゲットグループの作成を実行する
後ほど作成するロードバランサーで必要となるターゲットグループを作成します。

下記のような画面が表示されると思うので、``Create target group``を選択して下さい。
![ターゲットグループ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/56809293-d31c-b9ce-ab0c-cbbdb16e7025.png)

#### 2-2.ターゲットグループ作成の必須項目を入力
下記のような画面で必須項目を入力してください。

``~必要項目の説明~``

**・Choose a target type**:
今回はEC2インスタンを利用しているので、インスタンスを選択します。

インスタンスは下記のような特徴があります。

* 特定のVPC内のインスタンスへのロードバランシングをサポートします。
* Amazon EC2 Auto Scalingを使用して、EC2容量を管理およびスケーリングすることを容易にします。

インスタンスIDを使用してターゲットを指定すると、トラフィックはインスタンスのプライマリネットワークインターフェイスで指定されたプライマリプライベートIPアドレスを使用して、インスタンスにルーティングされます。

**・Target group name**:
特定のターゲットグループ名を入力してください。

**・Protocol Port**:
``Protocol = HTTP``、``Port = 80``を選択してください。

デフォルトでは、ロードバランサーはターゲットグループの作成時に指定した**プロトコル**と**ポート番号**を使用して、リクエストをターゲットにルーティングするので、プロトコルは``HTTP or HTTPS``、ポート番号は``1 ~ 65535``を選択して下さい。

**・VPC**:
利用するVPCを選択してください。

**・Protocol version**:
デフォルトでは、Application Load Balancerは``HTTP/1.1``を使用してターゲットにリクエストを送信します。

![スクリーンショット 2022-03-17 22.26.20（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/9fe2b08c-25ea-fafd-fc57-981b4561abc0.png)

**・Health checks**:
ヘルスチェックを実行する際のプロトコルを選択してください。

ロードバランサーは、登録されたターゲットに対して、以下の設定に従って定期的にリクエストを送信し、その状態をテスト(Health checks)します。

![スクリーンショット 2022-03-17 22.26.54（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/4e65d0ac-b25c-290a-a7f5-a4815e3b96ea.png)

上記の項目を入力後、作成を実行してください。

### ・3.ターゲットグループと、インスタンスを紐付ける
ターゲットグループ作成画面で``Next``を選択すると下記のような画面に遷移し、利用可能なインスタンスIDを指定してターゲットとして登録する必要があります。

ターゲットとなるインスタンスIDを選択して、``Include as pending below``をクリックしてください。

![スクリーンショット 2022-03-17 22.55.22（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/a874e5a9-bf9f-5218-d72b-8dcfcc3bf322.png)

クリック後、ターゲット(インスタンスID)が登録実行の一覧に追加されていることを確認して、``Register pending targets``をクリックしてターゲットグループとインスタンスの紐付けを実行してください。

![スクリーンショット 2022-03-17 22.56.04（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/e9878d7f-5453-0bde-30d3-6046ee3972d4.png)

実行後、ターゲットグループの詳細画面で下記のように指定したインスタンスIDが登録されていることを確認して下さい。
LBにターゲットグループを登録していないのでステータスは``unused``となっています。

![スクリーンショット 2022-03-17 22.57.21（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/b5aa3f37-7d51-9f97-c93e-11fe4c7b01fd.png)

### ・4.ロードバランサーの作成
ロードバランサーは、セキュリティポリシーとして知られている``Secure Socket Layer (SSL)``ネゴシエーションの設定を使用して、クライアントとSSL接続をネゴシエート(交渉)します。

#### 4-1.Application Load Balancerを選択

EC2のメニューからロードバランサーを選択してロードバランサーの作成をクリックします。

クリック後、下のような画面が表示されるので``Application Load Balancer``を選択して下さい。
詳細は、[Application Load Balancer とは?](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/introduction.html)をご確認下さい。

![ロードバランサー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/de897202-8f4d-edf7-1a1d-432559b483f7.png)

#### 4-2.基本的な設定

``~入力項目の説明~``

**・Load balancer name**:
一意なロードバランサーの名前を入力してください。

**・Scheme**:
今回はインターネット用ロードバランサーを作成するので、``Internet-facing``を選択します。

ロードバランサーの作成時に、内部用ロードバランサーにするかインターネット用ロードバランサーにするか選択する必要があります。
※ロードバランサーの作成後にスキームを変更することはできません。

**・IP address type**:
今回は``IPv4``を選択しています。

クライアントが IPv4 アドレスを使用してロードバランサーと通信する場合は IPv4 を選択し、クライアントが IPv4 と IPv6 の両方のアドレスを使用してロードバランサーと通信する場合は``Dualstack``を選択します。
ロードバランサーが内部ロードバランサーである場合は、IPv4を選択する必要があります。

![スクリーンショット 2022-03-17 23.12.07（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/357fd3be-f348-3bf0-7bca-5a59a00352e7.png)


#### 4-3.ネットワークマッピングの設定
ネットワークマッピングでは、EC2インスタンス(ターゲット)用の仮想プライベートクラウド（VPC）を選択後、ターゲットに使用するアベイラビリティゾーンを決定し、利用する**パブリックサブネット**を選択します。

**・VPC**:
今回ターゲットとなるEC2インスタンス用の仮想プライベートクラウド（VPC）を選択します。

:::note warn
注意点
※ インターネットゲートウェイを持つVPCのみ選択が可能です。
※ ターゲットが使用する各アベイラビリティゾーンに、**少なくとも1つのパブリックサブネットを持つ仮想プライベートクラウド（VPC）** である必要があります。
:::




**・Mappings**:
アベイラビリティゾーンの選択では、アプリケーションの耐障害性を高めるために、ロードバランサーで2つ以上のアベイラビリティゾーンを有効にする必要があります。

Subnetの選択では、ゾーンごとに1つの**パブリックネット**を選択します。
※インターネットに面したロードバランサーのサブネットには、**インターネットゲートウェイへのルート** が必要です。


![スクリーンショット 2022-03-17 23.30.48（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/288dddd0-25ee-6034-cdd4-2a04e78fa687.png)


#### 4-4.セキュリティーグループの選択
ロードバランサー用に新しいセキュリティグループを作成し、
ポート80で``0.0.0.0/0, ::/0``を許可、ポート443で``0.0.0.0/0, ::/0``を許可する設定を行ってください。

ロードバランサーにリスナーを追加したり、ターゲットグループのヘルスチェックポートを更新したりする際は、ロードバランサーに関連付けられたセキュリティグループが、新しいポートでのトラフィックを両方向に許可していることを確認する必要があります。

作成後、デフォルトのセキュリティグループを削除して作成したセキュリティグループを選択します。


![スクリーンショット 2022-03-17 23.13.07（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/fe934192-6214-2b39-b07f-cf489a18c20c.png)

#### 4-5.リスナーとルーティングの設定
Application Load Balancerの使用を開始する前に、1つまたは複数のリスナーを追加する必要があります。
リスナーとは、設定したプロトコルとポートを使用して接続リクエストをチェックするプロセスです。リスナーに対して定義したルールにより、ロードバランサーが登録済みターゲットにリクエストをルーティングする方法が決まります。

アプリケーションロードバランサーのリスナーは、次のプロトコルとポートをサポートします。

* Protocols: HTTP, HTTPS
* Ports: 1-65535

従って、今回はリスナーとして``HTTP:80``と``HTTPS:443``を選択しています。
デフォルトアクションでは、使用するターゲットグループを選択してターゲットグループにリクエストをルーティングします。

※各リスナーにはデフォルトのルールがあり、オプションで追加のルールを定義できます。
追加のルール設定に関する情報は[リンク先](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-listeners.html)を確認して下さい。

::: note warn
注意点
リスナーとして``HTTPS:443``を選択した場合、セキュリティポリシーを設定する必要があります。
:::

**・Secure listener settings**:
``Secure listener settings``では、**フロントエンド接続に使用するセキュリティポリシー**を選択します。(バックエンド接続には、常に ELBSecurityPolicy-2016-08 セキュリティポリシーが使用されます。)

今回は、公式で推奨されている`` ELBSecurityPolicy-2016-08``を選択しています。

>Elastic Load Balancing は、Secure Sockets Layer (SSL) ネゴシエーション設定 (セキュリティポリシーと呼ばれます) を使用して、クライアントとロードバランサー間の SSL 接続をネゴシエートします。<br>セキュリティポリシーはプロトコルと暗号の組み合わせです。プロトコルは、クライアントとサーバーの間の安全な接続を確立し、クライアントとロードバランサーの間で受け渡しされるすべてのデータのプライバシーを保証します。暗号とは、暗号化キーを使用してコード化されたメッセージを作成する暗号化アルゴリズムです。<br>プロトコルは、複数の暗号を使用し、インターネットを介してデータを暗号化します。接続ネゴシエーションのプロセスで、クライアントとロードバランサーでは、それぞれサポートされる暗号とプロトコルのリストが優先される順に表示されます。デフォルトでは、サーバーのリストで最初にクライアントの暗号と一致した暗号が安全な接続用に選択されます。
``引用:``[Application Load Balancer 用の HTTPS リスナーを作成する セキュリティポリシー](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies)

**・Default SSL certificate**:
AWS Certificate Managerを使用して証明書を作成またはインポートした場合は、``From ACM (ACMから)`` を選択して、証明書を選択します。

今回は、ACMを使用して証明書を作成したので``From ACM``を選択します。

![スクリーンショット 2022-03-17 23.19.10（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/2335614a-e031-5dfe-a282-4e8c95d90097.png)

上記の必要事項を入力後、作成を実行し下のような画面が表示された場合はロードバランサーの作成は成功です。

![スクリーンショット 2022-03-17 23.34.03（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/aacbbcc6-f332-2469-f7af-ca0321528d39.png)

#### 4-6.ロードバランサーの作成後の確認

ロードバランサーの作成後、ターゲットグループ一覧に移動して対象となるターゲットグループの詳細を確認してください。
下記のように、**Health statusがhealthy**になっていれば大丈夫です。

![スクリーンショット 2022-03-19 12.48.38（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/2fa11bb1-5d1e-9e1b-e693-a1133893fdf2.png)


### ・5. Route53のホストゾーンを編集する
ホストゾーンの詳細を開き、**Aレコード**を編集します。


CloudFrontディストリビューションやAmazon S3バケットなど、選択したAWSリソースにトラフィックをルーティングしたい場合や、ホストゾーン内のあるレコードから別のレコードにトラフィックをルーティングしたい場合に、``エイリアス``を選択します。

編集画面でエイリアスを有効にし、下記項目を編集して下さい。

**・エイリアスの選択**:
``Application Load BalancerとClassic Load Balancerへのエイリアス``を選択します。

**・アベイラビリティーゾーンの選択**:
``ap-northeast-1``を選択します。

**・ロードバランサーの選択**:
自動予測で表示されるロードバランサーを選択します。
例)dualstack.ロードバランサー名.以下略と表示されているはずです。

**・ルーティングポリシーの選択**:
レコードを作成するときは、Amazon Route 53がクエリに応答する方法を決定するルーティングポリシーを選択します。
ルーティングポリシーは、Route 53がリソースにトラフィックをルーティングする方法を選択することができます。

今回は、ドメインで特定の機能を実行するリソース(EC2インスタンス上のwebサーバー)が単一なので、``シンプルルーティングポリシー``を使用します。

シンプルルーティングでは、Route 53 の特殊な加重ルーティングやレイテンシールーティングを使用せずに、標準のDNSレコードを設定できます。
また、通常1つのリソース (ウェブサイトのウェブサーバーなど) にトラフィックをルーティングします。

![スクリーンショット 2022-03-17 23.49.50（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/be4565b3-6ba9-7445-24dd-8082f6671800.png)

## 特定のドメインを入力してhttpsで接続できることを確認する

ブラウザ上で特定のドメインを入力し、下のように鍵マークが付き``https://``でアクセスできていれば今回の作業は成功です。

![スクリーンショット 2022-03-19 18.54.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/5ffe99d0-faa4-8185-6492-8aea8f1db1b1.png)




## 参考文献
[DNS検証](https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/dns-validation.html)
[Application Load Balancer のターゲットグループ](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-target-groups.html)
[Application Load Balancer とは?](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/introduction.html)
[Application Load Balancer 用の HTTPS リスナーを作成する](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/create-https-listener.html)
[Application Load Balancer のリスナー](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-listeners.html)
[ルーティングポリシーの選択](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/routing-policy.html?icmpid=docs_console_unmapped)
[シンプルなエイリアスレコードに固有の値を指定する](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/resource-record-sets-values-alias.html?icmpid=docs_console_unmapped)
[レコードを使用する](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/rrsets-working-with.html?icmpid=docs_console_unmapped)