nginx Ingressで理解するSSL Passthroughの設定と動作原理

目次

はじめに

はじめに

本ドキュメントは、Kubernetes環境でNGINX Ingressコントローラーを使う際の「SSL Passthrough」機能について分かりやすくまとめたガイドです。実務で証明書管理やTLS終端を扱う方が、適切な設計と設定を行えるように作成しています。

目的

SSL Passthroughが何をするか、どのように動くか、設定時の注意点や制限を具体的に示します。困ったときのトラブルシューティングや代替手段も扱います。

対象読者

・KubernetesとIngressの基本知識を持つエンジニア
・社内WebサービスやAPIを安全に公開したい運用担当者

本書の構成

第2章から第10章まで、定義、動作原理、設定方法、ポートやTLSRouteの扱い、制限、クライアントIP保持、デフォルト証明書、推奨用途を順に解説します。各章で具体例や設定イメージを示しますので、現場でそのまま参照できます。

SSL Passthroughとは

概要

SSL Passthroughは、Ingress(ここではNGINX Ingressコントローラー)が暗号化済みのSSL/TLSトラフィックを復号せずにバックエンドにそのまま転送する仕組みです。コントローラーはパケットを中継するだけで、TLSセッションの終端をバックエンドが担当します。

なぜ使うか

・証明書管理を各サービスに任せたい場合に有効です。
・エンドツーエンドで暗号化を維持したいときに利用します。例えば、外部ロードバランサー→NGINX→アプリ(すべてHTTPS)という構成です。

動作イメージ(簡単)

クライアントがHTTPSで接続→NGINXはTCPレベルで受け取り→そのままバックエンドの443番ポートへ転送→バックエンドがTLSを復号します。SNI情報は残るため、ホスト名による振り分けに使える場合があります。

簡単な注意点

・Ingress側での細かいルール(パスベースのルーティング等)は利用できません。
・バックエンド側で証明書を用意する必要があります。

動作原理

レイヤーと基本動作

SSL PassthroughはOSIモデルのレイヤー4(TCP)で動作します。受け取った接続はそのまま(暗号化された状態で)バックエンドに転送します。プロキシはTLSを解除しないため、証明書の処理やHTTPヘッダーの書き換えは行いません。

TLSハンドシェイクの流れ

クライアントがサーバへTLS接続を開始すると、プロキシは中継役としてTCP接続を確立します。TLSハンドシェイクはクライアントと最終サーバの間で直接進行します。結果として、復号できるのは最終サーバ側だけです。

ローカルTCPプロキシの役割

設定されたHTTPSポート(通常443)で受信した全トラフィックをインターセプトし、ローカルでTCPプロキシを立ち上げて適切なバックエンドへ接続します。プロキシは接続先選択とコネクション中継を担当しますが、アプリケーション層の解析はしません。

SNIによる簡易ルーティング

多くの実装はClientHello内のSNI(サーバ名)を参照してルーティング先を決めます。SNI参照は暗号化解除を伴わないため、秘密鍵に触れずにドメイン単位の振り分けが可能です。

結果と影響

暗号化は維持されるため、プロキシ側でHTTPヘッダーの追加やWAFルールは適用できません。クライアントIPやアクセス制御は別途対応(PROXYプロトコルやTCPレベルの設定)が必要です。

設定方法

概要

NGINX IngressでSSL Passthroughを使うには、コントローラー側で機能を有効にし、Ingressリソースに対応するアノテーションを付けます。パススルーではコントローラーはTLSを終端せず、バックエンドがそのまま暗号化通信を扱います。

手順(NGINX Ingress)

  1. コントローラー有効化
  2. 起動引数で –enable-ssl-passthrough=true を付与するか、ConfigMapに enable-ssl-passthrough: “true” を設定します。これによりパススルー処理を受け付けます。
  3. Ingressの設定
  4. Ingressにアノテーション nginx.ingress.kubernetes.io/ssl-passthrough: “true” を追加します。
  5. ホスト名ベースでルールを定義し、バックエンドはTLSを受けるようにサービスをポート443で公開します。

例(簡略化)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
  annotations:
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: app-svc
            port:
              number: 443

この例ではコントローラーはTLSを終端せず、app-svcが証明書で応答します。

NetScalerの場合

NetScaler Ingress Controllerでは、アノテーション ingress.citrix.com/ssl-passthrough: ‘True’ を使います。対応コントローラーで有効化設定が必要です。

