NLB + API Gateway プライベート API で IPv6 からアクセスする

# やりたいこと

NLBまでの通信は、IPv6で通信し、  NLB以降の通信は、IPv4とする。
少々煩雑ですが、構成はこんなイメージです。
![test.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/69d5e175-c3a9-06bc-2fb0-ce27e1863578.png)


# 手順


## VPC

VPCは既存のものを利用しましたので説明は省きます。
ない場合は、プライベートサブネットが最低2つ以上あるVPCを2つ準備しておきます。


## EC2

NLBにリクエストするためにテスト用のEC2を準備しておきます。
IPv6を有効にする必要があるので以下の方の記事を参考に作成しておきましょう。

https://qiita.com/rotekxyz/items/5f171cc70d98b22f7d9b

なお、セキュリティグループのアウトバウンドルールでIPv6を許可しておくことに注意が必要です。
![スクリーンショット 2023-10-24 9.47.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/7660dba1-1fda-f000-255c-1a42c9d432cc.png)

EC2の作成が完了したら、ifconfigなどで、IPv6アドレスが取得できていることを確認しておきましょう。

```
ifconfig
enX0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 172.31.19.5  netmask 255.255.240.0  broadcast 172.31.31.255
        inet6 fe80::c08:f3ff:fe7b:zzzz  prefixlen 64  scopeid 0x20<link>
        inet6 2406:da14:daa:7d00:yyyy:9f5f:c5c9:b43d  prefixlen 128  scopeid 0x0<global>
```


## VPCエンドポイント

API GatewayのVPCエンドポイントを作成します。

サービス名に`com.amazonaws.ap-northeast-1.execute-api`を指定します。
![スクリーンショット 2023-10-23 16.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/5bcf4435-1a71-129e-cfa1-b98e019713a5.png)

IPアドレスは固定にしておきたいため、「IPv４アドレスの指定」にチェックをいれ、「IPv４アドレス」を入力します。
![スクリーンショット 2023-10-23 16.59.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/ee82e7de-771c-a6ab-830c-3e21c15912c7.png)


## API Gateway　と　Lambda

API GatewayとLambdaは、SAMでデプロイしてしまいます。

https://github.com/leomaro7/AWS_SAM/tree/master/Lambda-HelloWorld2

`template.yaml`の プライベートサブネットid1,プライベートサブネットid２,セキュリティグループは自身のものに置き換えて下さい。
VPCエンドポイントidは先程の手順で作成しAPI GatewayのVPCエンドポイントのidに置き換えます。

後は`　sam build`,`sam deploy`でデプロイしておきます。


## ACM

既存のものを利用するので詳しい手順は省きますが、証明書を準備していない場合は、ドキュメントを参考に準備しておきましょう。次のNLBをTLSで通すのに必要です。

https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/gs-acm-request-public.html


## NLB

先にターゲットグループを作成しておきます。

ターゲットタイプはもちろん、「IPアドレス」を指定します。
![スクリーンショット 2023-10-23 21.01.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/d5084ae9-6210-9879-bd5a-0f4d31e23c06.png)

「TLS 443」 を指定します。
指定するIPアドレスタイプは「IPv4」です。
VPCはNLBを配置するVPCを選択します。
![スクリーンショット 2023-10-23 21.07.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/ed8acca4-3aff-c53e-3418-24df85339580.png)

IPアドレスに先程作成したVPCエンドポイントのIPを登録していきます。
![スクリーンショット 2023-10-23 21.10.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/a66c713c-2152-5b10-e0b2-9c0d212949df.png)

次にNLBを作成していきます。

スキームはVPC内からのアクセスのみに許可するので、「内部」にします。
IPv4アドレスタイプはもちろん「Dualstack」を選択します。
![スクリーンショット 2023-10-23 21.14.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/5eefaa38-3183-2bd8-66d9-26ebabd93670.png)

プライベートサブネットを2つ以上選択します。（画像はパブリックサブネットとなっていますが気にしないでください。）
IPv4アドレス、IPv6アドレスは本当は固定にすべきなのですが面倒だったので、動的のままにしてあります。
![スクリーンショット 2023-10-23 21.14.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/c16176f3-fb05-9fef-8804-647a56eec30a.png)

つい最近のアップデートでNLBにセキュリティグループを適用させることができるようになりましたが、今回はシンプルにいきたいので、適用しません。
![スクリーンショット 2023-10-24 18.27.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/fff14ea0-651d-6f03-1c8b-20b9554427ef.png)

「TLS 443」 を指定し、先程作成したターゲットグループを指定します。
![スクリーンショット 2023-10-23 21.15.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/cc5c34b8-4c09-061a-5604-755eebb365c6.png)

こちらは先程作成したACMの証明書を指定します。
![スクリーンショット 2023-10-23 21.15.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/379a3c52-dd27-db48-093b-a49f43c81714.png)


## Route53

