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 HTTPtrafficMode: REQUIRED
only allows mesh-authenticated clients to connect
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
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 defaultauthenticationMode
mode isUNSET
, 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:
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).
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.yamlRetry 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 56Repeat with an HTTPS request
Note the use of
-k
andhttps://
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 56Repeat 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 sleepConfirm 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>
Observe the behaviour
In the example below, the
sleep
namespace was onboarded to the mesh, but thesleep-2
namespace was not. The Tenant'sauthenticationMode
was set toOPTIONAL
(orUNSET
), so services in that tenant accept both HTTP and HTTPS:
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.