異なるAWSアカウントのVPC間でPrivateLinkを使ったHTTPS通信を実現する方法

# はじめに

VPCが異なるアプリケーション間で通信を行う手段として、インターネット経由で行う方法と、PrivateLink、VPCピアリングなどを使った方法があります。企業によって、インターネットに接続させたくないといったセキュリティポリシーがあったりしますが、その場合は後者で挙げた方法を利用することになると思います。
そこで今回はPrivateLinkを使って、異なるAWSアカウントVPC間のHTTPS通信を実現してみたいと思います。

イメージはこんな感じです。

![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53830/dc79af00-c03c-a0b2-bfca-81604cd1bbdc.png)

# 前提
- 独自ドメインを取得していること  
ちなみに無料で取得したい場合は、[Freenom](https://www.freenom.com/ja/index.html)で取得できます。
ただし、今回はパブリックDNSはRoute53という前提で進めていきます。

本記事では、ドメインは「sevencafe.tk」として説明していきます。

# 手順

## サービス提供者

### 1. Elastic IPを割り当てる

1. [Elastic IP アドレス](https://console.aws.amazon.com/ec2/v2/#Addresses:)を開きます。
2. [Elastic IP アドレスの割り当て] ボタンをクリックします。
3. [Amazon の IPv4 アドレスプール] を選択して、[割り当て] ボタンをクリックします。

### 2. VPCを作成する

1. [VPC](https://console.aws.amazon.com/vpc/) を開きます。
2. [VPCウィザードの起動] をクリックします。
3. [パブリックとプライベートサブネットを持つVPC] を選択し、[選択] ボタンをクリックします。
4. 詳細情報を入力します。
  - IPv4 CIDR ブロック: **10.0.0.0/16**
  - IPv6 CIDR ブロック: **IPv6 CIDR ブロックなし**
  - VPC 名: **vpc-provider**
  - パブリックサブネットの IPv4 CIDR: **10.0.0.0/24**
  - アベイラビリティーゾーン: **ap-northeast-1a**
  - パブリックサブネット名: **subnet-public**
  - プライベートサブネットの IPv4 CIDR: **10.0.1.0/24**
  - アベイラビリティーゾーン: **ap-northeast-1c**
  - プライベートサブネット名: **subnet-private**
  - Elastic IP 割り当て ID: **割り当て済みElastic IP**
  - DNS ホスト名を有効化: **はい**
  - ハードウェアのテナンシー: **デフォルト**
5. [VPCの作成] ボタンをクリックします。

### 3. 踏み台サーバを作成する。

1. [EC2](https://console.aws.amazon.com/ec2/v2/#Instances:)を開きます。
2. [インスタンスの作成] ボタンをクリックします。
3. [Amazon Linux 2 AMI (HVM), SSD Volume Type] の[選択] ボタンをクリックします。
4. [t2.micro] にチェックを入れ、[次のステップ: インスタンスの詳細の設定] ボタンをクリックします。
5. 以下の情報を入力し、[次のステップ: ストレージの追加] ボタンをクリックします。他の項目はデフォルトのまま。
  - ネットワーク: **vpc-provider**
  - サブネット: **subnet-public**
6. [次のステップ: タグの追加] ボタンをクリックします。
7. [次のステップ: セキュリティグループの作成] ボタンをクリックします。
8. 以下の内容を入力し、[確認と作成] ボタンをクリックします。
  - セキュリティグループの割り当て: **新しいセキュリティグループを作成する**
  - セキュリティグループ名: **group-bastion**
  - 説明: **bastion security group**
  - ルール
     - タイプ: **SSH**
     - プロトコル: **TCP**
     - ポート: **22**
     - ソース: **カスタム 0.0.0.0/0**
9. [起動] ボタンをクリックします。
10. キーペアの選択ダイアログが表示されたら、既存のキーペアを選択し、[インスタンスの作成] ボタンをクリックします。

### 4. Elastic IPを踏み台サーバに関連づける

1. [Elastic IP](https://console.aws.amazon.com/ec2/v2/#Addresses:) を開きます。
2. [Elastic IPアドレスの割り当て] ボタンをクリックします。
3. [Amazon の IPv4 アドレスプール] を選択して、[割り当て] ボタンをクリックします。
4. 割り当てられたIPを選択し、[アクション] から[Elastic IPアドレスの関連付け] を選択します。
5. 以下の内容を入力し、[関連付ける] ボタンをクリックします。
  - リソースタイプ: **インスタンス**
  - インスタンス: **手順3で作成したインスタンス**

### 5. アプリケーションサーバを作成する。

1. [EC2](https://console.aws.amazon.com/ec2/v2/#Instances:)を開きます。
2. [インスタンスの作成] ボタンをクリックします。
3. [Amazon Linux 2 AMI (HVM), SSD Volume Type] の[選択] ボタンをクリックします。
4. [t2.micro] にチェックを入れ、[次のステップ: インスタンスの詳細の設定] ボタンをクリックします。
5. 以下の情報を入力し、[次のステップ: ストレージの追加] ボタンをクリックします。他の項目はデフォルトのまま。
  - ネットワーク: **vpc-provider**
  - サブネット: **subnet-private**
6. [次のステップ: タグの追加] ボタンをクリックします。
7. [次のステップ: セキュリティグループの作成] ボタンをクリックします。
8. 以下の内容を入力し、[確認と作成] ボタンをクリックします。
  - セキュリティグループの割り当て: **新しいセキュリティグループを作成する**
  - セキュリティグループ名: **group-application**
  - 説明: **application security group**
  - ルール1
     - タイプ: **SSH**
     - プロトコル: **TCP**
     - ポート: **22**
     - ソース: **カスタム group-bastion**
  - ルール２
     - タイプ: **HTTP**
     - プロトコル: **TCP**
     - ポート: **80**
     - ソース: **カスタム 0.0.0.0/0**
9. [起動] ボタンをクリックします。
10. キーペアの選択ダイアログが表示されたら、既存のキーペアを選択し、[インスタンスの作成] ボタンをクリックします。

### 6. Nginxをセットアップする

上記で作成したEC2にSSHで接続して、nginxをインストールします。

```bash
# Nginxインストール
sudo amazon-linux-extras install nginx1.12 -y

# Nginx起動
sudo systemctl start nginx.service

# index.htmlページ編集
sudo vi /usr/share/nginx/html/index.html
# "Hello PrivateLink"に書き換える

```

### 7. ホストゾーンを作成する

1. [Route 53](https://console.aws.amazon.com/route53/#hosted-zones:)を開きます。
2. [ホストゾーンの作成] ボタンをクリックします。
3. 以下の内容を入力し、[作成] ボタンをクリックします。
  - ドメイン: **sevencafe.tk**
  - タイプ: **パブリックホストゾーン**

### 8. SSL証明書を取得する

1. [Certificate Manager](https://console.aws.amazon.com/acm/) を開きます。
2. [証明書のリクエスト] ボタンをクリックします。
3. [パブリック証明書のリクエスト] を選択し、[証明書のリクエスト] ボタンをクリックします。
4. 以下のドメイン名を入力し、[次へ] ボタンをクリックします。
  - *.sevencafe.tk
  - sevencafe.tk
5. [DNSの検証] を選択し、[次へ] ボタンをクリックします。
6. [確認] ボタンをクリックします。
7. 内容を確認後、[確定とリクエスト] ボタンをクリックします。
8. 検証中のドメインを開き、[Route 53でのレコードの作成] ボタンをクリックします。
9. Route 53 でのレコードの作成のダイアログが開いたら、[作成] ボタンをクリックします。
10. [続行] ボタンをクリックします。

### 9. Network Load Balancerを作成する

1. [ロードバランサー](https://console.aws.amazon.com/ec2/v2/#LoadBalancers:) を開きます。
2. [ロードバランサの作成] ボタンをクリックします。
3. [Network Load Balancer] の [作成] ボタンをクリックします。
4. 以下の内容を入力し、[次の手順: セキュリティ設定の構成] ボタンをクリックします。
  - 名前: **nb-provider**
  - スキーム: **内部**
  - リスナー
     - ロードバランサーのプロトコル: **TLS**
     - ロードバランサーのポート: **443**
  - VPC: **vpc-provider**
  - アベイラビリティーゾーン: ap-northeast-1c（subnet-private）
5. 以下の内容を入力し、[次の手順: ルーティングの設定] ボタンをクリックします。
  - 証明書のタイプ: **ACM から証明書を選択する (推奨)**
  - 証明書の名前: **ACMで作成した証明書**
6. 以下の内容を入力し、[次の手順: ターゲットの登録] ボタンをクリックします。
  - ターゲットグループ: **新しいターゲットグループ**
  - 名前: target-application
  - ターゲットの種類: **インスタンス**
  - プロトコル: **TCP**
  - ポート: **80**
  - ヘルスチェックプロトコル: **TCP**
7. ap-northeast-1cにあるインスタンスをチェックし、[登録済みに追加] ボタンをクリックします。
8. [次の手順: 確認] ボタンをクリックします。
9. 内容を確認し、[作成] ボタンをクリックします。

### 10. エンドポイントサービスを作成する

1. [エンドポイントサービス](https://console.aws.amazon.com/vpc/#EndpointServices:) を開きます。
2. [エンドポイントサービスの作成] ボタンをクリックします。
3. 以下の内容を入力し、[サービスの作成] ボタンをクリックします。
  - Network Load Balancer の関連付け: **nb-provider**
  - エンドポイントの承諾が必要: **チェック**
  - Enable private DNS name: **チェック**
  - Private DNS name: **internal.sevencafe.tk**
4. 作成されたエンドポイントサービスを選択し、[ホワイトリストに登録されたプリンシパル]タブを選択します。
5. [ホワイトリストにプリンシパルを追加する] ボタンをクリックします。
6. ARNに利用者側のIAMユーザのARNを入力し、[ホワイトリストに登録されたプリンシパルに追加する] ボタンをクリックします。

### 11. Private DNSを検証する

1. [Route 53](https://console.aws.amazon.com/route53/#hosted-zones:)を開きます。
2. 作成したホストゾーンを選択します。
3. [レコードセットの作成] ボタンをクリックします。
4. 以下の内容を入力し、[作成] ボタンをクリックします。
  - 名前: **エンドポイントサービスの詳細タブ内の[Domain verivication name]**
  - タイプ: **TXT**
  - 値: **エンドポイントサービスの詳細タブ内の[Domain verification value]**
5. [エンドポイントサービス](https://console.aws.amazon.com/vpc/#EndpointServices:) を開きます。
6. 手順10で作成したエンドポイントサービスを選択し、[アクション] から[Verify domain ownership for Private DNS Name] を選択します。
7. ダイアログが表示されたら、[Verify] ボタンをクリックします。

**IAMユーザのARNの確認方法**
1. [IAMユーザ](https://console.aws.amazon.com/iam/#/users) を開きます。
2. 追加したいユーザのリンクをクリックします。
3. [ユーザーの ARN]を確認します。

### 12. 利用者のVPCエンドポイント利用を承諾する
サービス利用者の手順6が完了した後に行います。

1. [エンドポイントサービス](https://console.aws.amazon.com/vpc/#EndpointServices:) を開きます。
2. 手順10で作成したエンドポイントサービスを選択し、[エンドポイント接続] タブを選択します。
3. [承諾の保留中]になっているエンドポイントを選択し、[アクション]から[エンドポイント接続リクエストの承諾]を選択します。
4. 確認ダイアログが表示されたら、[はい、承諾します] ボタンをクリックします。

## サービス利用者

サービス提供者側の手順1〜5を同様に行います。VPCやサブネットのCIDRなど変えても問題ありませんが、<font color="red">アベイラビリティゾーン</font>は合わせるようにしてください。今回の例だと、 ```ap-northeast-1c``` になります。

### 6. VPCエンドポイントのセキュリティグループを作成する

1. [セキュリティグループ](https://console.aws.amazon.com/vpc/#SecurityGroups) を開きます。
2. [セキュリティグループの作成] ボタンをクリックします。
3. 以下の内容を入力し、[セキュリティグループを作成] ボタンをクリックします。
  - セキュリティグループ名: **group-vpc-endpoint**
  - 説明: **vpc endpoint security group**
  - VPC: **手順1で作成したVPC**
  - インバウンドルール
     - タイプ: **HTTPS**
     - ソース: **group-application**

### 7. エンドポイントの作成

1. [エンドポイント](https://console.aws.amazon.com/vpc/#Endpoints:) を開きます。
2. [エンドポイントの作成] ボタンをクリックします。
3. 以下の内容を入力し、[エンドポイントの作成] ボタンをクリックします。
  - サービスカテゴリ: **サービスを名前で検索**
  - サービス名: **サービス提供者側で作成したエンドポイントサービス名**
  - VPC: **手順1で作成したVPC**
  - サブネット: **[ap-northeast-1c] にチェック**
  - セキュリティグループ: **group-vpc-endpoint**

### 8. プライベートDNSを有効にする

サービス提供側でエンドポイント接続リクエストの承諾が完了した後に行います。

1. [エンドポイント](https://console.aws.amazon.com/vpc/#Endpoints:) を開きます。
2. 作成したエンドポイントを選択し、[アクション]を開き、[プライベートDNS名の変更] を選択します。 
3. [プライベート DNS 名を有効にする]にチェックをし、[プライベートDNS名の変更] ボタンをクリックします。

# 動作確認

サービス利用者側のプライベートサブネットに配置したインスタンスにSSH接続し、以下のコマンドを実行します。

```
$ curl https://internal.sevencafe.tk
Hello PrivateLink
```

試しにパブリックサブネットに配置したインスタンスでも確認してみてください。


# 参考サイト

- [[新機能] PrivateLinkの公開サービスにプライベートDNS名が指定可能になりました](https://dev.classmethod.jp/articles/private-dns-name-for-privatelink/)
- [そういえば、TLS 終端している NLB で PrivateLink できるんでしたっけ？](https://qiita.com/daimatsu/items/2c16412acffd2529ec28)
- [AWS PrivateLinkで異なるAWSアカウント間の重複するVPCレンジ間で通信してみる（その２：PrivateLink作成）](https://dev.classmethod.jp/articles/try-aws-privatelink_2/)