プライベートホストゾーンに、NLBを自身のドメインに対して、AAAAレコードを作成します。
![スクリーンショット 2023-10-24 18.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/ac50323b-239c-44d9-0e96-295adc2ceb73.png)

# 動作確認

まず、EC2からNLBのDNS名に対して、名前解決ができるか確認しておきます。

```
dig nlb-XXX.elb.ap-northeast-1.amazonaws.com. AAAA

;; ANSWER SECTION:
nlb-XXX.elb.ap-northeast-1.amazonaws.com. 55 IN AAAA 2406:da14:daa:7d00:aaa:515:446a:879e
nlb-XXX.elb.ap-northeast-1.amazonaws.com. 55 IN AAAA 2406:da14:daa:7d01:bbb:ab6d:c9f7:8dc4
nlb-XXX.elb.ap-northeast-1.amazonaws.com. 55 IN AAAA 2406:da14:daa:7d02:ccc:dde1:6d28:4840
```

次に自身のドメインに対して名前解決ができるか確認しておきます。

```
dig test.XXX.com AAAA

;; ANSWER SECTION:
test.XXX.com.    60      IN      AAAA    2406:da14:daa:7d00:aaa:515:446a:879e
test.XXX.com.    60      IN      AAAA    2406:da14:daa:7d01:bbb:ab6d:c9f7:8dc4
test.XXX.com.    60      IN      AAAA    2406:da14:daa:7d02:ccc:dde1:6d28:4840
```

名前解決ができることを確認できたら、早速自身のドメインに対して通信してみましょう。

```
curl -v https://test.XXX.com/prod/hello -H 'Host: XXX.execute-api.ap-northeast-1.amazonaws.com'

*   Trying [2406:da14:daa:7d00:aaa:515:446a:879e]:443...
* Connected to test.XXX.com (2406:da14:daa:7d00:aaa:515:446a:879e) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=test.XXX.com
*  start date: Oct 23 00:00:00 2023 GMT
*  expire date: Nov 20 23:59:59 2024 GMT
*  subjectAltName: host "test.XXX.com" matched cert's "test.XXX.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/1.x
> GET /prod/hello HTTP/1.1
> Host: XXX.execute-api.ap-northeast-1.amazonaws.com
> User-Agent: curl/8.3.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
< HTTP/1.1 200 OK
< Server: Server
< Date: Tue, 24 Oct 2023 09:43:55 GMT
< Content-Type: application/json
< Content-Length: 26
< Connection: keep-alive
< x-amzn-RequestId: f9421056-52bf-4d50-b23e-d41ae5bfcfe8
< x-amz-apigw-id: NTO6TFMqNjMFy0w=
< X-Amzn-Trace-Id: Root=1-653791db-29199c1f0b7e7f61a2ab530f;Sampled=0;lineage=9f7680ef:0
< 
* Connection #0 to host test.XXX.com left intact
{"message": "hello world"}
```

無事IPv6から接続できたことが確認できたと思います。


# ログ

一応ログを確認しておきましょう。（ログの作成手順は省きます。）

先程AAAAレコーは確認しておきましたが、NLBからAPI Gatewayまでの通信はIPv4になるので先にNLBのAレコードも確認しておきましょう。

```
dig nlb-XXX.elb.ap-northeast-1.amazonaws.com.  A

nlb-XXX.elb.ap-northeast-1.amazonaws.com. 60 IN A 172.31.3.77
nlb-XXX.elb.ap-northeast-1.amazonaws.com. 60 IN A 172.31.17.207
nlb-XXX.elb.ap-northeast-1.amazonaws.com. 60 IN A 172.31.40.17
```


## NLBのログ

EC2（2406:da14:daa:7d00:yyy:9f5f:c5c9:b43d）からNLB（2406:da14:daa:7d00:aaa:515:446a:879e）までは、IPv6で通信できていることが確認できます。

```
tls 2.0 2023-10-24T10:07:44 net/nlb/b2d777644ffaacc9 f25f1970aa026308 2406:da14:daa:7d00:yyy:9f5f:c5c9:b43d:53732 2406:da14:daa:7d00:aaa:515:446a:879e:443 77 37 124 352 - arn:aws:acm:ap-northeast-1:123456789012:certificate/- - TLS_AES_128_GCM_SHA256 tlsv13 - test.XXX.com - - - 2023-10-24T10:07:44
```

## API Gatewayのログ

NLB（172.31.17.207）からアクセスが来ていることが確認できました。

```
　{
    "requestId": "8ecb4541-a106-40db-9785-d3b564917845",
    "ip": "172.31.17.207",
    "caller": "-",
    "user": "-",
    "requestTime": "24/Oct/2023:10:47:11 +0000",
    "httpMethod": "GET",
    "resourcePath": "/hello",
    "status": "200",
    "protocol": "HTTP/1.1",
    "responseLength": "26"
}
```