Amazon VPCエンドポイントサービスをHTTP/2対応にする

任意のAWSアカウントのVPCにサービスが提供できるVPCエンドポイントサービスでのHTTP/2対応を試してみました。
2020.06.08

ども、ゲストのソラコム大瀧です。

VPCエンドポイントサービスは、PrivateLinkという技術でAWSアカウントをまたぐ任意のTCPサービスをセキュアに提供できる仕組みです。VPCエンドポイントサービスの内部で利用するNetwork Load Balancer(以下NLB)が最近ALPNをサポートしたことにより、HTTP/2でのサービス提供が可能になりました。本エントリーではその構成をやってみた様子をご紹介します。

動作確認環境

  • AWSリージョン : 東京リージョン
  • NLBのターゲット : EC2 Amazon Linux 2 (AMI: amzn2-ami-hvm-2.0.20200520.1-arm64-gp2 (ami-01e7d6c28d99b213c 東京リージョン))

手順

1. ホスト名とTLS証明書の準備

事前にドメインと今回のためのホスト名を用意しておきましょう。ドメインはレジストラで購入するパブリックなものが必要ですが、ホスト名は後述するプライベートDNS機能を利用するためパブリックなDNSレコードを用意する必要はありません。

今回のHTTP/2構成では、クライアント-VPCエンドポイント間でTLSによる暗号化通信を行うために、クライアントがアクセスするホスト名とTLS証明書のCommon Nameを合わせます。しかし、VPCエンドポイントが既定で提供するホスト名は、ランダム文字列を含むamazonaws.comドメインのため、ユーザーがTLS証明書を用意するのは難しいです。そこで今回の構成では、VPCエンドポイントサービスで設定するプライベートDNS名がお奨めです。プライベートDNS名は、ユーザーが所有するドメインのホスト名をクライアントのVPCからVPCエンドポイントに名前解決できる仕組みです。NLBに設定するTLS証明書の構成と合わせることで、TLS証明書のエラーを回避することができます。AWSであれば、Route 53でDNSドメイン、ACM(AWS Certificate Manager)でTLS証明書を構成するのが簡単なので、今回の手順ではそれらを利用します。

2. ターゲットEC2インスタンスの構成

まずはターゲットとなるEC2インスタンスを起動し、Apacheをインストールします。

$ sudo yum install httpd mod_ssl

Amazon LinuxのApacheでは既定でHTTP/2(mod_http2)が有効で自己署名証明書が設置済みなので、EC2のセットアップはこれでOKです。NLBからのHTTPSトラフィック(tcp/443)が受信できるようにセキュリティグループをセットしておきましょう。

3. ACMとNLBの構成

続いてNLBです。先にTLS証明書をACMで発行しておきます。手順はこちらの記事と同様に、今回は後ほどNLBに設定するホスト名vpce.takipone.comの証明書を用意しました。

続いてEC2管理画面のメニュー[ロードバランサー]から[ロードバランサーの作成]ボタンをクリックし、NLBを作成していきます。

[ロードバランサーの種類の選択]は[Network Load Balancer]の[作成]ボタンをクリックします

[手順1. ロードバランサーの設定]画面では、以下を設定します。

  • 任意の名前とスキームを入力します。VPCエンドポイントサービス向けには「内部」を選択します。
  • リスナーは「TLS(セキュア TCP)」を選択します。ロードバランサーのポートはクライアントからアクセスするポート番号なので、特別な指定がなければ既定の443で良いでしょう。
  • アベイラビリティゾーンは、ロードバランサーのノードを配置するアベイラビリティゾーンとVPCサブネットをそれぞれ選択します。

[手順2. セキュリティ設定の構成]画面では、TLS関連の設定を選択します。デフォルトの証明書の選択では、先ほど作成したACMの証明書を選択します。セキュリティポリシーの選択は既定のままにし、ALPNポリシーはHTTP/2を許容するHTTP/2OnlyHTTP/2OptionalHTTP/2Preferedの3つから望ましい挙動を選びましょう。今回はHTTP/2Preferedにしました。

[手順3. ルーティングの設定]画面ではターゲットグループを作成します。プロトコルを[TLS]に選択するのがポイントです。

[手順 4: ターゲットの登録]画面では、さきほど作成したApacheを実行するEC2インスタンスを選択し、[登録済みに追加]ボタンをクリックし登録します。

[確認]ボタン→[作成]ボタンでNLBの作成が開始します。[状態]が「active」になったら作成完了です。

ちなみに、↑の画像のようにロードバランサの[リスナー]タブにはALPNポリシーに関する警告が表示されますが注意喚起のために常時表示されるものなので、構成上の問題はありません。

4. VPCエンドポイントサービスの構成

