Securing Traffic with Anthos Service Mesh
Anthos Service Mesh security helps you mitigate insider threats and reduce the risk of a data breach by ensuring that all communications between workloads are encrypted, mutually authenticated, and authorized.
PERMISSIVE mode mTLS allows services to receive both plaintext and mTLS traffic from clients, allowing you to incrementally adopt mTLS.
STRICT mode mTLS across your service mesh effectively blocking plaintext traffic to all your Istio injected services and
scope STRICT mode mTLS down to a single namespace
- Enforce STRICT mTLS mode across the service mesh
- Enforce STRICT mTLS mode on a single namespace
- Explore the security configurations in the Anthos Service Mesh Dashboard
- Add authorization policies to enforce access based on a JSON Web Token (JWT)
- Add authorization policies for HTTP traffic in an Istio mesh
Confirm Anthos Service Mesh setup
Welcome to Cloud Shell! Type "help" to get started.
Your Cloud Platform project in this session is set to qwiklabs-gcp-03-5d22baeeb714.
Use “gcloud config set project [PROJECT_ID]” to change to a different project.
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ CLUSTER_ZONE=us-central1-c
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ export CLUSTER_NAME=gke
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ # get the project id
export GCLOUD_PROJECT=$(gcloud config get-value project)
# configure kubectl
gcloud container clusters get-credentials $CLUSTER_NAME \
--zone $CLUSTER_ZONE --project $GCLOUD_PROJECT
Your active configuration is: [cloudshell-26468]
Fetching cluster endpoint and auth data.
kubeconfig entry generated for gke.
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ gcloud container clusters list
NAME: gke
LOCATION: us-central1-c
MASTER_VERSION: 1.28.7-gke.1026000
MASTER_IP: 35.224.214.58
MACHINE_TYPE: e2-standard-2
NODE_VERSION: 1.28.7-gke.1026000
NUM_NODES: 3
STATUS: RUNNING
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl get service -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istiod ClusterIP 10.27.87.143 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 5h59m
istiod-asm-1157-23 ClusterIP 10.27.85.248 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 5h59m
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istiod-asm-1157-23-66d49d9464-5qbjg 1/1 Running 0 5h59m
istiod-asm-1157-23-66d49d9464-z4tb6 1/1 Running 0 5h59m
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Deploy sleep and httpbin services
In this task, you create a set of namespaces to host the httpbin, and sleep services. You will use those services to explore the impact of mTLS on traffic. The sleep service acts as the client and will call the httpbin service, which acts as a server.
In Cloud Shell, create namespaces for the example clients and services. Traffic in the legacy-* namespaces takes place over plain text, while traffic in the mtls-* namespaces happens over mTLS:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl create ns mtls-client
kubectl create ns mtls-service
kubectl create ns legacy-client
kubectl create ns legacy-service
kubectl get namespaces
namespace/mtls-client created
namespace/mtls-service created
namespace/legacy-client created
namespace/legacy-service created
NAME STATUS AGE
asm-system Active 6h
default Active 6h15m
gke-managed-system Active 6h15m
gmp-public Active 6h14m
gmp-system Active 6h14m
istio-system Active 6h2m
kube-node-lease Active 6h15m
kube-public Active 6h15m
kube-system Active 6h15m
legacy-client Active 3s
legacy-service Active 1s
mtls-client Active 6s
mtls-service Active 4s
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Deploy the legacy services in the legacy-* namespaces. You call them legacy because they are not part of the mesh:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ #configurations are stored in Github
kubectl apply -f \
https://raw.githubusercontent.com/istio/istio/release-1.6/samples/sleep/sleep.yaml \
-n legacy-client
kubectl apply -f \
https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml \
-n legacy-service
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Enable auto-injection of the Istio sidecar proxy on the mtls-* namespaces:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ # get the revision label
export DEPLOYMENT=$(kubectl get deployments -n istio-system | grep istiod)
export VERSION=asm-$(echo $DEPLOYMENT | cut -d'-' -f 3)-$(echo $DEPLOYMENT \
| cut -d'-' -f 4 | cut -d' ' -f 1)
# enable auto-injection on the namespaces
kubectl label namespace mtls-client istio.io/rev=${VERSION} --overwrite
kubectl label namespace mtls-service istio.io/rev=${VERSION} --overwrite
namespace/mtls-client labeled
namespace/mtls-service labeled
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Deploy the services in the mtls-* namespaces:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -f \
https://raw.githubusercontent.com/istio/istio/release-1.6/samples/sleep/sleep.yaml \
-n mtls-client
kubectl apply -f \
https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml \
-n mtls-service
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that the sleep service and the httpbin service are each deployed in both the mtls-service and legacy-service namespaces:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl get services --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
asm-system canonical-service-controller-manager-metrics-service ClusterIP 10.27.91.90 <none> 8443/TCP 6h3m
default kubernetes ClusterIP 10.27.80.1 <none> 443/TCP 6h18m
gmp-system alertmanager ClusterIP None <none> 9093/TCP 6h17m
gmp-system gmp-operator ClusterIP 10.27.86.11 <none> 8443/TCP,443/TCP 6h17m
istio-system istiod ClusterIP 10.27.87.143 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 6h3m
istio-system istiod-asm-1157-23 ClusterIP 10.27.85.248 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 6h3m
kube-system default-http-backend NodePort 10.27.81.33 <none> 80:30914/TCP 6h17m
kube-system kube-dns ClusterIP 10.27.80.10 <none> 53/UDP,53/TCP 6h17m
kube-system metrics-server ClusterIP 10.27.86.196 <none> 443/TCP 6h17m
legacy-client sleep ClusterIP 10.27.87.87 <none> 80/TCP 116s
legacy-service httpbin ClusterIP 10.27.82.27 <none> 8000/TCP 111s
mtls-client sleep ClusterIP 10.27.82.17 <none> 80/TCP 33s
mtls-service httpbin ClusterIP 10.27.87.129 <none> 8000/TCP 29s
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that a sleep pod is running in the mtls-client and legacy-client namespaces and that an httpbin pod is running in the mtls-service and legacy-service namespaces:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
asm-system canonical-service-controller-manager-74c6dc6698-mnbfh 2/2 Running 0 6h4m
gmp-system alertmanager-0 2/2 Running 0 6h16m
gmp-system collector-kvnjl 2/2 Running 0 6h11m
gmp-system collector-mc7fx 2/2 Running 0 6h11m
gmp-system collector-vnrsm 2/2 Running 0 6h11m
gmp-system gmp-operator-5c469746b-xqhl7 1/1 Running 0 6h16m
gmp-system rule-evaluator-868cb9b64b-5l287 2/2 Running 2 (6h11m ago) 6h11m
istio-system istiod-asm-1157-23-66d49d9464-5qbjg 1/1 Running 0 6h4m
istio-system istiod-asm-1157-23-66d49d9464-z4tb6 1/1 Running 0 6h4m
kube-system event-exporter-gke-7d996c57bf-vs54l 2/2 Running 0 6h16m
kube-system fluentbit-gke-j2sdr 2/2 Running 0 6h11m
kube-system fluentbit-gke-qk5lm 2/2 Running 0 6h11m
kube-system fluentbit-gke-x98l9 2/2 Running 0 6h11m
kube-system gke-metadata-server-dzrfx 1/1 Running 0 6h11m
kube-system gke-metadata-server-jks6p 1/1 Running 0 6h11m
kube-system gke-metadata-server-vswwv 1/1 Running 0 6h11m
kube-system gke-metrics-agent-gzhgs 2/2 Running 0 6h11m
kube-system gke-metrics-agent-m6zrn 2/2 Running 0 6h11m
kube-system gke-metrics-agent-tkqkt 2/2 Running 0 6h11m
kube-system konnectivity-agent-74d9755866-gwvh5 2/2 Running 0 6h11m
kube-system konnectivity-agent-74d9755866-ld6zl 2/2 Running 0 6h16m
kube-system konnectivity-agent-74d9755866-s97vk 2/2 Running 0 6h11m
kube-system konnectivity-agent-autoscaler-5847cf65c7-bl4vd 1/1 Running 0 6h16m
kube-system kube-dns-6f955b858b-ghn4z 4/4 Running 0 6h16m
kube-system kube-dns-6f955b858b-lktdd 4/4 Running 0 6h11m
kube-system kube-dns-autoscaler-755c7dfdf5-l6f7l 1/1 Running 0 6h16m
kube-system kube-proxy-gke-gke-pool-12345-83dd774c-3ztq 1/1 Running 0 6h11m
kube-system kube-proxy-gke-gke-pool-12345-83dd774c-b860 1/1 Running 0 6h11m
kube-system kube-proxy-gke-gke-pool-12345-83dd774c-t93w 1/1 Running 0 6h11m
kube-system l7-default-backend-6779bb6c8d-r2v8p 1/1 Running 0 6h16m
kube-system metrics-server-v0.6.3-764c8d87d9-lxn6x 2/2 Running 0 6h16m
kube-system netd-j22qw 2/2 Running 0 6h11m
kube-system netd-ljtlt 2/2 Running 0 6h11m
kube-system netd-nt87b 2/2 Running 0 6h11m
kube-system pdcsi-node-7ffz7 2/2 Running 0 6h11m
kube-system pdcsi-node-dm4fv 2/2 Running 0 6h11m
kube-system pdcsi-node-lgj8s 2/2 Running 0 6h11m
legacy-client sleep-7dbc8959b8-4vkxz 1/1 Running 0 2m38s
legacy-service httpbin-6fcb98998c-l9rgk 1/1 Running 0 2m33s
mtls-client sleep-7dbc8959b8-zn29d 2/2 Running 0 76s
mtls-service httpbin-6fcb98998c-jkn6t 2/2 Running 0 71s
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that the two sleep clients can communicate with the two httpbin services
-
Use Cloud Shell to run this nested command loop:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ for from in "mtls-client" "legacy-client"; do for to in "mtls-service" "legacy-service"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n" done done sleep.mtls-client to httpbin.mtls-service: 200 sleep.mtls-client to httpbin.legacy-service: 200 sleep.legacy-client to httpbin.mtls-service: 200 sleep.legacy-client to httpbin.legacy-service: 200 student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Now you’re ready to enforce security policies for this application.
Understand authentication and enable service to service authentication with mTLS
-
Anthos Service Mesh
-
In the console, go to Navigation Menu > Anthos > Service Mesh.
In the Anthos Service Mesh dashboard, you will see the 2 services that were created in the
mtls-service
andmtls-client
namespaces. You don’t see the legacy services because you did not label their namespace, and therefore they remain outside of the mesh. -
Under Namespace dropdown select mtls-service namespace and then click on the httpbin service located below.
-
In the left side panel, go to Connected Services.
Notice that you have 2 services:
- The
sleep
service in themtls-client
namespace, which is part of the mesh and has a sidecar proxy. Therefore you see the real name and communication goes over mTLS, as it’s the default behavior in Istio. - An
unknown
service, which represents thesleep
service in thelegacy-client
, which is not part of the mesh and has no sidecar proxy. Therefore you do not see the real name and the communication goes over plain text.
Use your mouse to hover over the lock symbol in the Request port column, and verify that green means mTLS and red means plain text.
Now check out the Security tab in the left side panel. It shows you that the httpbin service has received both plaintext and mTLS traffic.
- The
-
-
Test auto mutual TLS
By default, Istio configures destination workloads in
PERMISSIVE
mode. WhenPERMISSIVE
mode is enabled a service can accept both plaintext and mTLS traffic. mTLS is used when the request contains the X-Forwarded-Client-Cert header.- Use the Cloud Shell to send a request from the sleep service in the mtls-client namespace to the httpbin service in the mtls-service namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec $(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name}) -c sleep -n mtls-client -- curl http://httpbin.mtls-service:8000/headers -s | grep X-Forwarded-Client-Cert "X-Forwarded-Client-Cert": "By=spiffe://qwiklabs-gcp-03-5d22baeeb714.svc.id.goog/ns/mtls-service/sa/httpbin;Hash=a7792218923e8cc1a44fd35c04937402fcb4e75dd36e40a6a39e455378d0884f;Subject=\"OU=istio_v1_cloud_workload,O=Google LLC,L=Mountain View,ST=California,C=US\";URI=spiffe://qwiklabs-gcp-03-5d22baeeb714.svc.id.goog/ns/mtls-client/sa/sleep" student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
The traffic included the X-Forwarded-Client-Cert header and therefore was mutually authenticated and encrypted
Now send a request from the sleep service in the mtls-client namespace to the httpbin service in the legacy-service namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec $(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name}) -c sleep -n mtls-client -- curl http://httpbin.legacy-service:8000/headers -s | grep X-Forwarded-Client-Cert
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
The X-Forwarded-Client-Cert header isn’t present so the traffic was sent and received in plaintext.
Finally, send a request from the sleep service in the legacy-client namespace to the httpbin service in the mtls-service namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec $(kubectl get pod -l app=sleep -n legacy-client -o jsonpath={.items..metadata.name}) -c sleep -n legacy-client -- curl http://httpbin.mtls-service:8000/headers -s | grep X-Forwarded-Client-Cert
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
The X-Forwarded-Client-Cert header isn’t present so the traffic was sent and received in plaintext
Note: The httpbin service in the mtls-service namespace accepted mTLS traffic from the sleep service in the mtls-client namespace and plaintext from the sleep service in the legacy-client namespace.
Enforce STRICT mTLS mode across the service mesh
In STRICT
mode, services injected with the Istio proxy will not accept plaintext traffic and will mutually authenticate with their clients.
You can enforce STRICT
mTLS mode across the whole mesh or on a per-namespace basis by creating PeerAuthentication resources.
Create a Peer Authentication resources for the entire Service Mesh:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -n istio-system -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "mesh-wide-mtls"
spec:
mtls:
mode: STRICT
EOF
peerauthentication.security.istio.io/mesh-wide-mtls created
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ for from in "mtls-client" "legacy-client"; do
for to in "mtls-service" "legacy-service"; do
kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"
done
done
sleep.mtls-client to httpbin.mtls-service: 200
sleep.mtls-client to httpbin.legacy-service: 200
sleep.legacy-client to httpbin.mtls-service: 000
command terminated with exit code 56
sleep.legacy-client to httpbin.legacy-service: 200
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Note: The httpbin service in the mtls-service namespace now rejects the plaintext traffic it receives from the sleep client in the legacy-client namespace.
Remove the mesh wide mTLS PeerAuthentication resource by running this command in Cloud Shell:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl delete pa mesh-wide-mtls -n istio-system
peerauthentication.security.istio.io "mesh-wide-mtls" deleted
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Enforce STRICT mTLS mode on a single namespace
-
In Cloud Shell create a namespace for
STRICT
mTLS: -
Enable auto-injection of the Istio sidecar proxy on the new namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl create ns strict-mtls-service namespace/strict-mtls-service created student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ # get the revision label export DEPLOYMENT=$(kubectl get deployments -n istio-system | grep istiod) export VERSION=asm-$(echo $DEPLOYMENT | cut -d'-' -f 3)-$(echo $DEPLOYMENT \ | cut -d'-' -f 4 | cut -d' ' -f 1) # enable auto-injection on the namespaces kubectl label namespace strict-mtls-service istio.io/rev=${VERSION} --overwrite namespace/strict-mtls-service labeled student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
deploy another instance of the httpbin service in the strict-mtls-service namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -f \ https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml \ -n strict-mtls-service serviceaccount/httpbin created service/httpbin created deployment.apps/httpbin created student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Create a PeerAuthentication resource for the strict-mtls-service namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -n strict-mtls-service -f - <<EOF apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "restricted-mtls" namespace: strict-mtls-service spec: mtls: mode: STRICT EOF peerauthentication.security.istio.io/restricted-mtls created student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that the httpbin service in the mtls-service namespace still accepts plaintext traffic:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec $(kubectl get pod -l app=sleep -n legacy-client -o jsonpath={.items..metadata.name}) -c sleep -n legacy-client -- curl "http://httpbin.mtls-service:8000/ip" -s -o /dev/null -w "sleep.legacy-client to httpbin.mtls-service: %{http_code}\n" sleep.legacy-client to httpbin.mtls-service: 200 student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Now check to see that the strict-mtls-service namespace httpbin service does not accept plaintext traffic:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec $(kubectl get pod -l app=sleep -n legacy-client -o jsonpath={.items..metadata.name}) -c sleep -n legacy-client -- curl "http://httpbin.strict-mtls-service:8000/ip" -s -o /dev/null -w "sleep.legacy-client to httpbin.strict-mtls-service: %{http_code}\n" sleep.legacy-client to httpbin.strict-mtls-service: 000 command terminated with exit code 56 student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that the httpbin service in the strict-mtls-service namespace does accept mTLS traffic:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec $(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name}) -c sleep -n mtls-client -- curl "http://httpbin.strict-mtls-service:8000/ip" -s -o /dev/null -w "sleep.mtls-client to httpbin.strict-mtls-service: %{http_code}\n" sleep.mtls-client to httpbin.strict-mtls-service: 200 student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl delete pa restricted-mtls -n strict-mtls-service peerauthentication.security.istio.io "restricted-mtls" deleted student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Leverage RequestAuthentication and AuthorizationPolicy resources
This task shows you how to set up and use RequestAuthentication and AuthorizationPolicy resources. Ultimately, you will allow requests that have an approved JWT, and deny requests that don’t.
RequestAuthentication
A RequestAuthentication resource defines the request authentication methods that are supported by a workload. Requests with invalid authentication information will be rejected. Requests with no authentication credentials will be accepted but will not have any authenticated identity.
- Create a RequestAuthentication resource for the
httpbin
workload in themtls-service
namespace. This policy allows the workload to accept requests with a JWT issued bytesting@secure.istio.io
.
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
name: "jwt-example"
namespace: mtls-service
spec:
selector:
matchLabels:
app: httpbin
jwtRules:
- issuer: "testing@secure.istio.io"
jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.8/security/tools/jwt/samples/jwks.json"
EOF
requestauthentication.security.istio.io/jwt-example created
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that a request with an invalid JWT is denied:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec "$(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name})" -c sleep -n mtls-client -- curl "http://httpbin.mtls-service:8000/headers" -s -o /dev/null -H "Authorization: Bearer invalidToken" -w "%{http_code}\n"
401
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that a request without any JWT is allowed:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec "$(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name})" -c sleep -n mtls-client -- curl "http://httpbin.mtls-service:8000/headers" -s -o /dev/null -w "%{http_code}\n"
200
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
AuthorizationPolicy
- Create an AuthorizationPolicy resource for the
httpbin
workload in themtls-service
namespace:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: mtls-service
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
EOF
authorizationpolicy.security.istio.io/require-jwt created
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
The policy requires all requests to the httpbin
workload to have a valid JWT with requestPrincipal
set to testing@secure.istio.io/testing@secure.istio.io
. Istio constructs the requestPrincipal
by combining the iss
and sub
of the JWT token with a / separator as shown:
Download a legitimate JWT that can be used to send accepted requests:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.8/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode -
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Note that the iss
and sub
keys are set to testing@secure.istio.io
. This causes Istio to generate the attribute requestPrincipal
with the value testing@secure.istio.io/testing@secure.istio.io
Verify that a request with a valid JWT is allowed:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec "$(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name})" -c sleep -n mtls-client -- curl "http://httpbin.mtls-service:8000/headers" -s -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
200
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that a request without a JWT is denied:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec "$(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name})" -c sleep -n mtls-client -- curl "http://httpbin.mtls-service:8000/headers" -s -o /dev/null -w "%{http_code}\n"
403
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Authorizing requests based on method and path
This task shows you how to control access to workloads by using an AuthorizationPolicy that evaluates the request type and URL.
Update the require-jwt
authorization policy for the httpbin
workload in the mtls-service
namespace. The new policy will still have the JWT requirement that you set up in the previous task. In addition, you are going to limit the type of HTTP requests, so that clients can only perform GET requests to the /ip
endpoint:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: mtls-service
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
to:
- operation:
methods: ["GET"]
paths: ["/ip"]
EOF
authorizationpolicy.security.istio.io/require-jwt configured
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that a request to the httpbin
’s /ip
endpoint works:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec "$(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name})" -c sleep -n mtls-client -- curl "http://httpbin.mtls-service:8000/ip" -s -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
200
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Verify that a request to the httpbin
’s /headers
endpoint is denied:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl exec "$(kubectl get pod -l app=sleep -n mtls-client -o jsonpath={.items..metadata.name})" -c sleep -n mtls-client -- curl "http://httpbin.mtls-service:8000/headers" -s -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
403
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
Remove the require-jwt authorization policy by running this command:
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$ kubectl delete AuthorizationPolicy require-jwt -n mtls-service
authorizationpolicy.security.istio.io "require-jwt" deleted
student_03_9e708a64b511@cloudshell:~ (qwiklabs-gcp-03-5d22baeeb714)$
In this lab, you explored mutual TLS authentication in Istio. You saw how PERMISSIVE mode mTLS allows services to receive both plaintext and mTLS traffic from clients, allowing you to incrementally adopt mTLS. You also enabled STRICT mode mTLS across your service mesh effectively blocking plaintext traffic to all your Istio injected services and then you scoped STRICT mode mTLS down to a single namespace.
In addition, you explored RequestAuthentication and AuthorizationPolicy resources in Istio.