envoyは高機能なネットワークプロキシで、サポートするプロトコルが豊富、動的に構成変更が可能といった特長があります。 高機能プロキシ共通の課題としてconfigが複雑であるため、構成を理解することが適切な設定に必要となります。
導入着手の際、重要なリソースには以下のようなものがあります。
- dockerの
envoy公式イメージを利用するのが手軽。
- 起動configとして、
/etc/envoy/envoy.yaml
を参照する。このファイルの記述が適切であれば動作する。誤りがあると起動ログにエラー表示して終了。
- 起動configとして、
- 情報源は、
公式ドキュメントを最重視すべき
- そもそも情報は少ない。また、configフォーマットがバージョン間で頻繁に変更されており、非公式な情報の書き方がdeprecatedになっているケースが多い。
- 公式ドキュメントの情報量は多く、全体的に通読した方がconfigの構成を理解しやすい
configのトップレベル要素は以下のような構成になっています。
admin
オブジェクトは必須要素だが、基礎的な使い方の範囲ではさほどカスタマイズする必要はない。 Simple Configurationの記述と同じ内容でも動作する。static_resources
内のlisteners
とclusters
を目的に沿って適切に設定する。- xDS規約に沿ってファイルを分割した方が良い。バックエンドホストが増えるとconfigが長くなる
- YAMLには空白行や行頭
#
コメントを書けるので、見やすさのための区切りを入れると良い
Listener
Listenerは、流入するDownstreamリクエストをポート単位で定義するオブジェクトです。
主要な内部オブジェクトとして
Filterを定義し、L7プロキシの典型的な用途ではホスト名やパスに基づいてルーティングやリダイレクトなどを処理します。
listeners.filter_chains.filters[]
に個別のフィルタを定義-
HTTP connection managerが汎用のL7プロキシ向けオブジェクト
- route_config.virtual_hosts[].routes[] がルーティング定義
stat_prefix
は必須http_filters
は必須。指定しない場合、起動するがレスポンスなしでタイムアウトする動作になる
-
HTTP connection managerが汎用のL7プロキシ向けオブジェクト
- Basic認証、 JWT認証、 TCPプロキシはListenerに設定
- アクセスIPはデフォルトでは別のプロキシから
X-FORWARDED-FORを受け取る想定になっている。HTTP connection manager設定に
use_remote_address: true
を指定するとピアのIPを参照する挙動となり、アクセスログのREQ(X-FORWARDED-FOR)
にもこの値が入る
また、以下の点は注意が必要です。
-
VirtualHostの
domains
は対象とするドメイン文字列を設定するフィールドで、ワイルドカードも指定できます。開発環境などで非ウェルノウンポートを使う場合、この文字列にポート番号まで含めないとマッチしません(例:"*.example.com:8443")。domains
の定義が意図と異なる場合にもenvoyは特に問題なく起動します。VirtualHostにマッチする定義がなかった場合、リクエストはUpstreamホストに到達せず、分かりづらい挙動になります。
SSL証明書
SSLを使用する場合、 listeners.filter_chains.transport_socketに DownstreamTlsContextを設定します。以下のように証明書と秘密鍵のpathを指定すると動作します。
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain:
filename: "/etc/envoy/fullchain.pem"
private_key:
filename: "/etc/envoy/privkey.pem"
tls_certificates
はArrayを指定できますが、clientとの通信に設定できる証明書は1つに限られ、複数ドメインの証明書を指定するとエラーとなり起動しません。
基本的に証明書を複数指定したい場合には、listenerを分割する必要があります。
SNI
SNIによるマルチドメイン収容は、API v3で追加されました。
Listenerフィルターenvoy.filters.listener.tls_inspector
を追加すると、ドメイン名ごとに設定を分割できます。
なおv1.23頃からtyped_config
は必須になりました。
listener_filters:
- name: "envoy.filters.listener.tls_inspector"
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
- filter_chain_match:
server_names: ["example.com", "www.example.com"]
filters:
# listener config
- filter_chain_match:
server_names: "api.example.com"
filters:
# listener config
これにより、transport_socket
セクションもドメインごとに設定でき、SSL証明書の使い分けが可能になります。
server_names
にはワイルドカードも使えますが、サブドメインに限定される挙動であるため書き方には注意が必要です。
Cluster
Clusterは、Upstreamのサービス群を定義するオブジェクトです。configのネストは深いものの、基本的にはバックエンドのアドレスを登録することで動作します。
- 上流のホストは、
cluster.type
の設定と連動して、IPアドレス(デフォルト)またはホスト名で指定する。typeの種類は、 Supported service discovery typesを読んで理解しておく。- kubernetesのサービスホストで名前解決することも可能
なお、存在しないホストを登録した場合にも特にエラーなく起動します。ネットワークが不安定な場合にも起動への影響はなさそうです。
クライアント証明書認証
mTLSなどに用いるクライアント証明書認証は、
common_tls_contextのvalidation_context
オブジェクトとして指定します。
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
validation_context:
trusted_ca:
filename: "/etc/envoy/ca.crt"
require_client_certificate: true
この設定例では、検証方法は認証局との信頼チェーンのみです(require_client_certificate
の記述位置がcommon_tls_context
の外であることに注意)。追加の検証方法は、
validation_contextにオプションが定義されています。
config中の設定ポジションは以下のとおりです。
- DownStreamは
listeners[].filter_chains[].transport_socket.typed_config
- UpStreamは
clusters[].transport_socket.typed_config
なお、trusted_ca
に指定する認証局の証明書ファイルは期限も含めて有効なファイルを使用する必要があります。無効なものを指定した場合、クライアント側に要求も表示されず分かりづらい挙動となるため、開発環境などで注意が必要です。
Chuma Takahiro