Application layer policy tutorial
This tutorial shows how to use Calico Enterprise 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 Enterprise 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
You can also view the manifest in your browser.
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 Enterprise 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 Enterprise 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 Enterprise 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.