Envoy: TLS

# tldr
勉強がてらにEnvoyのドキュメントを邦訳してみました。ベースはGoogle Translateで、ところどころ不自然な箇所を直しています。

原文としたのEnvoyのドキュメントは[こちらのディレクトリ以下](https://github.com/envoyproxy/envoy/tree/master/docs)にあります（ライセンス：[Apache License 2.0](https://github.com/envoyproxy/envoy/blob/master/LICENSE), [NOTICE](https://github.com/envoyproxy/envoy/blob/master/NOTICE)）。

## TLS

Envoyは、アップストリームクラスタへの接続時に、リスナーでのTLS終了とTLS発信の両方をサポートします。最新のWebサービスに対して標準のエッジプロキシの役割を果たすだけでなく、高度なTLS要件（TLS1.2、SNIなど）を持つ外部サービスとの接続を開始するためのEnvoyのサポートで十分です。 Envoyは以下のTLS機能をサポートします。

- 構成可能な暗号：各TLSリスナーとクライアントは、サポートしている暗号を指定できます。
- クライアント証明書：アップストリーム/クライアント接続は、サーバー証明書の検証に加えてクライアント証明書を提示できます。
- 証明書の検証と固定：証明書の検証オプションには、基本的なチェーン検証、サブジェクト名検証、およびハッシュ固定が含まれます。
- 証明書失効：Envoyは、証明書失効リスト（CRL）が提供されている場合はそれを照合してピア証明書を確認できます。
- ALPN：TLSリスナーはALPNをサポートします。 HTTP接続マネージャはこの情報を使用して（プロトコルの推論に加えて）クライアントがHTTP / 1.1またはHTTP / 2のどちらを話しているのかを判断します。
- SNI：SNIは、サーバー（リスナー）とクライアント（アップストリーム）の両方の接続でサポートされています。
- セッション再開：サーバー接続はTLSセッションチケットを介して前のセッションを再開することをサポートします（RFC 5077を参照）。再開は、ホットリスタート間および並列Envoyインスタンス間で実行できます（通常はフロントプロキシ設定で役立ちます）。

### 基礎となる実装

現在EnvoyはTLSプロバイダとしてBoringSSLを使用するように書かれています。

### FIPS 140-2

BoringSSLは、--define boringssl = fips Bazelオプションを使用して、「BoringCryptoのセキュリティポリシー」モジュールの構築手順に従って、FIPS準拠モードで構築できます。現在、このオプションはLinux-x86_64でのみ利用可能です。

FIPSビルドの正当性は、--version出力にBoringSSL-FIPSが存在することを確認することで確認できます。

FIPSに準拠するにはFIPS準拠のモジュールを使用する必要がありますが、それだけでは不十分であり、状況によっては追加の手順が必要になる場合があることに注意することが重要です。追加の要件は、承認されたアルゴリズムのみを使用すること、および／またはＦＩＰＳ承認モードで動作するモジュールによって生成された秘密鍵のみを使用することを含み得る。詳細については、BoringCryptoモジュールのセキュリティポリシーおよび/または認定CMVPラボを参照してください。

FIPS準拠のビルドは、非FIPSビルドよりも古いバージョンのBoringSSLに基づいており、TLS 1.3の最終バージョンより前のものです。

### 証明書検証を有効にする

検証コンテキストで1つ以上の信頼できる機関証明書が指定されていない限り、アップストリーム接続とダウンストリーム接続の両方の証明書検証は有効になりません。

#### 設定例

```
static_resources：
  リスナー：
   - 名前：listener_0
    アドレス：{socket_address：{アドレス：127.0.0.1、ポート値：10000}}
    filter_chains：
     - フィルタ：
       - 名前：envoy.http_connection_manager
        ＃...
      tls_context：
        common_tls_context：
          validation_context：
            trusted_ca：
              ファイル名：/usr/local/my-client-ca.crt
  クラスタ：
   - 名前：some_service
    connect_timeout：0.25秒
    タイプ：STATIC
    lb_policy：ROUND_ROBIN
    load_assignment：
      cluster_name：some_service
      エンドポイント：
       - lb_endpoints：
        - 終点：
            住所：
              socket_address：
                アドレス：127.0.0.2
                port_value：1234
    tls_context：
      common_tls_context：
        tls_certificates：
          certificate_chain：{"ファイル名"： "/cert.crt"}
          private_key：{"ファイル名"： "/cert.key"}
        validation_context：
          trusted_ca：
            ファイル名：/etc/ssl/certs/ca-certificates.crt
```

/etc/ssl/certs/ca-certificates.crtは、Debianシステム上のシステムCAバンドルのデフォルトパスです。これにより、Envoyは127.0.0.2:1234のサーバーIDを検証します。 cURLは、標準のDebianインストールで動作します。 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のリファレンスを参照してください。

### 証明書の選択

DownstreamTlsContextは複数のTLS証明書をサポートします。これらはRSAとP-256 ECDSA証明書の組み合わせです。以下の規則が適用されます。

- 特定の種類（RSAまたはECDSA）の証明書は1つだけ指定できます。
- P-256以外のサーバーのECDSA証明書は拒否されます。
- クライアントがP-256 ECDSAをサポートしている場合、DownstreamTlsContextにP-256 ECDSA証明書が存在する場合はそれが選択されます。
- クライアントがRSA証明書のみをサポートしている場合、DownstreamTlsContextにRSA証明書が存在する場合はそれが選択されます。
- それ以外の場合は、リストの最初の証明書が使用されます。クライアントがRSA証明書のみをサポートし、サーバーがECDSA証明書のみを持つ場合、これは失敗したハンドシェイクになります。
- 静的証明書とSDS証明書は、特定のDownstreamTlsContextに混在させることはできません。

UpstreamTlsContextでは、今日サポートされているTLS証明書は1つだけです。

### 秘密発見サービス（SDS）

TLS証明書は静的リソースで指定することも、リモートから取得することもできます。詳細はSDSをご覧ください。

### 認証フィルタ

Envoyは、REST VPNサービスから取得したプリンシパルを介してTLSクライアント認証を実行するネットワークフィルタを提供します。このフィルタは、提示されたクライアント証明書ハッシュをプリンシパルリストと照合して、接続を許可するかどうかを決定します。オプションのIPホワイトリストも設定できます。この機能を使用して、Webインフラストラクチャに対するエッジプロキシVPNサポートを構築できます。

クライアントTLS認証フィルター構成の参照
トラブルシューティング

アップストリームクラスタへの接続時にEnvoyがTLSを開始すると、エラーはすべてUPSTREAM_TRANSPORT_FAILURE_REASONフィールドまたはAccessLogCommon.upstream_transport_failure_reasonフィールドに記録されます。一般的なエラーは次のとおりです。

- 秘密は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によって引き起こされる可能性があるエラーのより詳細なリストは、ここで見つけることができます。