TLS
Envoy 支援監聽器中的 TLS 終止,以及在連線到上游叢集時的 TLS 發起。Envoy 的支援足以為現代網路服務執行標準邊緣代理任務,以及發起與具有進階 TLS 需求(TLS1.2、SNI 等)的外部服務的連線。Envoy 支援下列 TLS 功能
可設定的密碼:每個 TLS 監聽器和用戶端都可以指定它支援的密碼。
用戶端憑證:除了伺服器憑證驗證外,上游/用戶端連線可以呈現用戶端憑證。
憑證驗證和釘選:憑證驗證選項包括基本鏈驗證、主體名稱驗證和雜湊釘選。
憑證撤銷:如果提供憑證撤銷清單 (CRL),Envoy 可以根據憑證撤銷清單 (CRL) 檢查對等憑證。提供。
ALPN:TLS 監聽器支援 ALPN。HTTP 連線管理員會使用此資訊(以及協定推斷)來判斷用戶端是否正在使用 HTTP/1.1 或 HTTP/2。
SNI:伺服器(監聽器)和用戶端(上游)連線都支援 SNI。
會話恢復:伺服器連線支援透過 TLS 會話票證恢復先前的會話(請參閱 RFC 5077)。恢復可以在熱重新啟動之間以及平行 Envoy 執行個體之間執行(通常在前端代理設定中很有用)。
BoringSSL 私密金鑰方法:TLS 私密金鑰操作(簽署和解密)可以從 擴充功能 非同步執行。這允許擴展 Envoy 以支援各種金鑰管理方案(例如 TPM)和 TLS 加速。此機制使用 BoringSSL 私密金鑰方法介面。
OCSP Stapling:線上憑證釘選協定回應可能會釘選到憑證。
底層實作
目前 Envoy 是使用 BoringSSL 作為 TLS 提供者來撰寫的。
FIPS 140-2
BoringSSL 可以依照 FIPS 相容模式 建置,遵循 BoringCrypto 模組的安全政策 中的建置指示,使用 --define boringssl=fips
Bazel 選項。目前,此選項僅在 Linux-x86_64 上可用。
FIPS 建置的正確性可以透過檢查 --version
輸出的 BoringSSL-FIPS
是否存在來驗證。
請務必注意,雖然使用 FIPS 相容模組對於 FIPS 相容性是必要的,但本身並不足夠,而且根據上下文,可能需要其他步驟。額外的需求可能包括僅使用核准的演算法和/或僅使用以 FIPS 核准模式運作的模組產生的私密金鑰。如需更多資訊,請參閱 BoringCrypto 模組的安全政策 和/或 經過認證的 CMVP 實驗室。
請注意,FIPS 相容的建置是基於較舊版本的 BoringSSL,而不是非 FIPS 建置,而且它不支援最新的 QUIC API。
啟用憑證驗證
除非驗證內容指定一或多個受信任的授權憑證,否則不會啟用上游和下游連線的憑證驗證。
設定範例
static_resources:
listeners:
- name: listener_0
address: {socket_address: {address: 127.0.0.1, port_value: 10000}}
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
virtual_hosts:
- name: default
domains: ["*"]
routes:
- match: {prefix: "/"}
route:
cluster: some_service
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: {filename: "certs/servercert.pem"}
private_key: {filename: "certs/serverkey.pem"}
validation_context:
trusted_ca:
filename: certs/cacert.pem
clusters:
- name: some_service
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: some_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 1234
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: {"filename": "certs/servercert.pem"}
private_key: {"filename": "certs/serverkey.pem"}
ocsp_staple: {"filename": "certs/server_ocsp_resp.der"}
validation_context:
match_typed_subject_alt_names:
- san_type: DNS
matcher:
exact: "foo"
trusted_ca:
filename: /etc/ssl/certs/ca-certificates.crt
/etc/ssl/certs/ca-certificates.crt 是 Debian 系統上系統 CA 組合的預設路徑。trusted_ca 和 match_typed_subject_alt_names 可讓 Envoy 驗證 127.0.0.1:1234 的伺服器身分是否為「foo」,方式與標準 Debian 安裝上的 cURL 相同。Linux 和 BSD 上系統 CA 組合的常見路徑如下
/etc/ssl/certs/ca-certificates.crt (Debian/Ubuntu/Gentoo 等)
/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem (CentOS/RHEL 7)
/etc/pki/tls/certs/ca-bundle.crt (Fedora/RHEL 6)
/etc/ssl/ca-bundle.pem (OpenSUSE)
/usr/local/etc/ssl/cert.pem (FreeBSD)
/etc/ssl/cert.pem (OpenBSD)
如需其他 TLS 選項,請參閱 UpstreamTlsContexts 和 DownstreamTlsContexts 的參考資料。
注意
如果僅指定 trusted_ca,Envoy 將驗證所呈現憑證的憑證鏈,但不驗證其主體名稱、雜湊等。通常需要其他驗證內容設定,具體取決於部署。
自訂憑證驗證器
上述說明設定由「預設」憑證驗證器使用。Envoy 也支援 envoy.tls.cert_validator
擴充功能類別中的自訂驗證器,該驗證器可以在 CertificateValidationContext 上設定。
例如,可以將 Envoy 設定為根據 SPIFFE 規格驗證對等憑證,並在單一監聽器或叢集中有多個信任組合。如需更多詳細資訊,請參閱 custom_validator_config 欄位的說明文件。
憑證選取
DownstreamTlsContexts 支援多個 TLS 憑證。這些可以是多個伺服器名稱模式的 RSA 和 ECDSA 憑證的組合。
憑證設定/載入規則
DNS SAN 或主體通用名稱會擷取為伺服器名稱模式,以在交握期間比對 SNI。如果憑證中存在 DNS SAN,則不會使用主體通用名稱。
FQDN(例如「test.example.com」)和萬用字元(例如「*.example.com」)同時有效,這將載入為兩個不同的伺服器名稱模式。
如果為相同的名稱或名稱模式指定多個特定類型(RSA 或 ECDSA)的憑證,則會使用載入的第一個憑證。
非 P-256、P-384 或 P-521 伺服器 ECDSA 憑證會被拒絕。
靜態憑證和 SDS 憑證可能不會在給定的 DownstreamTlsContext 中混合。
憑證選取規則
如果用戶端支援 SNI,例如 SNI 是「test.example.com」,它會尋找與 SNI 完全相符的憑證。如果憑證符合 OCSP 原則並與金鑰類型相符,則會選取該憑證進行交握。如果憑證符合 OCSP 原則,但金鑰類型為 RSA,而用戶端具有 ECDSA 功能,則會將其標記為候選憑證,並繼續搜尋,直到選取完全相符的憑證或憑證耗盡。如果沒有完全相符的憑證,則會選取候選憑證進行交握。
如果用戶端支援 SNI,但從與 SNI 完全相符的憑證中未選取任何憑證,則它會比對萬用字元伺服器名稱。例如,如果 SNI 是「test.example.com」,則具有「test.example.com」的憑證會優先於「*.example.com」。而且萬用字元比對僅適用於 1 個深度的層級,因此「*.com」不會與「test.example.com」比對。之後,它會對每個憑證執行 OCSP 和金鑰類型檢查,這與在精確 SNI 比對之後發生的情況相同。
如果沒有從符合萬用字元名稱的憑證中選取憑證,則會選取候選憑證進行交握(如果存在)。如果沒有候選憑證,請檢查full_scan_certs_on_sni_mismatch,如果已啟用,則掃描所有憑證,否則選擇第一個憑證進行交握。
如果客戶端完全沒有提供 SNI,無論full_scan_certs_on_sni_mismatch是 false 還是 true,都會進行完整掃描。
完整掃描會對每個憑證執行 OCSP 和金鑰類型檢查,這與上面精確 SNI 匹配中的描述相同。如果沒有選取任何憑證,則會回退到整個清單中的第一個憑證。
目前僅支援兩種金鑰類型:RSA 或 ECDSA。如果客戶端支援 P-256、P-384 或 P-521 ECDSA,則會優先選擇 P-256、P-384 或 P-521 ECDSA 憑證,而不是 RSA。回退的憑證可能會導致交握失敗。例如,客戶端僅支援 RSA 憑證,而憑證僅支援 ECDSA。
最終選取的憑證必須符合 OCSP 策略。如果找不到此類憑證,則會拒絕連線。
注意
透過支援基於 SNI 的憑證選取,可以為多個主機名稱設定大量憑證。引入full_scan_certs_on_sni_mismatch來決定當客戶端提供 SNI 時,是否在 SNI 不匹配時繼續完整掃描。SNI 不匹配在此上下文中包含兩種情況:一種是沒有符合 SNI 的憑證,另一種是有符合 SNI 的憑證,但這些憑證的 OCSP 策略失敗。full_scan_certs_on_sni_mismatch預設為 false,因此預設會停用完整掃描。如果啟用完整掃描,它將在 SNI 不匹配時從整個憑證清單中尋找憑證,這可能會因為 O(n) 的複雜度而導致潛在的 DoS 攻擊問題。
目前對於UpstreamTlsContexts僅支援單一 TLS 憑證。
機密探索服務 (SDS)
TLS 憑證可以在靜態資源中指定,也可以從遠端擷取。靜態資源支援憑證輪換,方法是從檔案系統來源 SDS 組態,或從 SDS 伺服器推送更新。有關詳細資訊,請參閱SDS。
OCSP Stapling
DownstreamTlsContexts支援在交握期間將線上憑證狀態協定 (OCSP) 回應釘選到 TLS 憑證。 ocsp_staple
欄位允許操作員在上下文中提供每個憑證的預先計算的 OCSP 回應。單一回應可能不適用於多個憑證。如果提供,OCSP 回應必須有效,並確認憑證尚未被撤銷。過期的 OCSP 回應可以接受,但可能會根據 OCSP 釘選策略導致下游連線錯誤。
DownstreamTlsContexts支援 ocsp_staple_policy
欄位,以控制當關聯的 OCSP 回應遺失或過期時,Envoy 是否應停止使用憑證或繼續不進行釘選。標記為 must-staple 的憑證,無論 OCSP 釘選策略為何,都需要有效的 OCSP 回應。實際上,必須釘選的憑證會導致 cEnvoy 的行為如同 OCSP 釘選策略為MUST_STAPLE一樣。Envoy 在其 OCSP 回應過期後,將不會使用必須釘選的憑證來建立新連線。
OCSP 回應永遠不會釘選到未透過 status_request
擴充功能表明支援 OCSP 釘選的 TLS 要求。
提供以下執行階段旗標來調整 OCSP 回應的要求並覆寫 OCSP 策略。這些旗標預設為 true
。
envoy.reloadable_features.require_ocsp_response_for_must_staple_certs
:停用此選項允許操作員在組態中省略必須釘選憑證的 OCSP 回應。envoy.reloadable_features.check_ocsp_policy
:停用此選項將會停用 OCSP 策略檢查。如果用戶端支援,即使回應已過期,OCSP 回應也會在可用時進行釘選。如果沒有回應,則會跳過釘選。
對於 UpstreamTlsContexts,OCSP 回應會被忽略。
驗證篩選器
Envoy 提供一個網路篩選器,透過從 REST VPN 服務擷取的主體來執行 TLS 用戶端驗證。此篩選器會將呈現的客戶端憑證雜湊與主體清單進行比對,以確定是否應允許連線。也可以設定選用的 IP 允許清單。此功能可用於為 Web 基礎結構建置邊緣 Proxy VPN 支援。
用戶端 TLS 驗證篩選器組態參考。
自訂交握器擴充功能
CommonTlsContext 具有一個 custom_handshaker
擴充功能,可用於完全覆寫 SSL 交握行為。這對於實作任何難以使用回呼表示的 TLS 行為非常有用。不需要撰寫自訂交握器即可使用私密金鑰方法,請參閱上面描述的私密金鑰方法介面。
為了避免重新實作所有Ssl::ConnectionInfo 介面,自訂實作可能會選擇擴充 Envoy::Extensions::TransportSockets::Tls::SslHandshakerImpl。
自訂交握器需要透過 HandshakerCapabilities 明確宣告它們負責的 TLS 功能。預設的 Envoy 交握器將管理其餘部分。
一個有用的範例交握器,名為 SslHandshakerImplForTest
,位於 此測試中,並示範特殊情況的 SSL_ERROR
處理和回呼。
疑難排解
當 Envoy 在與上游叢集建立連線時發起 TLS 時,任何錯誤都會記錄到 UPSTREAM_TRANSPORT_FAILURE_REASON 欄位或 AccessLogCommon.upstream_transport_failure_reason 欄位中。
當 Envoy 監聽器取得連線並與下游執行 TLS 時,任何錯誤都會記錄到 DOWNSTREAM_TRANSPORT_FAILURE_REASON 欄位或 AccessLogCommon.downstream_transport_failure_reason 欄位中。
常見錯誤有
Secret is not supplied by SDS
:Envoy 仍在等待 SDS 提供金鑰/憑證或根 CA。SSLV3_ALERT_CERTIFICATE_EXPIRED
:對等憑證已過期,並且不允許在組態中使用。SSLV3_ALERT_CERTIFICATE_UNKNOWN
:對等憑證不在組態中指定的 SPKI 中。SSLV3_ALERT_HANDSHAKE_FAILURE
:交握失敗,通常是因為上游需要用戶端憑證但未提供。TLSV1_ALERT_PROTOCOL_VERSION
:TLS 協定版本不符。TLSV1_ALERT_UNKNOWN_CA
:對等憑證 CA 不在信任的 CA 中。
可以在此處找到 BoringSSL 可以引發的更詳細錯誤列表