Sitemap
Ahmedatiia

Ahmedatiia

Senior DevOps Engineer

Securing Kubernetes Microservices Using Istio and Strict mTLS

3 min readMar 30, 2026

--

Press enter or click to view image in full size

Modern microservices architectures offer incredible flexibility — but they also introduce a hidden problem:

security inside the cluster is often an afterthought.

When I started working with Kubernetes, everything worked smoothly… until I asked a simple question:

“How secure is communication between my services?”

The answer wasn’t reassuring.

The Problem: Insecure Internal Communication

In a default Kubernetes setup:

  • Service-to-service traffic is not encrypted
  • There is no strong identity verification
  • Any compromised pod can:
  • Intercept internal traffic
  • Access other services
  • Impersonate workloads

The Solution: Istio as a Security Layer

To solve this, I introduced Istio as a dedicated security layer.

Istio works by injecting sidecar proxies (Envoy) into every pod.
These proxies intercept all incoming and outgoing traffic, allowing Istio to:

  • Control how services communicate
  • Enforce security policies
  • Provide deep visibility into traffic

Most importantly:

It enables secure communication without modifying application code

Understanding mTLS

Mutual TLS (mTLS) ensures that:

  • Both client and server authenticate each other
  • All traffic is encrypted

With Istio:

  • Certificates are automatically issued and rotated
  • Encryption is enforced transparently
  • Developers don’t need to modify their applications

mTLS Modes in Istio

Istio supports three modes for mTLS:

1. PERMISSIVE

  • Allows both encrypted and plain-text traffic
  • Useful for migration

Not fully secure

2. STRICT (Used in This Project)

  • Only encrypted (mTLS) traffic is allowed
  • Plain-text traffic is rejected

This enforces:

  • Full encryption
  • Strong service authentication
  • Zero Trust networking

3. DISABLE

  • No encryption
  • Not recommended for production

Why I Chose STRICT Mode

I enabled STRICT mTLS to enforce a Zero Trust architecture.

Get Ahmedatiia’s stories in your inbox

Join Medium for free to get updates from this writer.

This means:

  • All communication between services is encrypted
  • Each service has a verified identity
  • Unauthorized traffic is automatically blocked

Real Impact

With STRICT mode enabled:

  • Frontend → Backend communication is:
  • Encrypted
  • Authenticated

Any unknown service:

  • Cannot connect
  • Is rejected immediately

Ingress Gateway

The Istio Ingress Gateway acts as the entry point for external traffic.

It allows:

  • Secure exposure of services
  • TLS enforcement
  • Advanced routing rules

Implementation Steps

Here’s how I implemented Istio in my environment:

First Kubernetes yaml files

# ingressclass-istio
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: istio
spec:
controller: istio.io/ingress-controller
---
# PeerAuthentication - Istio
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: istio-system
spec:
mtls:
mode: STRICT
---
# Gateway - handles external traffic
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: main-gateway
namespace: default
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 8080
name: http
protocol: HTTP
hosts:
- "URL"
---
# VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: Vertual-service-name
namespace: default
spec:
hosts:
- "URL"
gateways:
- main-gateway
http:
- route:
- destination:
host: svc-name
port:
number: service-port

Then install Istio :


# 1. Install Istio with cert rotation settings
istioctl install --set profile=demo \
--set values.pilot.env.CITADEL_SELF_SIGNED_CA_CERT_TTL=8760h \
--set values.pilot.env.CITADEL_SELF_SIGNED_ROOT_CERT_CHECK_INTERVAL=1h \
--set values.pilot.env.CITADEL_SELF_SIGNED_ROOT_CERT_GRACE_PERIOD_PERCENTILE=20

kubectl delete secret istio-ca-secret -n istio-system
kubectl rollout restart deployment istiod -n istio-system
kubectl rollout status deployment istiod -n istio-system

# 2. Verify Istio control plane is running
kubectl get pods -n istio-system

# 3. Move ingressgateway off port 80/443 to avoid Traefik conflict
kubectl edit daemonsets.apps -n kube-system svclb-istio-ingressgateway-e5a375fc
# change 80 → 8080 and 443 → 8443

kubectl edit svc -n istio-system istio-ingressgateway
# change 80 → 8080 and 443 → 8443

# 4. Enable sidecar injection on your namespace
kubectl label namespace default istio-injection=enabled

# 5. Apply your app manifests (deployments, services, gateway, virtualservices, peerauth)
kubectl apply -f Kubernetes/

# 6. Restart pods so sidecars get injected
kubectl rollout restart deployment app

# 7. Verify pods show 2/2
kubectl get pods
# app-xxx 2/2 Running ✓

# 8. Verify all proxies are synced
istioctl proxy-status

# 9. Verify routes are on 8080
istioctl proxy-config routes \
$(kubectl get pod -n istio-system -l app=istio-ingressgateway \
-o jsonpath='{.items[0].metadata.name}') -n istio-system
# Should show http.8080 for backend.local and frontend.local

# 10. Test it works
curl -H "Host: URL" Server-IP:8080/url
# Expected: healthy msg

# 11. Install observability addons (Grafana, Kiali, Prometheus, Jaeger)
kubectl apply -f samples/addons/

# 12. Verify addons are running
kubectl get pods -n istio-system

Got questions? Drop them below — I’m all ears!

For more info
Here’s my GitHub repo: AhmedAtiia11

Here’s my Linkedin : Ahmed Atiia

--

--