In the previous section, we took a deep dive into traffic management, covering everything from basic routing to the world of Canary deployments. As we draw the series to a close, we shift our focus to a critical aspect of service mesh: security. Specifically, we'll be exploring Istio's authorization policies and network resiliency features.

It's important to highlight that, by default, Kubernetes does not come with built-in security features. This leaves each implementation and user with the critical task of establishing their own security measures. Istio steps in to fill this gap by offering custom resources that empower operators to enforce security measures seamlessly, without the need for intricate modifications to the core infrastructure or application code.

Through the course of this tutorial, we will delve into how Istio plays a pivotal role in crafting a 'zero trust' architecture, providing a robust framework for managing workload identities and ensuring secure communication between services. By the end of this tutorial, you’ll have a solid understanding of how to leverage Istio’s security features to protect your applications running on Kubernetes.

An introduction to Istio security features

Having established the need for robust security measures in Kubernetes and Istio’s capabilities in the introductory section, we now turn our attention to the practical advantages of offloading security concerns to a service mesh. This approach not only simplifies security management but also enhances the overall resilience and reliability of your services.

Benefit Description
Consistent Security Policies It allows for consistent application of security policies across all services in the mesh. This ensures uniform security measures without relying on individual service implementations.
Observability for Access Controls Offloading security to the service mesh often comes with built-in observability and logging features, providing insights into traffic patterns.
Reduced Attack Surface By handling security at the infrastructure level, it reduces the attack surface for individual services, as they don't need to implement security measures themselves.

Istio authorization policies

With Istio, you can define policies based on a variety of criteria, including source and destination identity, HTTP method, and even specific paths. This granular approach allows you to create access rules that align precisely with your application's requirements, ensuring that only authorized entities can interact with specific services. By handling access control at the network level, Istio effectively decouples security concerns from your application code.

Creating authorization policies

With an understanding of authorization policies, let’s take a look at how to create them. This tutorial assumes you have deployed the application using the previous tutorial and have it running.

In your editor of choice, create a file called authorization.yaml and add the following code:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-pongs
spec:
  selector:
    matchLabels:
      app: pong-server
  action: DENY
  rules:
  - from:
    - source:
        notNamespaces: ["default"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/pongs"]

Here’s a breakdown of what we just did:

  • selector: Defines the pods to which this policy applies based on their labels. In this case, it targets pods labeled with app: pong-server.
  • action: Specifies the action to be taken. Here, it's set to DENY, which means access will be denied.
  • rules: Contains a list of rules that define the conditions under which the policy is applied. In this example, it's set to deny access to the pongs endpoint for all requests originating from namespaces other than default.

Testing authorization policies

Before applying the manifest, take a moment to run the following curl command on the endpoint we are about to protect:

curl http:<your-load-balance-ip>/pongs

This will show the number of requests made to the pong service.

Applying the policy

Apply the policy using the following command:

kubectl apply -f authorization-policy.yaml

Verifying access restrictions with curl

To test the policy, use curl to send a request to the pongs endpoint. You should receive an RBAC: access denied response indicating that access is denied.

curl http://<your-load-balancer-ip>/pongs

While it can be helpful to deny access to certain endpoints, more times than not, only specific people should have access to certain parts of your application.

Authorization using HTTP headers

Next, let’s take a look at how we can achieve this authorization using HTTP headers. It’s crucial to highlight the importance of using secure tokens and avoiding their direct embedding into applications or scripts, as this could pose a significant security risk. Instead, consider employing tools like Sealed Secrets to safeguard sensitive information. Sealed Secrets enables you to encrypt secrets in a manner that only your cluster can decrypt.

We will start by deleting the previous authorization policy using kubectl:

kubectl delete -f authorization-policy.yaml

In your editor of choice, update the policy with the code below:

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: protect-pongs
  namespace: default
spec:
  selector:
    matchLabels:
      app: pong-server
  action: DENY
  rules:
  - to:
    - operation:
        paths: ["/pongs"]
    when:
    - key: request.headers[x-token]
      notValues: ["somerandomsequenceofstrings"]

Here’s a breakdown of what we just did:

  • selector: Defines the pods to which this policy applies based on their labels. In this case, it targets pods labeled with app: pong-server.
  • action: Specifies the action to be taken. Here, it's set to DENY, which means access will be denied.
  • rules: Contains a list of rules that define the conditions under which the policy is applied. In this example, it's set to deny access to the /pongs endpoint for all requests where the x-token header is not set to "somerandomsequenceofstrings".
Note: Be sure to replace “somerandomsequenceofstrings” with a more secure token.

This policy effectively protects the pongs endpoint, allowing access only when the x-token header is set to "somerandomsequenceofstrings". Apply the modified policy to enforce this protection.

Without the x-token Header (Access Denied):

curl -vv http://<your-load-balancer-ip>/pongs

You should receive a 403 Forbidden response indicating that access is denied.

With the x-token Header Set (Access Granted):

bashCopy code
curl -H "x-token: somerandomsequenceofstrings" http://<your-load-balancer-ip>/pongs

This time, you should receive a successful response from the /pongs endpoint, as the x-token header is set to "somerandomsequenceofstrings", which satisfies the condition specified in the AuthorizationPolicy.

Enabling mTLS with Istio

Mutual Transport Layer Security, often abbreviated as mTLS, is a security protocol that enhances the confidentiality and integrity of data exchanged between services in a network.

Unlike traditional SSL/TLS, which primarily authenticates the server to the client, mTLS provides a mutual authentication mechanism. This means both the client and server verify each other's identities, ensuring a higher level of trust and security in communication.

This level of encryption is particularly vital in environments where regulatory compliance and data privacy are non-negotiable requirements.

Enabling mTLS in our current setup is fairly straightforward. Open up destinatio-rule.yaml and update the configuration as follows:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: pong-server-destination-rule
spec:
  host: pong-server-service  
  subsets:
  - name: v1 
    labels:
      version: v1 
  - name: v2 
    labels:
      version: v2 
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL

In the updated manifest, we set tls.mode to ISTIOMUTUAL, which tells Istio to turn on mTLS. This particular configuration triggers Istio to request a client certificate during communication. This certificate is then verified against the configured caCertificates or credentialName. Choosing ISTIOMUTUAL mode enforces client authentication, ensuring that only authorized entities can access the service. This adds an additional layer of security to your services.

Next, apply the updated manifest:

kubectl apply -f destination-rule.yaml

To verify the change we just made, head back to the Kiali dashboard, Applications > pong-server > Traffic, and set the traffic refresh in the top right-hand corner to 30 minutes.

Make sure to keep an eye out for a lock symbol next to the service, this would indicate if you have mTLS working:

Enabling mTLS with Istio

Summary

In this three-part series, we embarked on a journey through the world of service mesh. We started by understanding the fundamental role of service mesh in microservice architectures. We then onboarded an application into Istio before exploring traffic management techniques, including canary deployments. Finally, we delved into Istio's security features, implementing access control and Mutual TLS.

Further resources

Service Mesh is a broad technology, and the conversation around whether you should adopt it or not could be its own article. If you’re wondering where to look next for more information, here are a few ideas:

At the time of writing Ambient Mesh is still in Beta, but it's worth taking a look at if you are looking for a simpler mode of operation for Istio.