注意点

  • パススルー有効時はコントローラーがHTTPヘッダを読むことができません。ホスト名でのルーティングやバックエンドの証明書管理に注意してください。

ポート設定

概要

SSL Passthroughを使う環境では、IPv4とIPv6の両方に対応するためにポートの割り当てを明確にします。例として、ポート442をSSL Passthrough用、ポート443を通常のHTTPS用に分ける方法を示します。これにより、暗号化を終端しないトラフィックをバックエンドに直接渡せます。

ポート割当の例

  • 442: SSL Passthrough(フロントでTLS終端をせず、バックエンドにそのまま渡す)
  • 443: 通常のHTTPS(リバースプロキシでTLS終端して内容を検査)

具体例として、クライアントがIPv6でアクセスするときも同じポート番号を使えるように、両方のアドレスファミリでリスナーを立てます。

リスナーとファイアウォール設定

リスナーは各プロトコル(IPv4/IPv6)でポートを開放します。ファイアウォールやクラウドのセキュリティグループでも同じポートを許可してください。間違って両方の用途で同一ポートを使うと接続が期待通り動かないことがあります。

SNIとポートの関係

SSL Passthrough時はプロキシがTLSを解けないため、SNIの中身を見てルーティングできません。ポートで用途を分けると、SNIを参照できない場面でも確実に振り分けられます。

性能と監視

別ポートにすることでログやメトリクスを分離できます。ヘルスチェックは各ポートに対して設定し、バックエンドが正しく応答しているか定期的に確認してください。

TLSRoute設定(NGINX Gateway Fabric)

概要

NGINX Gateway FabricでTLSを透過(passthrough)させるには、GatewayのリスナーをTLSにし、TLSRouteでmode: Passthroughを指定します。Gateway側でTLSを終端せず、バックエンドのアプリが直接証明書を扱う構成です。

前提

  • GatewayリソースにTLSリスナー(port: 443, protocol: TLS)を追加する。
  • TLSRouteを許可する設定(allowedRoutes)をGatewayに設定する。

手順(要点)

  1. Gatewayのlistenerでprotocol: TLS、port: 443を設定します。allowedRoutesでTLSRouteを許可してください。
  2. TLSRouteを作成し、spec.rulesにmode: Passthroughを指定します。SNIで振り分ける場合はmatchesのsniHostsを使い、backendRefsで対象Serviceの443ポートを指します。

例(簡易YAML)

# Gateway(抜粋)
spec:
  listeners:
  - name: tls
    protocol: TLS
    port: 443
    allowedRoutes:
      kinds:
      - kind: TLSRoute

# TLSRoute(抜粋)
spec:
  parentRefs:
  - name: my-gateway
  rules:
  - matches:
    - sniHosts: ["example.com"]
    mode: Passthrough
    backendRefs:
    - name: my-backend-svc
      port: 443

注意点

  • PassthroughではGatewayはTLSを終端しないため、証明書はバックエンドで用意します。SNIがないとルーティングできない場合があります。ネットワークとポートの開放状態を事前に確認してください。

以上がTLSRouteでmode: Passthroughを使う際の基本です。具体的なNGINX Gateway FabricのバージョンやCRD実装によってフィールド名が異なる場合があるため、マニュアルも併せてご確認ください。

制限事項と注意点

制限事項

SSL Passthroughはレイヤー4(TCP)で通信を透過します。これにより、Ingressオブジェクトに設定したHTTPレイヤーの機能が適用されません。例えばリクエストのパスやヘッダーを基にした細かい振り分けは行えません。

使用できないアノテーション

レート制限、リライト、HTTPヘッダー操作など、HTTPレイヤーで動作するアノテーションは機能しません。具体例として、「/api を /v1/api にリライトする」や「1分間に10リクエスト以上を遮断する」といった設定は無効になります。

ホスト名ベースのみ対応

SSL Passthroughはホスト名(SNI)に基づく振り分けのみサポートします。パスベースのルーティングはできません。たとえば同じホスト名で異なるパスに振り分けたい場合には不向きです。

NetScaler Ingress Controllerの例外

NetScaler Ingress Controllerでは、ホスト名ベースでないIngressやデフォルトバックエンド向けのIngressではSSL Passthroughが無効になります。該当ケースでは別途TLS終端やプロキシ設定を検討してください。

パフォーマンスとリスク

