SREチーム所属の大嶋です。Advent Calendarは2年目になります。
この記事はZOZOテクノロジーズ #2 Advent Calendar 2019 21日目の記事になります。
弊社では全部で5つのAdvent Calendarが公開しています。
ZOZOテクノロジーズ #1 Advent Calendar 2019
ZOZOテクノロジーズ #2 Advent Calendar 2019
ZOZOテクノロジーズ #3 Advent Calendar 2019
ZOZOテクノロジーズ #4 Advent Calendar 2019
ZOZOテクノロジーズ #5 Advent Calendar 2019
概要
ZOZOテクノロジーズ #5 Advent Calendar 2019 10日目の記事においてNLB配下でgRPC通信するときに考えるALPN対応状況という内容が公開されています。
上記記事の振り返りで述べられている以下内容に我々のチームで直面しました。
ALPN対応のgrpcライブラリが用意されているJavaやNode.jsなどの言語で、かつ外部通信用にgRPCのAPIを公開(NLB使う)する方式だと苦しいなと思いました。
この場合は、EnvoyやNginxにTLS終端させて、ACMは諦めるという方向になるでしょうか。。。
この内容について我々のチームがどのような対処をしたのか書かせて頂きます。
課題
NLBでのALPNが未対応のため、gRPCでconnection errorが発生していました。そのため一時的にSSL暗号化をせず検証していました。
上記状態を解消するために今回はenvoyにてSSL終端を実施しました。
普段であればELBでのSSL終端を実施していたので、初めての検証となりました。
こちらが構築イメージになります。
Client-envoy間は暗号化し、envoyにて複合するように設計しました。
#実施作業事項
- SSL証明書準備、配置
- envoyにてTLS設定を追加
- envoyの受信Portを443に変更
- NLBのListenerPortを443に変更
- 動作確認
SSL証明書準備、配置
今回は検証のため自己署名証明書を利用します。
$ openssl req -nodes -x509 -newkey rsa:4096 -keyout example-com.key -out example-com.crt -days 365
そして/etc/配下に配置します。
ADD ./example-com.crt /etc/server.crt
ADD ./example-com.key /etc/server.key
envoyにてTLS設定を追加
tls_context:
common_tls_context:
alpn_protocols:
- "h2,http/1.1"
tls_certificates:
- certificate_chain:
filename: "/tmp/server.crt"
private_key:
filename: "/tmp/server.key"
インデントに注意してください。僕はズレててハマったので、以下を参考にどうぞ。
参考:Example configuration
envoyのPortを443に変更
ports:
- name: https
containerPort: 443
上記に加え、ヘルスチェックなどのPortも443に変更してください。
NLBのListenerPortを443に変更
apiVersion: v1
kind: Service
metadata:
name: envoy
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
type: LoadBalancer
selector:
app: envoy
ports:
- name: https
protocol: TCP
port: 443
targetPort: 443
動作確認
$ curl -k -vvv --http2-prior-knowledge https://test.com:443
* Rebuilt URL to: https://test.com:443/
* Trying XX.XX.XX.XX...
* TCP_NODELAY set
* Connected to test.com (XX.XX.XX.XX) 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/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, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (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: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=test.com
* start date: Dec 20 06:44:26 2019 GMT
* expire date: Dec 19 06:44:26 2020 GMT
* issuer: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=test.com
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* 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 0x7fc69d004400)
> GET / HTTP/2
> Host: test.com
> User-Agent: curl/7.54.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 404
< content-length: 0
< date: Mon, 23 Dec 2019 03:00:57 GMT
< server: envoy
< x-envoy-upstream-service-time: 27
<
* Connection #0 to host test.com left intact
無事TLSでのハンドシェイクを通過し、HTTP2で通信することができました。
適当なパスをcurlしているので、404が出てますが一旦検証としては完了とします。
まとめ
現在は検証段階なので、追加で気づいたことがあれば別記事で更新させて頂きます。
最後までお付き合い頂きありがとうございました!