---
title: "Application layer policy tutorial"
description: "Step-by-step tutorial for applying Calico Cloud application-layer policy to workloads in a connected cluster — control ingress traffic by HTTP attributes."
product: "Calico Cloud"
version: "v23.0.1"
section: "Network policy"
canonical_url: "https://docs.tigera.io/calico-cloud/network-policy/application-layer-policies/alp-tutorial"
---

# 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](https://github.com/projectcalico/yaobank) application creates a customer-facing web application, a microservice that serves up account summaries, and an [etcd](https://github.com/coreos/etcd) datastore.

```bash
kubectl apply -f https://docs.tigera.io/files/10-yaobank.yaml
```

```bash
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
```

> **SECONDARY:** You can also [view the manifest in your browser](https://docs.tigera.io/assets/files/10-yaobank-e41239c6a0de293afb2f1b3c6a44eee6.yaml).

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

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

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

```text
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.

```bash
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:

```bash
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.

```bash
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 the web console in features like Service Graph.

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

```yaml
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.

```yaml
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.

```yaml
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.

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

Repeat our attempt to access the database.

```bash
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.
