[アップデート] Network Load Balancer で TLS ALPN がサポートされたので HTTP/2 が可能になりました。

HTTP/2でTLSの通信効率向上に期待
2020.05.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本日のアップデートで Network Load Balancer(NLB)が TLS ALPN(Application-Layer Protocol Negotiation) をサポートするようになりました。

何が嬉しいのか

TLS リスナーで HTTP/2 が利用可能に

これまで NLB の TLS リスナーでは ALPN に対応していなかったため、HTTP/2 で受けることが出来ませんでした。そのため、NLB を介した HTTP/2 通信をするには TLS リスナーではなく TCP リスナーとして NLB を構成する必要がありました。

この場合、NLB は TCP パススルーとしてのみ機能しますので、TLS ネゴシエーションや、TLS の暗号化/復号といった処理は NLB のターゲットとなるサーバー側で行うこととなり、少なからず TLS 通信のための負荷が掛かることになります。

今回、gRPC は試していませんが、従来であれば以下の記事のように TCP リスナーとしてエンドツーエンドでの TLS ネゴシエーションだったところを、NLB の TLS リスナーで対応できるようになるかと思います。

ちなみに ALB の場合は、ALPN に対応していますが、ALB が HTTP/2 を HTTP/1.1 に変換してターゲットグループに流しますので、gRPC などは利用できません。

Application Load Balancer は、HTTPS リスナーに HTTP/2 のネイティブサポートを提供します。1 つの HTTP/2 コネクションで最大 128 のリクエストを並行して送信できます。ロードバランサーは、これらのリクエストを個々の HTTP/1.1 のリクエストに変換し、ターゲットグループの正常なターゲットにこれを分配します。

(引用:Application Load Balancer のリスナー

TLS リスナーで終端は出来ない!?

今回のアップデートを見たとき、TLS リスナーで終端できるのだろうと思っていたのですが、ALPN ポリシーを利用する場合は、TLS リスナーに加えて TLS ターゲットグループが必須要件となっていますので、ターゲット側でも何らかの証明書が必要なようです。

・Requirements
- TLS listener
- TLS target group

(引用:TLS Listeners for Your Network Load Balancer

なにわともあれ、HTTP/2 によって従来の HTTP/1.1 に比べて効率的な通信が利用できることに変わりはないですね。

やってみる

事前準備

NLB のターゲットとなる EC2 に証明書を作成しておきます。今回は以下の記事を参考に、自動生成された自己証明書を利用しました。

$ cert -k 18.181.203.233:443
DomainName: 18.181.203.233
IP:         18.181.203.233
Issuer:     ip-192-168-0-129.ap-northeast-1.compute.internal
NotBefore:  2020-05-28 07:11:04 +0900 JST
NotAfter:   2021-06-02 08:51:04 +0900 JST
CommonName: ip-192-168-0-129.ap-northeast-1.compute.internal
SANs:       [ip-192-168-0-129.ap-northeast-1.compute.internal]
Error:

ターゲットグループ

ALPN ポリシーでサポートされるターゲットグループグループは TLS のみです。

リスナー

ALPN ポリシーでサポートされるリスナーも TLS のみです。リスナー設定時に、以下のように ALPN ポリシーの設定項目が追加されています。今回は HTTP/2 が優先される HTTP2Preferred を指定しています。

ALPN ポリシーが有効である場合、ALPN Policy only applies when forwarding to a TLS target group との警告メッセージが常時でているようです。

確認

それでは curl コマンドでリクエストを送ってみます。手順は割愛していますが、作成した NLB は http2.marumo.classmethod.info として Route53 に登録しています。

HTTP/2対応

$ curl -v  https://http2.marumo.classmethod.info
*   Trying 52.194.162.22...
* TCP_NODELAY set
* Connected to http2.marumo.classmethod.info (52.194.162.22) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (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 to use h2
* Server certificate:
*  subject: CN=*.marumo.classmethod.info
*  start date: Nov 22 00:00:00 2019 GMT
*  expire date: Dec 22 12:00:00 2020 GMT
*  subjectAltName: host "http2.marumo.classmethod.info" matched cert's "*.marumo.classmethod.info"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fc488008200)
> GET / HTTP/2
> Host: http2.marumo.classmethod.info
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 200
< date: Thu, 28 May 2020 03:51:17 GMT
< server: Apache/2.4.43 () OpenSSL/1.0.2k-fips
< last-modified: Wed, 27 May 2020 21:49:34 GMT
< etag: "1b-5a6a8300d4035"
< accept-ranges: bytes
< content-length: 27
< content-type: text/html; charset=UTF-8
<
<html>
Classmethod
</html>
* Connection #0 to host http2.marumo.classmethod.info left intact
* Closing connection 0

HTTP/2 で通信されていることが判ります。サーバー側の ssl_access_log でも "GET / HTTP/2.0" が確認できます。

101.xx.xx.xx - - [28/May/2020:03:51:17 +0000] "GET / HTTP/2.0" 200 27

ALPN 無効で試す

従来の ALPN 無効に戻した状態でも試してみます。

HTTP/2非対応

$ curl --http2 -v  https://http2.marumo.classmethod.info
*   Trying 52.194.162.22...
* TCP_NODELAY set
* Connected to http2.marumo.classmethod.info (52.194.162.22) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (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 did not agree to a protocol
* Server certificate:
*  subject: CN=*.marumo.classmethod.info
*  start date: Nov 22 00:00:00 2019 GMT
*  expire date: Dec 22 12:00:00 2020 GMT
*  subjectAltName: host "http2.marumo.classmethod.info" matched cert's "*.marumo.classmethod.info"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: http2.marumo.classmethod.info
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 28 May 2020 03:58:08 GMT
< Server: Apache/2.4.43 () OpenSSL/1.0.2k-fips
< Upgrade: h2,h2c
< Connection: Upgrade
< Last-Modified: Wed, 27 May 2020 21:49:34 GMT
< ETag: "1b-5a6a8300d4035"
< Accept-Ranges: bytes
< Content-Length: 27
< Content-Type: text/html; charset=UTF-8
<
<html>
Classmethod
</html>
* Connection #0 to host http2.marumo.classmethod.info left intact
* Closing connection 0

ALPN, server did not agree to a protocol とされており、HTTP/1.1 の通信になっていることが判ります。ssl_access_log でも "GET / HTTP/1.1" が確認できます。

101.xx.xx.xx - - [28/May/2020:03:58:08 +0000] "GET / HTTP/1.1" 200 27

さいごに

今回、TLS ALPN 対応により HTTP/2 の利用が可能となったわけですが、あらためて 「HTTP/2 って?」と考えると「TLS ネゴシエーションや、暗号化/復号、効率的な通信ができるんですよね…」くらいのふわっとした知識しかないことを認識したので、これを機に深堀りしてみようと思います。

その先に来るであろう QUIC なども見据えた HTTP/2 まわりのアップデートなのかな… などと想像するのも楽しいですね。

以上!大阪オフィスの丸毛(@marumo1981)でした!