Skip to main content
Calico Cloud documentation

Application layer policy tutorial

This tutorial shows how to use Calico Cloud application layer policy to restrict ingress traffic for applications and microservices.

Install the demo application

We will use a simple microservice application to demonstrate Calico Cloud application layer policy. The YAO Bank application creates a customer-facing web application, a microservice that serves up account summaries, and an etcd datastore.

kubectl apply -f https://docs.tigera.io/files/10-yaobank.yaml
namespace/yaobank configured
service/database created
serviceaccount/database created
deployment.apps/database created
service/summary created
serviceaccount/summary created
deployment.apps/summary created
service/customer created
serviceaccount/customer created
deployment.apps/customer created

Verify that the application pods have been created and are ready.

    kubectl rollout status deploy/summary deploy/customer deploy/database

When the demo application is displayed, you will see three pods.

NAME                        READY     STATUS    RESTARTS   AGE
customer-2809159614-qqfnx 3/3 Running 0 21h
database-1601951801-m4w70 3/3 Running 0 21h
summary-2817688950-g1b3n 3/3 Running 0 21h

Set up

  • A Calico Cloud cluster is running with application layer policy enabled
  • Cluster has three microservices: customer, database, summary
  • The customer web service should not have access to the backend database, but should have access to clients outside the cluster

Imagine what would happen if an attacker were to gain control of the customer web pod in our application. Let's simulate this by executing a remote shell inside that pod.

kubectl exec -ti customer-<fill in pod ID> -c customer -- bash

Notice that from here, we get direct access to the backend database. For example, we can list all the entries in the database like this:

curl http://database:2379/v2/keys?recursive=true | python -m json.tool

(Piping to python -m json.tool nicely formats the output.)

Apply application layer policy

In this step, we get the application layer policy YAML and apply it. Note that the policy scope is cluster-wide.

With a Calico Cloud policy, you can mitigate risks to the banking application.

wget https://docs.tigera.io/files/30-policy.yaml
kubectl create -f 30-policy.yaml

Let's examine this policy piece by piece. First, notice that an application layer policy looks like a regular Calico Cloud global network policy. The only difference you'll see is the ability to use the application layer policy parameters in global network policy. Another important difference is that you'll see HTTP traffic flows in Manager UI in features like Service Graph.

Next, there are three policy objects, one for each microservice.

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: customer
spec:
selector: app == 'customer'
ingress:
- action: Allow
http:
methods: ['GET']
egress:
- action: Allow

The first policy protects the customer web app. Because this application is customer-facing, we do not restrict what can communicate with it. We do, however, restrict its communications to HTTP GET requests.

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: summary
spec:
selector: app == 'summary'
ingress:
- action: Allow
source:
serviceAccounts:
names: ['customer']
egress:
- action: Allow

The second policy protects the account summary microservice. We know the only consumer of this service is the customer web app, so we restrict the source of incoming connections to the service account for the customer web app.

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: database
spec:
selector: app == 'database'
ingress:
- action: Allow
source:
serviceAccounts:
names: ["summary"]
egress:
- action: Allow

The third policy protects the database. Only the summary microservice should have direct access to the database.

Verify the policy is working

Let's verify our policy is working as intended. First, return to your browser and refresh to ensure policy enforcement has not broken the application.

Next, return to the customer web app. Recall that we simulated an attacker gaining control of that pod by executing a remote shell inside it.

kubectl exec -ti customer-<fill in pod ID> -c customer bash

Repeat our attempt to access the database.

curl -I http://database:2379/v2/keys?recursive=true

We omitted the JSON formatting because we do not expect to get a valid JSON response. This time we should get a 403 Forbidden response. Only the account summary microservice has database access according to our policy.