= Defining a Network Policy :toc: :icons: :linkcss: :imagesdir: ../../resources/images == What is Network Policy? Kubernetes Network Policy objects allow for fine-grained network policy enforcement, ensuring that traffic within your Kubernetes cluster can only flow in the direction that you specify. As an example, if we take a scenario where Kubernetes namespaces are used to enforce boundaries between products, or even enforce boundaries between different environments (e.g. development vs production), network policies can be configured to ensure no unauthorized network traffic is allowed beyond its boundary. Think of it as being similar to applying Security Groups in the AWS world. == Implementations Network policies are implemented by an add-on; there are several available. Any of these solutions allow you to specify a network policy and then enforce the rules while your services are running. === Calico https://www.projectcalico.org[Calico] is an open-source plugin that implements pod networking and Network Policy. | link:calico[Set up a Kubernetes cluster with Calico] === Weave Net https://www.weave.works/docs/net/latest/kubernetes/kube-addon/[Weave Net] is an open-source plugin that implements pod networking and Network Policy. If you're using https://www.weave.works/docs/cloud/latest/concepts/network-policy/[Weave Cloud] you can visualize your container networks and services all from a single dashboard and also configure monitoring to alert you about any suspicious network activity. | link:weavenet[Set up a Kubernetes cluster with Weave Net] == Enforcing network isolation You must install one of the above Network Policy add-ons before continuing. Then we will configure Kubernetes Network Policies. We will create a namespace, deploy some test pods into it, and see the before and after effects of configuring a Network Policy, which will be enforced by the add-on you just installed. All configuration files for this chapter are in the `network-policies` directory. Make sure you change to that directory before giving any commands in this chapter. === Precheck . Create a namespace: $ kubectl create ns ns-1 namespace "ns-1" created . Deploy a container into namespace `ns-1` that will expose an http endpoint, and log all requests it receives. First, create a Deployment, ReplicaSet and Pod using the command: $ kubectl run --namespace=ns-1 http-echo --image=solsson/http-echo --env="PORT=80" --port=80 deployment "http-echo" created . Label the pod (we will use labels as part of defining network policies): $ kubectl label po --selector=run=http-echo --namespace=ns-1 app=http-echo pod "http-echo-1790350443-z2v7n" labeled . Create a Service to expose the pod: $ kubectl expose --namespace=ns-1 deployment http-echo --port=80 service "http-echo" exposed + Monitor the logs of the deployed container by querying the name of the pod defined with the label `run=http-echo`, then passing it to the `kubectl logs` command: + ``` kubectl get po \ --selector=run=http-echo \ --namespace=ns-1 \ -o jsonpath='{.items[*].metadata.name}' | \ xargs kubectl logs -f --namespace=ns-1 ``` + This command will sit silently until `http-echo` logs a request. + Let's say this is `shell 1`. + . In another shell, say `shell 2`, deploy a second container: $ kubectl run \ --namespace=ns-1 \ -i --tty \ busybox \ --image=busybox \ --restart=Never \ -- sh If you don't see a command prompt, try pressing enter. / # + . We will now attempt to call the `http-echo` pod from our `busybox` pod by performing an HTTP POST . As we have no network policies in place, we should see the following command return successfully with a 200 response, along with a log message being output in the `http-echo` shell window: + ``` / # wget -S http://http-echo.ns-1.svc.cluster.local/test --post-data '{"message":"hello"}' -O test Connecting to http-echo.ns-1.svc.cluster.local (100.71.77.153:80) HTTP/1.1 200 OK X-Powered-By: Express Content-Type: application/json; charset=utf-8 Content-Length: 533 ETag: W/"215-KyoPN1JoGjQlzW9TxpIay22VPF8" Date: Thu, 26 Oct 2017 00:53:21 GMT Connection: close test 100% |*************************************************************************************************| 533 0:00:00 ETA ``` HTTP POST request succeeds. === Create default network policy Let's now create a Network Policy, but we will not configure any rules which by default will deny all traffic within the namespace. Leaving the 2 shells open from the previous steps, run the following in another shell, say `shell 3`: $ kubectl create -f templates/deny-all-by-default-network-policy.yaml --namespace=ns-1 networkpolicy "deny-all-by-default" created When running the following command again in shell 2, we should see it eventually timeout and fail (note that rather than waiting for it to time out, you can press `Ctrl` + `C` to quit after about 10 seconds once satisfied that no response will be returned): ``` / # wget -S http://http-echo.ns-1.svc.cluster.local/test --post-data '{"message":"hello"}' -O test Connecting to http-echo.ns-1.svc.cluster.local (100.64.161.56:80) wget: can't connect to remote host (100.64.61.223): Connection timed out ``` === Create network policy with a rule We will now delete the NetworkPolicy that we just created, and create a new NetworkPolicy with a rule defined. If you `cat templates/allow-network-policy.yaml` you will see the following rule defined: spec: podSelector: matchLabels: app: http-echo ingress: - from: - podSelector: matchLabels: app: busybox The rule above is stating that for every pod that has the label `app: http-echo` defined, allow access to it from pods that have the label `app: busybox` defined. Run the following in `shell 3` to remove the deny all by default rule, and replace with the above allow rule: $ kubectl delete netpol deny-all-by-default --namespace=ns-1 networkpolicy "deny-all-by-default" deleted $ kubectl create -f templates/allow-network-policy.yaml --namespace=ns-1 networkpolicy "allow" created If we repeat the following command in `shell 2`, the call should still timeout and fail (again, you can press CTRL-C to quit after 10 seconds rather than waiting for the full timeout to occur): ``` / # wget -S http://http-echo.ns-1.svc.cluster.local/test --post-data '{"message":"hello"}' -O test Connecting to http-echo.ns-1.svc.cluster.local (100.64.161.56:80) wget: can't connect to remote host (100.64.61.223): Connection timed out ``` Why is this still failing even after creating a rule? It is failing because we configured the rule so that only pods with the label `app: busybox` are authorized to call pods with the label `app: http-echo`. Let's go ahead and label our `busybox` pod on `shell 3`: / # kubectl label po --selector=run=busybox --namespace=ns-1 app=busybox pod "busybox" labeled Repeating the test in `shell 2` again should now be successful: ``` / # wget -S http://http-echo.ns-1.svc.cluster.local/test --post-data '{"message":"hello"}' -O test Connecting to http-echo.ns-1.svc.cluster.local (100.64.161.56:80) HTTP/1.1 200 OK X-Powered-By: Express Content-Type: application/json; charset=utf-8 Content-Length: 536 ETag: W/"218-xgvU8WZSN+2SEyOX6Q2R/AhLuRM" Date: Thu, 26 Oct 2017 02:15:32 GMT Connection: close test 100% |*************************************************************************************************| 534 0:00:00 ETA ``` == Teardown Remove all the resources and the namespace using the command: $ kubectl delete ns ns-1 namespace "ns-1" deleted You are now ready to continue on with the workshop! :frame: none :grid: none :valign: top [align="center", cols="2", grid="none", frame="none"] |===== |image:button-continue-developer.png[link=../../04-path-security-and-networking/405-ingress-controllers/] |image:button-continue-operations.png[link=../../04-path-security-and-networking/405-ingress-controllers/] |link:../../developer-path.adoc[Go to Developer Index] |link:../../operations-path.adoc[Go to Operations Index] |=====