Skip to main content
logoTetrate Service BridgeVersion: next

Understanding mTLS

TSB applies mTLS (mutual TLS), encrypting all traffic between services in the mesh. In practice, you may not want to enforce mTLS until you have migrated all of your client services to the mesh, or configured them to access mesh services through a gateway.

In this exercise, we'll edit the Tenant settings to uncover various options for enforcing mTLS:

  • trafficMode: OPTIONAL (the default) uses mTLS within the mesh, and allows external clients to connect using HTTP
  • trafficMode: REQUIRED only allows mesh-authenticated clients to connect
Why edit the Tenant resource?

The Tetrate platform uses a hierarchical model to generate and apply configuration to workloads and services. If we apply a setting at the Tenant level, TSB will then apply that setting downwards to Workspaces and services that are managed by these workspaces, in line with the configured propagation policy.

A Tenant is a good place to define global settings that should apply to large numbers of workloads.

TSB also provides a more sophisticated 'Configuration Profiles' capability that can be used to define partial configuration templates which are then attached at various points in the configuration hierarchy.

Deploy the sleep Test Client

First, we will deploy the sleep app in an unmanaged sleep namespace. This will allow us to test traffic from outside the mesh.

kubectl create namespace sleep
kubectl apply -n sleep -f https://raw.githubusercontent.com/istio/istio/master/samples/sleep/sleep.yaml

Test the Scenarios

  1. Test the default behavior

    Test with a plain HTTP request, from the sleep container outside the mesh:

    kubectl exec deploy/sleep -n sleep -- curl -sS "http://productpage.bookinfo:9080/productpage" | grep "<title>"

    The request succeeds. You should see the output <title>Simple Bookstore App</title>. This is because TSB's default authenticationMode mode is UNSET, which corresponds to Istio's PERMISSIVE mode.

    In this mode, the sidecars for each mesh-managed service will accept both plaintext (HTTP) and mTLS (authenticated HTTPS) requests:

    Sleep uses http

    If you check the topology graph for the cluster, you should observe that sleep is communicating with productpage over plaintext HTTP, whereas the internal HTTP traffic within the bookinfo application is secured with mTLS (note the padlock 🔒 icon).

  2. Enforce mTLS and repeat the test:

    Create and apply the following Tenant Setting:

    export ORG=tetrate
    export TEN=default

    cat <<EOF > ${TEN}-settings.yaml
    apiVersion: api.tsb.tetrate.io/v2
    kind: TenantSetting
    metadata:
    organization: ${ORG}
    tenant: ${TEN}
    name: ${TEN}-setting
    spec:
    defaultSecuritySetting:
    authenticationSettings:
    trafficMode: REQUIRED
    authorization:
    mode: CLUSTER
    EOF

    tctl apply -f ${TEN}-settings.yaml

    Retry the same request from sleep to productpage:

    kubectl exec deploy/sleep -n sleep -- curl -sS "http://productpage.bookinfo:9080/productpage" | grep "<title>"

    The request fails. The configuration requires all services in the mesh to be addressable with HTTPS only, and you should see the following error:

    curl: (56) Recv failure: Connection reset by peer
    command terminated with exit code 56
  3. Repeat with an HTTPS request

    Note the use of -k and https:// to make an HTTPS request:

    kubectl exec deploy/sleep -n sleep -- curl -sSk "https://productpage.bookinfo:9080/productpage" | grep "<title>"

    The request fails. As well as requiring HTTPS, the mesh requires clients to authenticate themselves with a trusted client certificate:

    curl: (56) OpenSSL SSL_read: OpenSSL/3.5.2: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0
    command terminated with exit code 56
  4. Repeat from within the mesh

    You can redeploy the sleep pod with the mesh sidecar injected. HTTP requests will then succeed:

    Relabel the sleep namespace so that pods deployed within are added to the mesh, and redeploy the sleep pod:

    kubectl label ns sleep istio-injection=enabled
    kubectl rollout restart -n sleep deploy sleep

    Confirm that the new sleep pod now consists of two containers ('READY: 2/2'):

    kubectl get pod -n sleep

    Submit an HTTP request; this will be intercepted and proxied by the sidecar to the other mesh services:

    kubectl exec deploy/sleep -n sleep -- curl -sS "http://productpage.bookinfo:9080/productpage" | grep "<title>"

    The request succeeds. You'll see the following output:

    <title>Simple Bookstore App</title>
  5. Observe the behaviour

    In the example below, the sleep namespace was onboarded to the mesh, but the sleep-2 namespace was not. The Tenant's authenticationMode was set to OPTIONAL (or UNSET), so services in that tenant accept both HTTP and HTTPS:

    sleep from mesh and non-mesh

Cleaning Up

Remove the sleep namespace and pod as follows:

kubectl delete -n sleep -f https://raw.githubusercontent.com/istio/istio/master/samples/sleep/sleep.yaml
kubectl delete namespace sleep

Delete the Tetrate TenantSetting:

export ORG=tetrate
export TEN=default

tctl delete TenantSetting --org ${ORG} --tenant ${TEN} ${TEN}-setting

What have we achieved?

We have seen how you can easily enforce a basic security policy that mesh-hosted services can only be accessed by clients who are also in the mesh.