[小ネタ]NLB で ALPN ポリシーを使う場合でも NLB での TLS 終端は出来るという話

NLB で ALPN ポリシーを使う場合でも NLB での TLS 終端は出来る
2022.11.12

お疲れさまです。とーちです。

最近、gRPC を少し触る機会があり AWS 上の gRPC サーバに対しての負荷分散方法を調べていました。
調べる中で NLB で ALPN ポリシーを使用する場合は NLB で TLS 終端出来ない(TLS ターゲットグループが必須となる)という記事をいくつか見かけたので、そういうものなのかと思っていたのですが、実際に試してみたところ TLS ターゲットグループは必須ではなかったのでその共有をしたいと思います。

この記事で伝えたいこと

この記事で伝えたいのはこの1点だけで、後はおまけです。

  • NLB で ALPN ポリシーを使う場合でも NLB での TLS 終端は出来る

AWS ドキュメント上の記載について

NLB が ALPN ポリシーをサポートしたのは2020/5/27からなのですが、当時のドキュメント上では弊社ブログにも記載のある通り、

・Requirements

  • TLS listener
  • TLS target group

と記載されていたようです。ところが現在の最新の ドキュメントを見てみるとこの記載は削除されています。 記載がなくなっているということは TLS 終端出来るのではと思い試してみることにしました。

余談ですが、GitHub 上では2022/2/2のコミットで該当部分の記載が削除されていることが確認出来ます。

実際にやってみる

実際にやってみます。構成はこんな感じです。

NLB の TLS リスナーは以下の設定にしました。矢印の箇所が示す通り ALPN ポリシーを「HTTP2Only」で有効にしています。

ターゲットグループの設定はこんな感じです。プロトコルが TLS ではなくTCPになっていることをご確認ください。

ECS タスク上の Nginx 設定は以下の通りシンプルなものです。listen に http2 を指定することで http2 が有効となります。当然ですが、TLS 証明書は入れていません。

server {

    listen 8080 http2;
    server_tokens off;

    location = /api/_/healthz {
        empty_gif;
        break;
    }
}

この状態でクライアント PC から curl コマンドを実行してみました。結果は以下の通り、問題なく通信出来ています。 サーバ側からの「ALPN: server accepted h2」により HTTP/2 通信でやり取りすることが確定された様子が分かります。

> curl -v https://test.****.com/api/_/healthz
*   Trying xxx.xxx.xxx.xxx:443...
* Connected to test.****.com (xxx.xxx.xxx.xxx) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=****.com
*  start date: Nov  7 00:00:00 2022 GMT
*  expire date: Dec  7 23:59:59 2023 GMT
*  subjectAltName: host "test.****.com" matched cert's "*.****.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /api/_/healthz]
* h2h3 [:scheme: https]
* h2h3 [:authority: test.****.com]
* h2h3 [user-agent: curl/7.84.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x154010e00)
> GET /api/_/healthz HTTP/2
> Host: test.****.com
> user-agent: curl/7.84.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< server: nginx
< date: Fri, 11 Nov 2022 15:04:57 GMT
< content-type: image/gif
< content-length: 43
< last-modified: Mon, 28 Sep 1970 06:00:00 GMT

nginx 側ログにも HTTP/2 で通信しているログが記録されていました。

xxx.xxx.xxx.xxx - - [11/Nov/2022:14:58:42 +0000] "GET /api/_/healthz HTTP/2.0" 200 43 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" "-"

まとめ

短い内容でしたが以上となります。自分がネットで調べてみた時に、NLB が ALPN ポリシーを使っているときに TLS 終端出来ることを書いているサイトが見つけられなかったので、自分で記事にしてみました。
この記事が誰かのお役に立てばなによりです。

以上、とーちでした。