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 withapp: pong-server
.action
: Specifies the action to be taken. Here, it's set toDENY
, 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 thepongs
endpoint for all requests originating from namespaces other thandefault
.
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 withapp: pong-server
.action
: Specifies the action to be taken. Here, it's set toDENY
, 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 thex-token
header is not set to "somerandomsequenceofstrings".
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:
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:
- Istio authorization methods
- DevSecOps in Practice: Integrating Security in the Development Lifecycle
- Kubernetes security tutorials
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.