Istio – on – AKS reference

Istio


AKS Istio Mesh Setup (Central US)

1) Variables

RG="rg-aks-istio-centralus"
AKS="aks-istio-centralus"
LOCATION="centralus"

2) Prerequisites

2.1 Ensure Azure CLI is up to date

Azure requires a recent Azure CLI for the Istio add-on workflow. (Microsoft Learn)

az version

2.2 Login and select subscription (if needed)

az login
az account show
# az account set --subscription "<subscription-id>"

3) Create Resource Group

az group create --name "$RG" --location "$LOCATION"

4) Pick an Istio revision available in Central US

Azure publishes “Istio revisions” per region. Always pick from the output of this command. (Microsoft Learn)

az aks mesh get-revisions --location "$LOCATION" -o table

Pick one revision from the list (example: asm-1-27 or whatever you see in your output):

REVISION="asm-1-27"

5) Create AKS cluster with Istio add-on enabled

Option A: Create new cluster with mesh enabled

This is the standard path. (Microsoft Learn)

az aks create \
  --resource-group "$RG" \
  --name "$AKS" \
  --location "$LOCATION" \
  --enable-asm \
  --revision "$REVISION" \
  --generate-ssh-keys

Option B: Enable mesh on an existing cluster (if you already have one)

Azure provides az aks mesh enable for existing clusters. (Microsoft Learn)

az aks mesh enable --resource-group "$RG" --name "$AKS"

6) Get kubeconfig

az aks get-credentials --resource-group "$RG" --name "$AKS" --overwrite-existing

7) Verify Istio control plane is running

AKS-managed Istio control plane is in aks-istio-system. (Microsoft Learn)

kubectl get pods -n aks-istio-system

Also confirm mesh mode from Azure:

az aks show -g "$RG" -n "$AKS" --query "serviceMeshProfile.mode" -o tsv
az aks show -g "$RG" -n "$AKS" --query "serviceMeshProfile.istio.revisions" -o tsv

8) Create an app namespace and enable sidecar injection (revision-based)

AKS add-on uses revision label for injection (not istio-injection=enabled). (Microsoft Learn)

Example for Bookinfo:

kubectl create namespace bookinfo

kubectl label namespace bookinfo istio.io/rev="$REVISION" --overwrite

kubectl get ns bookinfo --show-labels

9) Enable Istio Ingress Gateway (External)

Azure supports external or internal ingress gateways. For Internet access, enable external. (Microsoft Learn)

az aks mesh enable-ingress-gateway \
  --resource-group "$RG" \
  --name "$AKS" \
  --ingress-gateway-type external

Verify gateway service:

kubectl get svc -n aks-istio-ingress
kubectl get svc aks-istio-ingressgateway-external -n aks-istio-ingress -o wide

Azure documents the aks-istio-ingress namespace and the gateway enablement flow. (Microsoft Learn)


10) Get the external gateway IP (for later Bookinfo access)

INGRESS_HOST=$(kubectl -n aks-istio-ingress get svc aks-istio-ingressgateway-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
INGRESS_PORT=$(kubectl -n aks-istio-ingress get svc aks-istio-ingressgateway-external -o jsonpath='{.spec.ports[0].port}')
echo "Gateway IP: $INGRESS_HOST  Port: $INGRESS_PORT"

11) (Optional) Mesh-wide config uses shared ConfigMap per revision

If later you configure mesh-wide settings, AKS add-on expects a shared configmap named istio-shared-configmap-<revision> in aks-istio-system. (Microsoft Learn)


Introduction

Now that Bookinfo is working on AKS with the Istio add-on enabled, this is the right time to deeply understand traffic management in Istio.

In this session, we will not just talk about theory. We will apply practical experiments using kubectl so that you clearly see how traffic decisions are controlled inside the mesh.

By the end of this tutorial, you will understand:

  • How Istio routes traffic
  • How canary deployments work
  • How header-based routing works
  • How to inject faults
  • How to configure retries and timeouts
  • How circuit breaking protects services
  • How mirroring works
  • How to debug traffic behavior

Pre-requisites

  • AKS cluster with Istio add-on enabled
  • Bookinfo deployed in namespace bookinfo
  • External ingress gateway enabled
  • kubectl configured and working

