Skip to content

Access control💣

In this lab, we will learn how to use an authorization policy to control access between workloads.

Let’s enable automatic sidecar injection on the default namespace by adding the label istio-injection=enabled:

kubectl label namespace default istio-injection=enabled

Check that the default namespace contains the label for Istio proxy injection.

kubectl get namespace -L istio-injection
default             Active   19h   enabled
kube-system         Active   19h
kube-public         Active   19h
kube-node-lease     Active   19h
flux-system         Active   19h
bigbang             Active   16h
jaeger              Active   16h   enabled
gatekeeper-system   Active   16h
istio-operator      Active   16h   disabled
logging             Active   16h   enabled
monitoring          Active   16h
kiali               Active   16h   enabled
istio-system        Active   16h
eck-operator        Active   16h

Next, we will create the Web frontend deployment, service account, service, and a VirtualService.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: web-frontend
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-frontend
  labels:
    app: web-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-frontend
  template:
    metadata:
      labels:
        app: web-frontend
        version: v1
    spec:
      serviceAccountName: web-frontend
      containers:
        - image: gcr.io/tetratelabs/web-frontend:1.0.0
          imagePullPolicy: Always
          name: web
          ports:
            - containerPort: 8080
          env:
            - name: CUSTOMER_SERVICE_URL
              value: 'http://customers.default.svc.cluster.local'
---
kind: Service
apiVersion: v1
metadata:
  name: web-frontend
  labels:
    app: web-frontend
spec:
  selector:
    app: web-frontend
  ports:
    - port: 80
      name: http
      targetPort: 8080
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: web-frontend
spec:
  hosts:
    - 'frontend.bigbang.dev'
  gateways:
    - istio-system/public
  http:
    - route:
        - destination:
            host: web-frontend.default.svc.cluster.local
            port:
              number: 80

Save the above YAML to web-frontend.yaml and create the resource using kubectl apply -f web-frontend.yaml.

Finally, we will deploy the customers v1 service.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: customers
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: customers-v1
  labels:
    app: customers
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: customers
      version: v1
  template:
    metadata:
      labels:
        app: customers
        version: v1
    spec:
      serviceAccountName: customers
      containers:
        - image: gcr.io/tetratelabs/customers:1.0.0
          imagePullPolicy: Always
          name: svc
          ports:
            - containerPort: 3000
---
kind: Service
apiVersion: v1
metadata:
  name: customers
  labels:
    app: customers
spec:
  selector:
    app: customers
  ports:
    - port: 80
      name: http
      targetPort: 3000
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: customers
spec:
  hosts:
    - 'customers.default.svc.cluster.local'
  http:
    - route:
        - destination:
            host: customers.default.svc.cluster.local
            port:
              number: 80

Save the above to customers-v1.yaml and create the deployment and service using kubectl apply -f customers-v1.yaml. If we open the web frontend page in frontend.bigbang.dev, the data from the customers v1 service should be displayed.

To reach the host frontend.bigbang.dev, it is necessary to add the following line in /etc/hosts:

<public-ip> frontend.bigbang.dev

Let’s start by creating an authorization policy that denies all requests in the default namespace.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: deny-all
 namespace: default
spec:
  {}

Save the above to deny-all.yaml and create the policy using kubectl apply -f deny-all.yaml.

If we try to access frontend.bigbang.dev we will get back the following response:

RBAC: access denied

Similarly, if we try to run a Pod inside the cluster and make a request from within the default namespace to either the web frontend or the customer service, we’ll get the same error.

Let’s try that:

kubectl run curl --rm --image=radial/busyboxplus:curl -i --tty

From inside curl pod:

curl customers
RBAC: access denied

curl web-frontend
RBAC: access denied

In both cases, we get back the access denied error.

The first thing we will do is to allow requests being sent from the ingress gateway to the web-frontend application using an ALLOW action. In the rules, we are specifying the source namespace (istio-system) where the ingress gateway is running and the ingress gateway’s service account name in the principals field.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-ingress-frontend
  namespace: default
spec:
  selector:
    matchLabels:
      app: web-frontend
  action: ALLOW
  rules:
    - from:
        - source:
            namespaces: ["istio-system"]
        - source:
            principals: ["public-ingressgateway-service-account"]

Save the above to allow-ingress-frontend.yaml and create the policy using kubectl apply -f allow-ingress-frontend.yaml.

If we try to make a request from our host to the frontend.bigbang.dev, we will get a different error this time:

curl https://frontend.bigbang.dev/
"Request failed with status code 403"

This error is coming from the customers service - remember we allowed calls to the web frontend. However, web-frontend still can’t make calls to the customers service.

If we go back to the curl Pod and try to request curl web-frontend we will get an RBAC error.

The DENY policy is in effect, and we are only allowing calls to be made from the ingress gateway.

When we deployed the web frontend, we also created a service account for the Pod (otherwise, all Pods in the namespace are assigned the default service account). We can now use that service account to specify where the customer service calls can come from.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-web-frontend-customers
  namespace: default
spec:
  selector:
    matchLabels:
        app: customers
        version: v1
  action: ALLOW
  rules:
  - from:
    - source:
        namespaces: ["default"]
    - source:
        principals: ["web-frontend"]

Save the above YAML to allow-web-frontend-customers.yaml and create the policy using kubectl apply -f allow-web-frontend-customers.yaml.

As soon as the policy is created, we will see the web frontend working again. You can try that it works by opening the frontend.bigbang.dev in the browser.

We have used multiple authorization policies to explicitly allow calls from the ingress to the front end and from the frontend to the customer service. Using a deny-all policy is a good way to start because we can control, manage, and then explicitly allow the communication we want to happen between services.

Clean-up💣

The following commands will clean-up your cluster.

kubectl delete -f web-frontend.yaml
kubectl delete -f customers-v1.yaml
kubectl delete -f allow-ingress-frontend.yaml
kubectl delete -f deny-all.yaml
kubectl delete -f allow-web-frontend-customers.yaml