内部のTCPプロキシが高負荷でクラッシュするリスクがあります。特に大容量の接続や多数の同時接続がある環境では注意が必要です。運用ではTLSをエンドツーエンドで終端するか、負荷分散層でのTLS終端を検討してください。

運用上の注意

ログや可観測性が制限されます。バックエンドで証明書や接続状態を確認する方法を用意してください。また設定変更前に影響範囲を検証し、監視と自動復旧の仕組みを整備することをおすすめします。

クライアントIP保持の問題

問題の概要

SSL PassthroughではTLSを途中で終端しないため、IngressやロードバランサーがクライアントIPを直接把握できません。結果としてアプリケーションやログに残るIPがロードバランサーやプロキシのIPになることがあります。

対策(実践例を含む)

  1. コントローラとIngress両方で有効化
  2. コントローラ起動時に –enable-ssl-passthrough 等のフラグを付けます。
  3. Ingressリソース側で注釈(例: nginx.ingress.kubernetes.io/ssl-passthrough: “true”)を付与します。両方必要な場合が多いです。

  4. PROXYプロトコルの利用

  5. TCPレベルで元の接続情報を渡すPROXYプロトコルを使うと、バックエンドが本来のクライアントIPを受け取れます。ロードバランサーとIngressコントローラー両方で対応が必要です。

  6. アプリケーション側の追加検証

  7. X-Forwarded-ForやPROXYヘッダを信頼する場合、送信元を限定(クラスタ内CIDRやロードバランサーのIP)して検証してください。なりすまし防止に重要です。

設計上の注意点

完全にクライアントIPを保持するのは環境依存で難しいです。プロキシ階層が増えると信頼チェーンが複雑になります。ログや認証の要件に応じて、TLS終端位置やPROXYプロトコル採用の可否を早めに決めてください。

デフォルト証明書の設定

目的

SSL Passthroughを使っていても、コントローラー自身がTLSを受け付ける場面があり、そのときに提示する証明書が必要です。例えばホスト名が一致しない接続やSNI情報がない接続では、デフォルト証明書を返すことでTLSハンドシェイクを完了させます。

作成手順(例)

  1. 証明書と秘密鍵を用意します。自己署名でも実運用でも構いません。
  2. Kubernetesシークレットを作成します。

kubectl create secret tls default-tls \
–cert=server.crt –key=server.key -n ingress-nginx

シークレットのタイプは kubernetes.io/tls になります。

コントローラー設定例

Ingressコントローラー(helmやマニフェスト)のextraArgsに下記を追加します。

controller:
extraArgs:
default-ssl-certificate: “ingress-nginx/default-tls”

ここではネームスペース/シークレット名の形式で指定します。

注意点

  • シークレット名を間違えるとTLS接続が失敗します。接続テストで必ず確認してください。
  • 証明書を更新する場合はシークレットを置き換えます。通常、コントローラーはシークレットの変更を検知して反映しますが、反映されない場合はコントローラーの再起動で対応します。
  • デフォルト証明書は通常のリクエストの正しいホスト名を置き換えるものではありません。ルーティングに合致する証明書がある場合はそちらが優先されます。

以上の手順で、SSL Passthrough環境でも安全にデフォルト証明書を提供できます。

推奨される用途

概要

SSL Passthroughは、IngressやロードバランサーでTLSを終端せず、バックエンドに暗号化されたまま渡す方式です。バックエンド側で証明書やTLS設定を管理したい場合に適しています。

推奨ケース(具体例付き)

  • バックエンドが独自に証明書を管理している場合
  • 例:各テナントが個別の証明書を持つマルチテナント環境。Ingressで終端すると証明書の管理が複雑になります。
  • エンドツーエンドでの暗号化が必須の場合
  • 例:決済システムや医療データを扱うサービスで、途中での復号を避けたいとき。
  • クライアント証明書(mTLS)をバックエンドで検証する場合
  • 例:APIゲートウェイを経由せず、バックエンドで相互認証を行いたいケース。
  • 非HTTP系のTLSトラフィックを扱う場合
  • 例:gRPC over TLSや独自プロトコルのTLS通信。
  • インフラ側でトラフィック内容の検査や改変が不要な場合
  • 例:ヘッダー書き換えやセッション操作を行わず、単に転送したいだけの場面。

SSL Passthroughは、バックエンドにTLS制御を残すことで管理性やセキュリティを高めます。必要な検査やログ収集がIngress側で行えない点は考慮してください。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

目次