DEV Community

Cover image for Istio - Service Mesh
Omar Ahmed
Omar Ahmed

Posted on • Edited on

Istio - Service Mesh

Istio Basics

1. Download Istio CLI

curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH
Enter fullscreen mode Exit fullscreen mode

2. Install Istio control plane

istioctl install --set profile=demo -y
kubectl get pods -n istio-system
Enter fullscreen mode Exit fullscreen mode

3. Enable auto sidecar injection on prod

kubectl create namespace prod
kubectl label namespace prod istio-injection=enabled
# Confirm:
kubectl get ns --show-labels
kubectl get namespace -L istio-injection
Enter fullscreen mode Exit fullscreen mode

4. Open Kiali UI

# Kiali's UI
kubectl port-forward --address=0.0.0.0 svc/kiali 3000:20001 
# Then open: http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

5. Verify sidecar injection (pods should be 2/2 Ready)

kubectl -n prod create deploy node-app --image siddharth67/node-service:v1
kubectl describe pod node-app-786cb44f85-wkq99 -n prod | grep -A2 "Containers:"
Enter fullscreen mode Exit fullscreen mode
❯❯❯ kubectl describe pod node-app-786cb44f85-wkq99 -n prod | grep -A2 "Containers:"                                                        ⎈ (kind-kind/prod)
Init Containers:
  istio-init:
    Container ID:  containerd://2b5ae904579ca1739120831e123b29d23ee3649c6e615f9b4fd1b24f07bbfea7
--
Containers:
  node-service:
    Container ID:   containerd://97484d714ff2c66bf40408aa674b75c049f32f0f9bfbd8d76b7a17f784bbb53b
Enter fullscreen mode Exit fullscreen mode

Istio Ingress Gateway

The Istio Ingress Gateway is a specialized Envoy proxy that handles inbound traffic from outside the service mesh into your cluster.
What it does:

  • Acts as the entry point for external traffic
  • Provides load balancing, TLS termination, and protocol handling
  • Replaces traditional ingress controllers in Istio environments
  • Runs as a deployment (not a sidecar)

Virtual Service

Virtual Service defines routing rules - it tells the gateway WHERE to send the traffic once it enters the mesh.
What it does:

  • Defines traffic routing logic
  • Handles path-based routing, header matching, traffic splitting
  • Works with both ingress traffic (via Gateway) and internal traffic
  • Provides advanced routing features like retries, timeouts, fault injection

6. Bring traffic through Istio ingress (so Kiali can see it)

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: devsecops-gateway
  namespace: prod
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: devsecops-vs
  namespace: prod
spec:
  hosts:
  - "*"
  gateways:
  - devsecops-gateway
  http:
  - match:
    - uri:
        prefix: /plusone
    route:
    - destination:
        host: devsecops-svc
        port:
          number: 5000
Enter fullscreen mode Exit fullscreen mode

End-to-end path:
Client → Istio ingressgateway (port 80) → VirtualService match /plusone → ClusterIP Service devsecops-svc:5000 → Pod.

kubectl -n prod apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: devsecops
  name: devsecops
spec:
  replicas: 3
  selector:
    matchLabels:
      app: devsecops
  template:
    metadata:
      labels:
        app: devsecops
    spec:
      serviceAccountName: default
      volumes:
      - name: vol
        emptyDir: {}
      containers:
      - name: devsecops-container
        image: siddharth67/node-service:v1   
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /tmp
          name: vol
        securityContext:
          capabilities:
            drop: [ "NET_RAW" ]
          runAsUser: 100
          runAsNonRoot: true
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false
        resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: devsecops
  name: devsecops-svc
spec:
  selector:
    app: devsecops
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP
  type: ClusterIP
EOF
Enter fullscreen mode Exit fullscreen mode

7. Send traffic through the mesh

kubectl -n istio-system port-forward svc/istio-ingressgateway 8080:80
while true; do curl -s http://localhost:8080/plusone/99; echo; sleep .2; done
Enter fullscreen mode Exit fullscreen mode

Kiali will not see the traffic if you're not routing through the Istio gateway, so if we want to see the workload through the Kiali UI, we should create IngressGateway and VirtualService objects.
Here's why: Kiali visualizes service mesh traffic by reading telemetry data that Istio's sidecars (Envoy proxies) collect. For this to work, your traffic needs to flow through Istio's data plane components.


Istio mTLS - Auto mutual TLS

mTLS (mutual TLS) with Istio provides automatic encryption and authentication between services in your mesh. Here's how it works:
Default Behavior:
Istio enables mTLS automatically when sidecars are injected:

  • Traffic between services with sidecars is automatically encrypted
  • Uses permissive mode by default (accepts both mTLS and plain text)
  • No configuration needed for basic mTLS

App A ──(plaintext)──► Sidecar A ──(mTLS)──► Sidecar B ──(plaintext)──► App B

PeerAuthentication modes

