Skip to main content
In this lesson you’ll configure authentication in Istio, deploy a simple hello-world app, observe how PeerAuthentication enforces mTLS, and learn how to override global policies at namespace or workload scope. Prerequisites: kubectl and istioctl configured to talk to your cluster.
Ensure your cluster has Istio installed and the istio-system namespace is present. Use istioctl version and kubectl get ns to validate installation before proceeding.

1) Verify Istio automatic sidecar injection on namespaces

Check namespace labels to determine whether automatic Envoy sidecar injection is enabled:
Example output:
The label istio-injection=enabled means pods created in that namespace get the Envoy sidecar injected automatically. If a namespace has no such label, pods will not be injected and won’t participate in mTLS unless manually proxied.

2) Deploy the helloworld sample

Apply the sample manifest to create the hello-world service and workloads:
Verify pods are created and ready:
Example ready state:
Note: 2/2 indicates the application container plus the Envoy sidecar are running.

3) Create a test namespace and run a client pod

Create a namespace test (if it doesn’t already exist) and run an nginx pod to act as a client:
If you accidentally created the test pod in the default namespace, delete and recreate it in test:

4) Verify connectivity from the test pod to helloworld

From the test pod, curl the hello endpoint on the helloworld service in the default namespace:
You should receive a response similar to:
Why this works: by default, Istio does not enforce mTLS cluster-wide — plaintext traffic is still allowed unless you enable enforcement via PeerAuthentication.

5) Enforce global mTLS with a PeerAuthentication

Create a global PeerAuthentication resource in istio-system to enforce strict mTLS cluster-wide. peer_auth_global.yaml
Apply it:
Confirm the PeerAuthentication exists:
Example output:
Now retry the curl from the non-injected test pod (if test is not injection-enabled):
You will likely see a failure like:
Explanation: the server requires mTLS (STRICT). Because the test pod lacks an Envoy sidecar, the client sends plaintext traffic which the server rejects.

6) Enable injection for test namespace and retry

Use istioctl analyze to surface issues and then enable injection:
Recreate the client pod so it gets injected:
Now retry the curl (from the injected client):
Expected response headers:
Both client and server traffic are now proxied through Envoy and use mTLS, so the connection succeeds.

7) Override global policy at namespace scope (PERMISSIVE)

A PeerAuthentication in istio-system sets a global default but can be overridden by PeerAuthentication resources in namespaces. To allow plaintext and mTLS traffic in the default namespace, create a PERMISSIVE PeerAuthentication: peer_auth_default.yaml
Apply it:
Example output:
With PERMISSIVE in default, clients that are not mTLS-capable (non-injected) can still reach workloads in default using plaintext.

8) Target permissive mode to specific workloads (selector)

Instead of making an entire namespace permissive, scope the permissive mode to only the workloads that match labels (e.g., app=helloworld): peer_auth_default.yaml
Apply the change:
Now PERMISSIVE applies only to pods in default that have app=helloworld. Other workloads in default remain governed by the global STRICT policy in istio-system.

Test with an app namespace (non-injected)

Create a non-injected app namespace and run an nginx pod:
From the non-injected app pod, curl the helloworld endpoint:
Expected (permissive applies to helloworld):
Now try productpage (Bookinfo) in default from the same non-injected app pod. Because the selector only matched app=helloworld, productpage is still subject to global STRICT and will reject plaintext:
You should see:
The same request from an injected namespace (e.g., test) will succeed:
Expected success:
Summary: a global STRICT enforces mTLS cluster-wide. PeerAuthentication resources scoped to a namespace or to specific workloads via selector can override that setting to PERMISSIVE or DISABLE.

PeerAuthentication modes at a glance

Useful references

For troubleshooting: know that a global PeerAuthentication in istio-system can be overridden by PeerAuthentication resources in a namespace or by selectors. Use istioctl analyze and kubectl get peerauthentications.security.istio.io -A to inspect effective policies.
The image shows a webpage from Istio's documentation about Peer Authentication, specifically focusing on MutualTLS settings.

Appendix — example YAMLs

Global strict (peer_auth_global.yaml):
Namespace override (peer_auth_default.yaml, permissive for all workloads in default):
Namespace override with selector (permissive only for app=helloworld):
That completes this demo on PeerAuthentication and mTLS enforcement with Istio.

Watch Video

Practice Lab