Security

The security of a K8S cluster is a central topic when designing your infrastructure. By using some advanced Istio’s features, you can simultaneously simplify your code base, stay focused on your business logic and shield your application more effectively.

Pirates looking at a chest

Mutual TLS

Description

Istio can administer communications between microservices by using a secured link between any component in the mesh. Connections are established using mutual TLS and are entirely handled by the sidecar proxy running inside your pods.

By definition, the mTLS is activated globally in the namespace. There are two ways to test its behaviour:

  • Attach to a running sidecar proxy and run a tcpdump command to see live traffic ;

  • Create an unproxified pod, attach to it and curl a service which has mTLS enabled ;

The first process is the most rigorous, but you would have to run the proxy as a privileged user to be able to inspect network traffic. To do so, you would need to own the VM running the process (or use minikube or kind on your local machine), and install Istio properly on the cluster. For security reasons, both these requirements are impossible to meet on Google Kubernetes Engine and its managed version of Istio.

Therefore, we will use the second approach, by creating another namespace. You will configure it to be unsecured regarding mTLS, and you will try to reach the middleware component.

Execution

Before proceeding any further, make sure you are back with the base behaviour. To do so, you may run the following command:

Λ\: $ kubectl delete namespace workshop && \
      kubectl apply --filename 03_application-bootstrap/application-base.yml

Let’s start by creating a sloppy namespace:

Λ\: $ kubectl create namespace workshop-unsecured
namespace/workshop-unsecured created

Then, let’s create a one-time pod with curl command installed:

Λ\: $ kubectl run --rm --restart Never -it shell --namespace workshop-unsecured --image tutum/curl -- bash
root@shell:/#
If you don’t see a command prompt, try pressing enter

Now we can try to reach the middleware service which is running in the workshop namespace:

Λ\: $ curl -vvv "middleware.workshop:8080"; echo;
* Rebuilt URL to: middleware.workshop:8080/
* Hostname was NOT found in DNS cache
*   Trying 10.121.6.186...
* Connected to middleware.workshop (10.121.6.186) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: middleware.workshop:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json
< content-length: 77
< x-envoy-upstream-service-time: 268
< date: Mon, 01 Jun 2020 11:47:38 GMT
* Server istio-envoy is not blacklisted
< server: istio-envoy
< x-envoy-decorator-operation: middleware.workshop.svc.cluster.local:8080/*
<
* Connection #0 to host middleware.workshop left intact
{"from":"middleware (v1) => database (v1)","date":"2020-06-01T11:47:38.911Z"}

As expected, we are able to reach the middleware service without the sidecar proxy.

Now, from another terminal instance, let’s activate communication encryption in the workshop namespace. To enable mTLS at the namespace level, you need to apply the following YAML:

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: default
  namespace: workshop
spec:
  peers:
    - mtls:
        mode: STRICT

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: default
  namespace: workshop
spec:
  host: "*.workshop.svc.cluster.local"
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule (1)
metadata:
  namespace: workshop
  name: front
spec:
  host: front
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
    - name: version-1
      labels:
        version: v1
1 We have to redeclare the previous DestinationRule to allow secured communication between the Gateway and the front component
# Run in another terminal instance
Λ\: $ kubectl apply --filename 07_security/01_mutual-tls/01_workshop-namespace-as-mtls.yml

Back in the one-time curl pod attached terminal, if you try to reach the middleware service again:

# Run in the pod with curl command in the workshop-unsecured namespace
Λ\: $ curl -vvv middleware.workshop:8080
* Rebuilt URL to: middleware.workshop:8080/
* Hostname was NOT found in DNS cache
*   Trying 10.121.7.48...
* Connected to middleware.workshop (10.121.7.48) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: middleware.workshop:8080
> Accept: */*
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer

You should see a Recv failure: Connection reset by peer, meaning you reached the service, but cannot communicate since the mTLS is not configured on both ends.

Therefore, you were able enforce network security by leveraging the capabilities of the sidecar proxy. This improves the safety of your application by delegating internal communications encrypting to the infrastructure.