1. PERMISSIVE (Default)
Traffic accepted:
✅ mTLS from other sidecars
✅ Plain text from non-mesh services
✅ Plain text from services without sidecars

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: prod
spec:
  mtls:
    mode: PERMISSIVE  # Accepts both mTLS and plaintext
Enter fullscreen mode Exit fullscreen mode

2. STRICT
Traffic accepted:
✅ mTLS from other sidecars
❌ Plain text traffic (rejected with connection errors)

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: enforce-mtls
  namespace: prod
spec:
  mtls:
    mode: STRICT  # Only accepts mTLS traffic
Enter fullscreen mode Exit fullscreen mode

3. DISABLE
Traffic accepted:
❌ mTLS traffic (rejected)
✅ Plain text traffic only

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: disable-mtls
  namespace: prod
spec:
  mtls:
    mode: DISABLE
Enter fullscreen mode Exit fullscreen mode
❯❯❯ k get crd
NAME                                       CREATED AT
authorizationpolicies.security.istio.io    2025-09-05T13:29:53Z
destinationrules.networking.istio.io       2025-09-05T13:29:52Z
envoyfilters.networking.istio.io           2025-09-05T13:29:52Z
gateways.networking.istio.io               2025-09-05T13:29:52Z
peerauthentications.security.istio.io      2025-09-05T13:29:54Z #<<##########
proxyconfigs.networking.istio.io           2025-09-05T13:29:52Z
requestauthentications.security.istio.io   2025-09-05T13:29:54Z
serviceentries.networking.istio.io         2025-09-05T13:29:52Z
sidecars.networking.istio.io               2025-09-05T13:29:53Z
telemetries.telemetry.istio.io             2025-09-05T13:29:54Z
virtualservices.networking.istio.io        2025-09-05T13:29:53Z
wasmplugins.extensions.istio.io            2025-09-05T13:29:51Z
workloadentries.networking.istio.io        2025-09-05T13:29:53Z
workloadgroups.networking.istio.io         2025-09-05T13:29:53Z

❯❯❯ k get peerauthentications
No resources found in prod namespace.

❯❯❯ k get pa  # peerauthentications
No resources found in prod namespace.
Enter fullscreen mode Exit fullscreen mode

8. MTLS Modes:

kubectl apply <<'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: mtls
  namespace: prod
spec:
  mtls:
    mode: PERMISSIVE
EOF
Enter fullscreen mode Exit fullscreen mode

Apply the Deployment below for testing:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: devsecops-client
  namespace: prod
  labels:
    app: devsecops-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: devsecops-client
  template:
    metadata:
      labels:
        app: devsecops-client
    spec:
      containers:
      - name: curl
        image: curlimages/curl:latest
        args:
          - sh
          - -c
          - |
            while true; do
              echo "$(date) -> $(curl -sS -o /dev/null -w '%{http_code}' http://devsecops-svc.prod.svc.cluster.local:5000/health || echo 'curl-failed')";
              sleep 5;
            done
        securityContext:
          runAsNonRoot: true
          runAsUser: 1000
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            cpu: 200m
            memory: 128Mi
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f deploy.yaml
Enter fullscreen mode Exit fullscreen mode
❯❯❯ k get pa                                                                                                                                                    
NAME   MODE         AGE
mtls   PERMISSIVE   103s

❯❯❯ k describe pa mtls                                                                                                                                  
Name:         mtls
Namespace:    prod
Labels:       <none>
Annotations:  <none>
API Version:  security.istio.io/v1
Kind:         PeerAuthentication
Metadata:
  Creation Timestamp:  2025-09-06T13:04:22Z
  Generation:          1
  Resource Version:    48804
  UID:                 1c9f7fbd-a1a3-4135-9a8a-94e7efb65e9e
Spec:
  Mtls:
    Mode: PERMISSIVE
Events:    <none>     
Enter fullscreen mode Exit fullscreen mode


❯❯❯ cat pa.yaml                                                                                                                                                 
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: mtls
  namespace: prod
spec:
  mtls:
    mode: DISABLE

❯❯❯ k apply -f pa.yaml                                                                                                                                          
peerauthentication.security.istio.io/mtls configured

❯❯❯ k get pa                                                                                                                                                    
NAME   MODE      AGE
mtls   DISABLE   10m

❯❯❯ k describe pa mtls                                                                                                                                          
Name:         mtls
Namespace:    prod
Labels:       <none>
Annotations:  <none>
API Version:  security.istio.io/v1
Kind:         PeerAuthentication
Metadata:
  Creation Timestamp:  2025-09-06T13:14:56Z
  Generation:          2
  Resource Version:    51468
  UID:                 17008123-2ca7-414c-9b37-136fdc9a67ad
Spec:
  Mtls:
    Mode:  DISABLE
Events:    <none>  
Enter fullscreen mode Exit fullscreen mode

Top comments (0)