この記事は公開されてから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)でした!