Otherwise, you will create network policies and there won't be anything to enforce them. In the worse case, you might think that you have secured access to an application but the pods are actually still open to request from anywhere. There won't be any error messages when you create the policy. It will be created successfully but we'll simply have no effect. The cluster administrator can tell you if the network plugin in your cluster supports network policy or not. Some examples of network plugins that support network policy are Calico and Romana. With that caveat out of the way, we can talk about two kinds of pods, isolated and non-isolated. A pod that is non-isolated allows traffic from any source. This is the default behavior. Once a pod is selected by a network policy it becomes isolated. The pods are selected using labels, which are the core grouping primitive in Kubernetes. Let's see how to use network policies in a demo by writing several network policies and observing their effects. To begin with, I am running a cluster with the Calico network plugin installed. You can see that by checking the pods in the kube-system namespace, and observe there're several pods beginning with calico.
Calico is one of the network plugins that support network policy. I have created three pods in the network policy namespace. One is a server and the other two are clients that send requests to the server every second. Client one is in the U.S. East region, while client two is in the U.S. West region. Both clients are able to send requests and get responses from the server. This can be seen by watching the logs of each client. I use the -f option to follow or stream the logs for each pod. New logs are generated every second acknowledging response was received from the server. Let's take a look at our first policy. Working our way down from the top, network policies are included in the networking API. This policy is made to allow traffic from the U.S. East region and is scoped to the network policy namespace. In the spec, first there is a pod selector that selects the pods that the policy applies to. Here we are using the match labels selector to select any pod with the app server label. This applies to the single server pod that is running in the cluster. If the pod selector were empty the policy would apply to all pods in the namespace. Next is the policy types list. The two allowed values are ingress to indicate the policy applies to incoming traffic, and egress to indicate the policy applies to outgoing traffic. You can include one or the other, or both as in this case.
If, for example, you only included egress, then all ingress traffic would be allowed by the policy. Corresponding to the ingress policy type is the ingress list, which specifies rules for where the traffic is allowed. Each rule includes a from list specifying sources and a ports list specifying allowed ports. If the from list is omitted, all sources of traffic are allowed on the specified ports. If the ports list is omitted, traffic on all ports is allowed from the specified sources. If both are omitted, all traffic on all ports is allowed. Source rules can be made of pod selectors to select traffic based on pod labels, namespace selectors to select based on the namespace of pods or IP block to select based on a range of IP addresses. This policy uses a pod selector to allow ingress traffic from pods with the us-east region label. Each item in the ports list can restrict the allowed traffic to a given port and protocol. In this example, TCP port 8888 is allowed because that is the port the server listens to. The egress mapping includes a "to" map that lists rules in the same format as the ingress rules. In this case, no rules are specified so all outbound traffic is allowed. Let's create the policy and then check to verify that client one in the U.S. East region is allowed to communicate with the server. And it is because responses are still being received. What if we check client two, which is in the U.S. West region? There're no new log messages being received.
The policy is doing its job. Besides doing some basic tests like this, you can always use the describe command to check that the policy is doing what you expect. It outputs a description of the policy in a relatively easy to understand format. Now let's look at one more policy to see how IP block rules are configured. This policy is constructed to block outgoing traffic to a single IP address from app server pods. This policy is an egress-only policy so there is no ingress included in the policy types list. The egress list has a single IP block rule. There're two parts to the rule. The cidr field is required and sets a range of allowed IP addresses. Cidr is a notation for representing a block of IP addresses. 0.0.0.0/0 represents all IP addresses. If that was the complete rule all outgoing traffic would be allowed. However, there is an except list. The except field is optional but when included, it acts as a blacklist within the white list that the cidr field specifies. In this case, there's a single exception which represents one IP address. That IP address happens to be the IP address of the client one pod. This is for demonstration purposes only. In general, you should use labels when selecting pods in your cluster because pods should be treated as ephemeral.
They can be terminated and brought up again with a different IP address, or as labels remain the same. No port list is specified so all ports are allowed. Let's go ahead and create the policy. Now there're two policies being enforced. One allows incoming traffic from the U.S. East region, which allows client one traffic in the current cluster. And the second policy denies outgoing traffic from the server to client one. Think about what you might expect to observe. Will either client pod receive responses from the server? Let's check. Client two still doesn't receive responses. What about client one? It is still receiving responses. That may come as a surprise. We never discussed how policies are combined. For network policies you should think of them as sets of allow rules that are added together. If any rule allows traffic, even if others deny it, the traffic is allowed. In this case, the default allow egress rule and the first policy allows all egress, even though the second policy has blacklisted a specific IP. So to see the effect of the IP block rule, we can delete the first policy with the default allow egress rule.
Now, if we check the logs for client one, which is not allow egress according to the policy that is being enforced, it is still able to receive responses. What is happening now? The rules apply to new connections. In the case of a client sending a request to the server, the connection is already in place and the response is sent back through the same existing connection. There is no new connection so the network policy can't block the egress. However, if we create a connection from the server, say by running the ping command, to ping the client one pod, we can see that there is no response. Contrast that with client two which we can see that we get a response. To have a clear picture of how network policies work, it is important to remember how multiple policies are combined and that the rules apply to creating connections, not traffic sent over established connections. That's all for this lesson on Kubernetes networking. We began with a review of basic networking principles. Then we paid some extra attention to the different types of services available in Kubernetes. Lastly, we discussed network policies and how they can restrict traffic that is allowed to and from pods. In the next lesson, you will continue with the theme of security in Kubernetes and learn about service accounts.