Envoy Gateway TLS とセキュリティ: HTTPS を設定し、API を裸で走らせない
HTTP が動いたら、そこはまだウォームアップです。あなたの service が石器時代に住んでいない限り、本番ではほぼ確実に HTTPS が必要です。この記事では、Envoy Gateway における TLS の基本を整理し、API を平文で走らせないための土台を固めます。
Gateway で TLS はどう動くのか
最も一般的なやり方は、Gateway listener で TLS を terminate することです。
意味:
- client は HTTPS で接続する
- Gateway が handshake と証明書を処理する
- その後のトラフィックは内部では平文のまま Service へ転送される
基本的な HTTPS listener はこうです。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
group: ""
name: example-certここで大事なのは 2 点です。
protocol: HTTPStls.mode: Terminate
つまり、TLS はここで終端し、Gateway が証明書を扱うということです。
HTTPS + HTTPRoute と TLSRoute の違い
ここは重要です。TLSRoute を見ると、多くの人がすぐこう思います。
「HTTPS listener があれば足りるのでは? なぜ別に TLSRoute が必要なの?」
違いは Gateway が TLS を terminate するかどうか にあります。
| シナリオ | よくある組み合わせ | 説明 |
|---|---|---|
| Gateway が TLS を terminate し、その後 HTTP ルールを適用する | HTTPS listener + HTTPRoute |
最も一般的な web サイト / API パターン |
| Gateway は復号せず、SNI だけで暗号化トラフィックを route する | TLS listener + TLSRoute |
TLS passthrough パターン |
つまり:
- Gateway で
path、header、methodを見たいなら、まず TLS を terminate してからHTTPRouteを使う必要がある - end-to-end 暗号化を保ち、Gateway で復号したくないなら
TLSRouteが正しい道筋
どちらが「より上級」かではありません。大事なのは、自分が欲しいのが「TLS を terminate して L7 routing したい」のか、「暗号化を保ったまま SNI ベース routing したい」のかを理解することです。
証明書 Secret を用意する
テスト環境なら self-signed certificate で十分です。公式例でもこの形を使っています。
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization"
openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crtcert/key を Kubernetes Secret として保存します。
kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crtその後 Gateway から certificateRefs 経由でこの Secret を参照できます。
⚠️ self-signed cert はテスト用に限ります。本番では cert-manager など既存の証明書管理フローを使ってください。デモ構成をそのまま本番へ持ち込むのは、カップ麺だけで生活するようなもので、たまにならいいけれど長期運用には向きません。
既存 Gateway に HTTPS listener を追加する
前の記事の eg Gateway がすでにあるなら、そのまま patch できます。
kubectl patch gateway eg --type=json --patch '
- op: add
path: /spec/listeners/-
value:
name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
group: ""
name: example-cert
'status を確認します。
kubectl get gateway/eg -o yamllistener が正常そうなら HTTPS を試します。
curl -v -HHost:www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" --cacert example.com.crt https://www.example.com/getこのコマンドはローカル検証にかなり便利です。特に DNS がまだ張られていない段階で役立ちます。
1 つの Gateway で複数 HTTPS domain を扱う
複数 domain がある場合、同じ Gateway に複数の HTTPS listener を追加します。
たとえば foo.example.com を足すなら:
listeners:
- name: https-main
protocol: HTTPS
port: 443
hostname: www.example.com
tls:
mode: Terminate
certificateRefs:
- name: example-cert
- name: https-foo
protocol: HTTPS
port: 443
hostname: foo.example.com
tls:
mode: Terminate
certificateRefs:
- name: foo-cert対応する HTTPRoute 側の hostname も正しく更新するのを忘れないでください。listener が待ち受けていても、route が送信先を知らなければトラフィックは流れません。
TLSRoute のメンタルモデル
TLS passthrough では、TLSRoute を次のように捉えるとわかりやすいです。
💡
TLSRouteのapiVersionは、インストールしている Gateway API CRD の version によって異なる場合があります。以下は概念説明用の例です。適用前に cluster に入っている version を確認してください。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg-tls
spec:
gatewayClassName: eg
listeners:
- name: tls
protocol: TLS
port: 443
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: passthrough-route
spec:
parentRefs:
- name: eg-tls
hostnames:
- "db.example.com"
rules:
- backendRefs:
- name: db-service
port: 5432このパターンのよくある用途:
- SNI hostname だけで route する
- 暗号化を backend まで保つ
- Gateway では HTTP path/header を解釈しない
つまり TLSRoute と HTTPRoute の違いは名前だけではなく、扱っているトラフィック層がまったく違います。
Cross-Namespace の証明書参照
公式ドキュメントが強調している便利な機能があります。
Gateway は他 namespace の certificate Secret を参照できますが、そのためには ReferenceGrant が必要です。
たとえば platform team が envoy-gateway-system に証明書を集約し、application 側の Gateway が default にある場合、明示的な許可なしに namespace をまたいで参照することはできません。
例:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-default-to-read-cert
namespace: envoy-gateway-system
spec:
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: default
to:
- group: ""
kind: Secret意味:
defaultnamespace のGatewayがenvoy-gateway-systemにあるSecretを参照することを許可する
ReferenceGrant がなければ、この cross-namespace reference は invalid として扱われます。Gateway API が意地悪なのではなく、防御のための仕組みです。
一文まとめ
Envoy Gateway の TLS は、響きほど謎ではありません。certificate Secret を用意し、HTTPS listener を設定し、route と hostname を揃える。基本はこれでほぼ完了です。
💡 初心者が最もやりがちな失敗は、TLS が難しすぎることではありません。
hostname、certificateRefs、HTTPRoute hostnamesの 3 つが揃っていないことです。どれか 1 つずれると、トラフィックはすぐ不機嫌になります。
次の一歩
インストール、概念、routing、TLS を一通り見たので、次の記事ではそれらを本番で爆発しにくい実践知にまとめます。 👉 ベストプラクティス