次は、作成したNLBに他のVPCからアクセスできるようにVPCエンドポイントサービスに登録します。VPC管理画面のメニュー[エンドポイントのサービス]から[エンドポイントサービスの作成]ボタンをクリックします。

作成画面では、[Network Load Balancerの関連付け]で先ほど作成したNLBを選択します。[Enable private DNS name]のチェックをオンにし、[Private DNS name]にクライアントがアクセスするホスト名(=ロードバランサに設定したTLS証明書のホスト名)を入力、[サービスの作成]ボタンをクリックすればサービスが作成されます。

サービスの作成完了画面では、プライベートDNS利用のために、ドメインの所有権を確認するレコードを登録する案内が表示されます。

今回はドメインのHosted ZoneをRoute 53で管理しているので、以下のように確認レコードを追加しました。

エンドポイントサービスのプロパティにある[Domain verification status]がVerifiedになれば確認成功です。

これでエンドポイントサービス側VPCの構成はOKです。このあとVPCエンドポイントを作成するときに指定するエンドポイントサービス名com.amazonaws.vpce.<リージョン名>.vpce-svc-XXXXXXXXXXXXを控えておきましょう。

5. VPCエンドポイントの構成

それでは、エンドポイントサービスとは異なるVPCにVPCエンドポイントを作成し、VPCを超えたHTTP/2接続を試してみます。VPC管理画面メニューの[エンドポイント]を選択し、[エンドポイントの作成]ボタンをクリックします。

エンドポイントの作成画面では、[サービスカテゴリ]で[サービスを名前で検索]を選択し、[サービス名]に手順4で作成したエンドポイントサービス名を貼り付けて[検証]ボタンをクリックします。[VPC]はクライアントが利用するVPCを選択し、アベイラビリティゾーンごとにVPCエンドポイントを配置するVPCサブネット(クライアントからアクセスできる任意のVPCサブネット)を選択します。

画面の中ほどでは、[プライベートDNS名を有効にする]のチェックをオンにし、セキュリティグループはクライアントからのHTTPS(tcp/443)アクセスを許可するセキュリティグループを作成ないし指定します。

[エンドポイントの作成]ボタンをクリックすれば、作成が開始します。ステータスが[保留中]になり、しばらく待つと[使用可能]になりますが、待てなければエンドポイントサービスの[エンドポイント接続]タブで[アクション] - [エンドポイント接続リクエストの承認]をクリックして促すこともできます。

これでVPCエンドポイントが作成されました。

動作確認

それでは、クライアントとなるEC2からcurlコマンドでアクセスしてみます。

$ curl --http2 -v https://vpce.takipone.com/
*   Trying 10.0.11.88...
* TCP_NODELAY set
* Connected to vpce.takipone.com (10.0.11.88) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* 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=vpce.takipone.com
*  start date: Jun  7 00:00:00 2020 GMT
*  expire date: Jul  7 12:00:00 2021 GMT
*  subjectAltName: host "vpce.takipone.com" matched cert's "vpce.takipone.com"
*  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 0x2ca6a990)
> GET / HTTP/2
> Host: vpce.takipone.com
> User-Agent: curl/7.61.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 403
< date: Sun, 07 Jun 2020 10:19:18 GMT
< server: Apache/2.4.43 () OpenSSL/1.0.2k-fips
< last-modified: Fri, 08 May 2020 17:01:39 GMT
< etag: "e2e-5a525f35ec2c0"
< accept-ranges: bytes
< content-length: 3630
< content-type: text/html; charset=UTF-8
<
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
	:(以下略)
$

正しくHTTP/2で通信できていますね!また、アクセスしているIPアドレスがクライアントと同じVPC内のIPアドレスになっているのでVPCエンドポイント宛に通信している様子もわかります。

ちなみにApacheのアクセスログを見てみると...

/var/log/httpd/ssl_access_log

172.30.1.213 - - [07/Jun/2020:10:19:18 +0000] "GET / HTTP/2.0" 403 3630

こんな感じで残ります。172.30.1.213はNLBのIPアドレスですね。PrivateLink経由でクライアントIPアドレスやアクセス元のVPCエンドポイントIDを取得するためにはProxy Protocolバージョン2の有効化で対応できます。ターゲットのミドルウェア側での対応が必要になるので、こちらのエントリーを参考に検討しても良いかもしれません。

まとめ

VPCエンドポイントサービスを介してHTTP/2通信が出来る様子をご紹介しました。HTTP/2が必須というケースは多くないと思いますが、他のAWSユーザーのVPC向けにSaaSサービスを展開するようなシナリオでHTTP/2が使えるのは、けっこう便利な場合があるかもしれません。

参考URL