.. _install_sandboxes_tls_inspector:

TLS Inspector Listener Filter
=============================

.. sidebar:: Requirements

   .. include:: _include/docker-env-setup-link.rst

   :ref:`curl <start_sandboxes_setup_curl>`
    Used to make ``HTTP`` requests.

   :ref:`jq <start_sandboxes_setup_jq>`
    Parse ``json`` output from the upstream echo servers.

This example demonstrates how the ``TLS``  inspector can be used to select ``FilterChains`` to
distribute the traffic between upstream clusters according to the matched ``transport_protocol`` and/or
``application_protocols``.

It also demonstrates the admin statistics generated by the ``TLS`` inspector listener filter.

Step 1: Build the sandbox
*************************

Change directory to ``examples/tls-inspector`` in the Envoy repository, and bring up the services.

This starts one proxy listening on ``localhost:10000``, and with an admin interface listening on port 12345.

It also starts three upstream ``HTTP`` services that echo back received headers in ``json`` format.

The first 2 services are ``HTTPS`` services listening on port ``443`` and the other has no ``TLS`` and listens on
port ``80``.

.. code-block:: console

  $ pwd
  envoy/examples/tls-inspector
  $ docker compose pull
  $ docker compose up --build -d
  $ docker compose ps

                Name                               Command               State                         Ports
  ---------------------------------------------------------------------------------------------------------------------------------
  tls-inspector_service-http_1            docker-entrypoint.sh node  ... Up
  tls-inspector_service-https-http1.1_1   docker-entrypoint.sh node  ... Up
  tls-inspector_service-https-http2_1     docker-entrypoint.sh node  ... Up
  tls-inspector_tls-inspector_1           /docker-entrypoint.sh /usr ... Up      0.0.0.0:10000->10000/tcp, 0.0.0.0:12345->12345/tcp


Step 2: Access services
***********************

Querying the service at port 10000 with a different HTTP version specified over TLS, or
with HTTP protocol without TLS, the requests will be handled by different upstream services.

Query the proxy with ``HTTP1.1`` and ``TLS``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: console

   $ curl -sk --http1.1 https://localhost:10000  | jq  '.os.hostname'
   "service-https-http1.1"

The upstream ``service-https-http1.1`` handles the request.

Query the proxy with ``HTTP2`` and ``TLS``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: console

   $ curl -sk --http2  https://localhost:10000  | jq  '.os.hostname'
   "service-https-http2"

The upstream ``service-https-http2`` handles the request.

Query the proxy with no ``TLS``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: console

   $ curl -sk http://localhost:10000  | jq  '.os.hostname'
   "service-http"

The upstream ``service-http`` handles the request. Since TLS Inspector listener filter detects the
transport is plaintext, it will not set transport_protocol to ``TLS``.

Step 3: View the admin statistics
*********************************

TLS inspector has a statistics tree rooted at ``tls_inspector``, which can be extracted with the
admin access entrypoint configured.

.. code-block:: console

   $ curl -sk http://localhost:12345/stats |grep tls_inspector
   tls_inspector.alpn_found: 2
   tls_inspector.alpn_not_found: 0
   tls_inspector.client_hello_too_large: 0
   tls_inspector.connection_closed: 0
   tls_inspector.read_error: 0
   tls_inspector.sni_found: 2
   tls_inspector.sni_not_found: 0
   tls_inspector.tls_found: 2
   tls_inspector.tls_not_found: 1

Viewing the admin statistics we can see that ``TLS``, ``SNI`` and ``ALPN`` are all detected since
we access services twice via ``HTTP`` over ``TLS``. It also shows one ``tls_not_found`` from the
plaintext query.