Step 0: Get Gateway URL

First, get the external gateway IP and port.

INGRESS_HOST=$(kubectl -n aks-istio-ingress get svc aks-istio-ingressgateway-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
INGRESS_PORT=$(kubectl -n aks-istio-ingress get svc aks-istio-ingressgateway-external -o jsonpath='{.spec.ports[0].port}')
export GATEWAY_URL="$INGRESS_HOST:$INGRESS_PORT"

echo "http://$GATEWAY_URL/productpage"

Test that Bookinfo is accessible:

curl -s "http://$GATEWAY_URL/productpage" | grep -o "<title>.*</title>"

If this works, we are ready to experiment.


Architecture Refresher

When a request flows through Bookinfo, this is what happens:

Client AKS Load Balancer Istio Ingress Gateway productpage (with Envoy sidecar) reviews (with Envoy sidecar) ratings (with Envoy sidecar) details (with Envoy sidecar)

Every request goes through Envoy proxies. Istio control plane pushes routing rules to these proxies.


Step 1: Create Subsets for Reviews Service

Before doing version-based routing, we must define subsets.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
EOF

Verify:

kubectl get destinationrule -n bookinfo

This maps subset names to pod labels.


Step 2: Reset to Stable (100% v1)

Always start from a clean baseline.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 100
EOF

Now all traffic goes to v1.


Step 3: Canary Deployment (80% v1, 20% v2)

This is how controlled rollout works.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 80
    - destination:
        host: reviews
        subset: v2
      weight: 20
EOF

Test multiple requests:

for i in {1..30}; do
  curl -s "http://$GATEWAY_URL/productpage" | grep -q "glyphicon-star" && echo "stars" || echo "no-stars"
done | sort | uniq -c

You will see mixed results.

This is exactly how production systems gradually shift traffic.


Step 4: Header-Based Routing

We will route a specific user to v2.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1
EOF

Test:

curl -H "end-user: jason" http://$GATEWAY_URL/productpage

Now only that user sees v2.

This is how feature flags and beta user testing are implemented.


Step 5: Fault Injection (Delay Testing)

Simulate a slow service.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - fault:
      delay:
        percentage:
          value: 100
        fixedDelay: 5s
    route:
    - destination:
        host: reviews
        subset: v1
EOF

Test:

time curl -s http://$GATEWAY_URL/productpage > /dev/null

You should see around 5 seconds delay.

This is useful for resilience testing.


Step 6: Timeout Configuration

Prevent long waits.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - timeout: 2s
    route:
    - destination:
        host: reviews
        subset: v1
EOF

Now the request fails quickly instead of waiting.


Step 7: Retries

Handle transient failures.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - timeout: 2s
    retries:
      attempts: 3
      perTryTimeout: 1s
      retryOn: 5xx,connect-failure,refused-stream,reset
    route:
    - destination:
        host: reviews
        subset: v1
EOF

Retries are useful when services fail intermittently.


Step 8: Traffic Mirroring

Send traffic to v2 silently while users still see v1.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
  mirror:
    host: reviews
    subset: v2
  mirrorPercentage:
    value: 100
EOF

Generate traffic:

for i in {1..20}; do curl -s http://$GATEWAY_URL/productpage > /dev/null; done

Check logs:

kubectl logs -n bookinfo -l app=reviews,version=v2

This is used for shadow deployments.


Step 9: Circuit Breaking

Protect downstream services.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-cb
spec:
  host: reviews
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 1
      http:
        http1MaxPendingRequests: 1
        maxRequestsPerConnection: 1
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 5s
      baseEjectionTime: 30s
      maxEjectionPercent: 100
EOF

This prevents overload and ejects unhealthy instances.


Step 10: Reset to Stable

Always reset to normal after experiments.

kubectl delete virtualservice reviews -n bookinfo
kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 100
EOF

Final Understanding

Istio traffic management gives you centralized, declarative control over:

  • Version rollout
  • User targeting
  • Resilience
  • Testing
  • Failure handling
  • Production protection

All without modifying application code.

This is why service meshes are powerful in microservices architectures.

Perfect. Now that traffic experiments are clear, let us move to security and enable mTLS (Mutual TLS) in your Bookinfo mesh.

I will guide you step by step and also show you how to test and prove that mTLS is actually working.

This assumes:

  • AKS with Istio add-on
  • Namespace bookinfo
  • Sidecar injection already enabled

What is mTLS in Istio?

mTLS means:

  • Client verifies server identity
  • Server verifies client identity
  • Traffic between services is encrypted
  • Certificates are issued automatically by Istio

In Istio, this happens at the Envoy sidecar level, not inside application code.


Step 1: Check Current mTLS Mode

By default, Istio may run in PERMISSIVE mode.

Check existing PeerAuthentication:

kubectl get peerauthentication -A

If nothing is defined, mesh may still allow plaintext traffic.


Step 2: Enable STRICT mTLS in Bookinfo Namespace

We will enable STRICT mode for namespace bookinfo.

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
spec:
  mtls:
    mode: STRICT
EOF

Verify:

kubectl get peerauthentication -n bookinfo
kubectl describe peerauthentication default -n bookinfo

Now:

All service-to-service communication in this namespace must use mTLS.


Step 3: Verify Sidecars Have Certificates

Pick one pod:

kubectl get pods -n bookinfo

Exec into productpage pod:

kubectl exec -it <productpage-pod> -n bookinfo -- ls /etc/certs

You should see:

  • cert-chain.pem
  • key.pem
  • root-cert.pem

This confirms Istio issued certificates.


Step 4: Functional Test (Application Still Works)

Test Bookinfo from outside:

curl -s http://$GATEWAY_URL/productpage | grep -o "<title>.*</title>"

It should still work.

Reason:

  • Gateway also participates in mTLS
  • Internal traffic is encrypted automatically

Step 5: Prove Plaintext Traffic is Blocked

This is the important test.

We will try to call a service directly from inside the cluster without mTLS.

Create a temporary debug pod WITHOUT sidecar:

kubectl run tmp-shell -n bookinfo --rm -it --image=curlimages/curl -- sh

Inside that shell, try:

curl http://reviews:9080/reviews/1

Expected result:

Connection should fail.

Why?

Because:

  • STRICT mode requires mTLS
  • This pod has no sidecar
  • No certificate is presented
  • Connection rejected

Exit the pod.


Step 6: Compare with Sidecar Pod

Now exec into a pod that has sidecar:

kubectl exec -it <productpage-pod> -n bookinfo -- sh

Inside:

curl http://reviews:9080/reviews/1

This should succeed.

Reason:

  • Sidecar injects mTLS
  • Certificates exchanged
  • Request allowed

This is the strongest proof that mTLS is active.


Step 7: Inspect mTLS Status Using istioctl (Optional but Recommended)

If you have istioctl installed:

istioctl authn tls-check <productpage-pod>.bookinfo

You should see:

  • Mode: ISTIO_MUTUAL

This confirms encrypted traffic.


Step 8: Enable STRICT mTLS for Entire Namespace (Explicit Policy)

You can scope it explicitly:

kubectl apply -f - <<'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: bookinfo-mtls
  namespace: bookinfo
spec:
  mtls:
    mode: STRICT
EOF

Now all workloads must use mTLS.


Step 9: What Actually Happens Internally

When productpage calls reviews:

  1. Envoy intercepts request
  2. Envoy establishes TLS handshake
  3. Certificate exchanged
  4. Identity verified
  5. Encrypted channel created
  6. Request forwarded

All of this without modifying application code.


Step 10: Reset mTLS (If Needed)

If something breaks and you want to revert:

kubectl delete peerauthentication default -n bookinfo

Or switch to PERMISSIVE:

kubectl apply -n bookinfo -f - <<'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
spec:
  mtls:
    mode: PERMISSIVE
EOF

What You Just Achieved

You now:

  • Enforced encrypted service-to-service traffic
  • Verified certificate issuance
  • Proved plaintext calls are blocked
  • Understood how Envoy handles TLS automatically

This is zero-trust networking inside Kubernetes.

Published
Categorized as Uncategorized Tagged

By continuous learner

devops & cloud enthusiastic learner

Leave a ReplyCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Please turn AdBlock off
Floating Social Media Icons by Acurax Wordpress Designers

Discover more from Direct DevOps from Quality Thought

Subscribe now to keep reading and get access to the full archive.

Continue reading

Exit mobile version
%%footer%%