An Introduction to Kubernetes Network Policies for Security Professionals

An Introduction to Kubernetes Network Policies for Security Professionals

Note. transl.: The author of the article - Reuven Harrison - has over 20 years of experience in software development, and today is the CTO and co-founder of Tufin, a security policy management solutions company. While he considers Kubernetes network policies to be powerful enough to segment the network in a cluster, he also believes that they are not so easy to implement in practice. This material (rather voluminous) is intended to improve the awareness of specialists in this matter and help them in creating the necessary configurations.

Today, many companies are increasingly choosing Kubernetes to run their applications. Interest in this software is so high that some call Kubernetes "the new operating system for data centers." Gradually, Kubernetes (or k8s) is beginning to be perceived as a critical part of the business, which requires the organization of mature business processes, including network security.

For security professionals who have been puzzled by working with Kubernetes, the default policy of this platform can be a real discovery: allow everything.

This guide will help you understand the inner workings of network policies; understand how they differ from the rules for regular firewalls. It will also talk about some of the pitfalls and give recommendations that will help protect applications in Kubernetes.

Kubernetes network policies

The Kubernetes network policy mechanism allows you to manage the interaction of applications deployed on the platform at the network layer (the third in the OSI model). Network policies lack some of the advanced features of modern firewalls, such as OSI layer 7 control and threat detection, but they provide a basic layer of network security that is a good starting point.

Network policies control communications between pods

Workloads in Kubernetes are distributed across pods, which consist of one or more containers deployed together. Kubernetes assigns each pod an IP address accessible from other pods. Kubernetes network policies set access permissions for groups of pods in the same way that security groups in the cloud are used to control access to virtual machine instances.

Defining Network Policies

Like other Kubernetes resources, network policies are set in YAML. In the example below, the application balance opens access to postgres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: balance
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

(Note. transl.: this screenshot, like all subsequent similar screenshots, was not created using native Kubernetes tools, but using the Tufin Orca tool, which was developed by the company of the author of the original article and which is mentioned at the end of the material.)

Basic knowledge of YAML is required to define your own network policy. This language is based on indentation (specified by spaces, not tabs). The indented element belongs to the nearest indented element above it. The new element of the list starts with a hyphen, all other elements are of the form key-value.

After describing the policy in YAML, use kubectlto create it in the cluster:

kubectl create -f policy.yaml

Network Policy Specification

The Kubernetes network policy specification includes four elements:

  1. podSelector: defines the pods affected by this policy (targets) - required;
  2. policyTypes: indicates what types of policies are included in this one: ingress and/or egress - optional, but I recommend explicitly specifying it in all cases;
  3. ingress: defines allowed incoming traffic to target pods - optional;
  4. egress: defines allowed outgoing traffic from target pods is optional.

An example borrowed from the Kubernetes site (I replaced role on app), shows how all four elements are used:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:    # <<<
    matchLabels:
      app: db
  policyTypes:    # <<<
  - Ingress
  - Egress
  ingress:        # <<<
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:         # <<<
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

An Introduction to Kubernetes Network Policies for Security Professionals
An Introduction to Kubernetes Network Policies for Security Professionals

Note that it is not necessary to include all four elements. It is only required podSelector, the rest of the parameters can be used as desired.

If we omit policyTypes, the policy will be interpreted as follows:

  • It is assumed by default to define the ingress side. If the policy does not explicitly indicate this, the system will assume that all traffic is prohibited.
  • The behavior on the egress side will be determined by the presence or absence of the corresponding egress parameter.

To avoid mistakes, I recommend always be explicit policyTypes.

According to the logic above, in case the parameters ingress and / or egress omitted, the policy will deny all traffic (see "Sweep Rule" below).

Default policy - allow

If no policies are defined, Kubernetes allows all traffic by default. All pods can freely exchange information with each other. From a security point of view, this may seem counterintuitive, but remember that Kubernetes was originally created by developers with the goal of making applications interoperable. Network policies were added later.

Namespaces

Namespaces are the Kubernetes collaboration mechanism. They are designed to isolate logical environments from each other, while allowing communication between spaces by default.

Like most Kubernetes components, network policies live in a specific namespace. In the block metadata you can specify which space the policy belongs to:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace  # <<<
spec:
...

If the namespace is not explicitly specified in the metadata, the system will use the namespace specified in kubectl (default namespace=default):

kubectl apply -n my-namespace -f namespace.yaml

I recommend specify namespace explicitly, unless you are writing a policy that targets multiple namespaces at once.

Primary element podSelector in the policy will select pods from the namespace to which the policy belongs (it does not have access to pods from another namespace).

Similarly, podSelectors in ingress and egress blocks can only select pods from their own namespace, unless, of course, you combine them with namespaceSelector (This will be discussed in the "Filter by namespaces and pods" section).

Policy Naming Rules

Policy names are unique within the same namespace. There cannot be two policies with the same name in the same space, but there can be policies with the same name in different spaces. This is useful when you want to reapply the same policy across multiple spaces.

I especially like one of the naming methods. It consists of concatenating the namespace name with the target pods. For example:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres  # <<<
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

Labels

Custom labels can be attached to Kubernetes objects such as pods and namespaces. Labels (labels tags) are the equivalent of tags in the cloud. Kubernetes network policies use labels to select podsto which they apply:

podSelector:
  matchLabels:
    role: db

… or namespacesto which they apply. This example selects all pods in namespaces with matching labels:

namespaceSelector:
  matchLabels:
    project: myproject

One caveat: when using namespaceSelector make sure the namespaces you select contain the correct label. Be aware that built-in namespaces such as default ΠΈ kube-system, do not contain labels by default.

You can add a label to a space like this:

kubectl label namespace default namespace=default

In this case, the namespace in the section metadata should refer to the actual name of the space, not the label:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default   # <<<
spec:
...

Source and Destination

Firewall policies consist of source and destination rules. Kubernetes network policies are defined per target, the set of pods they apply to, and then set rules for ingress and/or egress traffic. In our example, the policy target will be all pods in the namespace default with key label app and the value db:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: db   # <<<
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

An Introduction to Kubernetes Network Policies for Security Professionals
An Introduction to Kubernetes Network Policies for Security Professionals

Subsection ingress in this policy opens incoming traffic to target pods. In other words, the ingress is the source and the target is the corresponding destination. Similarly, egress is the destination, and the target is its source.

An Introduction to Kubernetes Network Policies for Security Professionals

This is equivalent to two firewall rules: Ingress β†’ Target; Target β†’ Egress.

Egress and DNS (important!)

Restricting outgoing traffic pay special attention to DNS - Kubernetes uses this service to map services to IP addresses. For example, the following policy will not work because you have not allowed the application balance access DNS:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  policyTypes:
  - Egress

An Introduction to Kubernetes Network Policies for Security Professionals

You can fix it by opening access to the DNS service:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:               # <<<
    ports:            # <<<
    - protocol: UDP   # <<<
      port: 53        # <<<
  policyTypes:
  - Egress

An Introduction to Kubernetes Network Policies for Security Professionals

Last element to is empty, and so it indirectly chooses all pods in all namespaces, allowing balance send DNS queries to the appropriate Kubernetes service (usually it runs in space kube-system).

This approach works, however overly permissive and insecure, because it allows you to direct DNS queries outside the cluster.

You can improve it in three consecutive steps.

1. Allow DNS queries only inside cluster by adding namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector: {} # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

An Introduction to Kubernetes Network Policies for Security Professionals

2. Allow DNS queries only in the namespace kube-system.

To do this, you need to add a label to the namespace kube-system: kubectl label namespace kube-system namespace=kube-system - and register it in the policy using namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector:         # <<<
        matchLabels:             # <<<
          namespace: kube-system # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

An Introduction to Kubernetes Network Policies for Security Professionals

3. Paranoid people can go even further and restrict DNS requests to a specific DNS service in kube-system. The "Filter by namespaces AND pods" section will show you how to achieve this.

Another option is to resolve DNS at the namespace level. In this case, it won't need to be opened for every service:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.dns
  namespace: default
spec:
  podSelector: {} # <<<
  egress:
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Empty podSelector selects all pods in the namespace.

An Introduction to Kubernetes Network Policies for Security Professionals

First match and rule order

In conventional firewalls, the action (Allow or Deny) on a packet is determined by the first rule it satisfies. In Kubernetes, the order of policies doesn't matter.

By default, when no policies are set, communication between pods is allowed and they can exchange information freely. As soon as you start formulating policies, each pod affected by at least one of them becomes isolated according to the disjunction (logical OR) of all the policies that have selected it. Pods not affected by any policy remain open.

You can change this behavior with a sweep rule.

Cleanup Rule ("Forbid")

Firewall policies usually deny any traffic that is not explicitly allowed.

Kubernetes does not have a "deny" action, but the same effect can be achieved with a normal (permissive) policy by selecting an empty group of source pods (ingress):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

This policy selects all pods in the namespace and leaves ingress undefined, denying all incoming traffic.

Similarly, you can restrict all outgoing traffic from the namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress

An Introduction to Kubernetes Network Policies for Security Professionals

Please note that any additional policies that allow traffic to pods in the namespace will take precedence over this rule (similar to adding an allow rule before a deny rule in the firewall configuration).

Allow all (Any-Any-Any-Allow)

To create an "Allow All" policy, you need to supplement the above deny policy with an empty element ingress:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: default
spec:
  podSelector: {}
  ingress: # <<<
  - {}     # <<<
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

It provides access to all pods in all namespaces (and all IPs) to any pod in the namespace default. This behavior is enabled by default, so it usually doesn't need to be further defined. However, sometimes it may be necessary to temporarily disable certain specific permissions in order to diagnose the problem.

The rule can be narrowed down to only allow access to a specific set of pods (app:balance) in the namespace default:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-to-balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  ingress: 
  - {}
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

The following policy allows all incoming (ingress) AND outgoing (egress) traffic, including access to any IP outside the cluster:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}
  egress:
  - {}
  policyTypes:
  - Ingress
  - Egress

An Introduction to Kubernetes Network Policies for Security Professionals
An Introduction to Kubernetes Network Policies for Security Professionals

Combining Multiple Policies

Policies are logically ORed at three levels; Each pod's permissions are set according to the disjunction of all the policies that affect it:

1. In the fields from ΠΈ to three types of elements can be defined (all combined with OR):

  • namespaceSelector - selects the entire namespace;
  • podSelector - selects pods;
  • ipBlock - selects a subnet.

At the same time, the number of elements (even the same ones) in subsections from/to not limited. All of them will be combined with a logical OR.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

2. Inside policy section ingress can have many elements from (combined by logical OR). Similarly, section egress may include many elements to (also combined by disjunction):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
  - from:
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

3. Different policies are also combined with a logical OR

But when they are combined, there is one restriction on which indicated Chris Cooney: Kubernetes can only combine policies with different policyTypes (Ingress or Egress). Policies that define ingress (or egress) will overwrite each other.

Relationship between namespaces

By default, the exchange of information between namespaces is allowed. This can be changed with a restrictive policy that restricts outgoing and/or incoming traffic to the namespace (see "Sweep Rule" above).

By blocking access to a namespace (see "Sweep Rule" above), you can make exceptions to the deny policy by allowing connections from a specific namespace with namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: # <<<
        matchLabels:
          namespace: default
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

As a result, all pods in the namespace default get access to pods postgres in namespace database. But what if you want to open access to postgres only specific pods in the namespace default?

Filter by namespaces AND pods

Kubernetes version 1.11 and above allows you to combine operators namespaceSelector ΠΈ podSelector using logical AND. It looks like this:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          namespace: default
      podSelector: # <<<
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

Why is it interpreted as AND instead of the usual OR?

Note that podSelector does not start with a hyphen. In YAML this means that podSelector and standing in front of him namespaceSelector refer to the same list element. Therefore, they are combined with a logical AND.

Adding a dash before podSelector will result in a new list element that will be combined with the previous one namespaceSelector using logical OR.

To select pods with a specific label in all namespaces, enter empty namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

Multiple labels combine with AND

Firewall rules with multiple entities (hosts, networks, groups) are combined using a logical OR. The following rule will fire if the packet source matches Host_1 OR Host_2:

| Source | Destination | Service | Action |
| ----------------------------------------|
| Host_1 | Subnet_A    | HTTPS   | Allow  |
| Host_2 |             |         |        |
| ----------------------------------------|

On the contrary, in Kubernetes different labels in podSelector or namespaceSelector are combined with a logical AND. For example, the following rule will select pods that have both labels, role=db И version=v2:

podSelector:
  matchLabels:
    role: db
    version: v2

The same logic applies to all types of statements: policy target selectors, pod selectors, and namespace selectors.

Subnets and IP addresses (IPBlocks)

Firewalls use VLANs, IP addresses, and subnets to segment a network.

In Kubernetes, IP addresses are automatically assigned to pods and can change frequently, so labels are used to select pods and namespaces in network policies.

Subnets (ipBlocks) are used when managing incoming (ingress) or outgoing (egress) external (North-South) connections. For example, this policy opens all pods from the namespace default access to Google DNS service:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 8.8.8.8/32
    ports:
    - protocol: UDP
      port: 53

An Introduction to Kubernetes Network Policies for Security Professionals

The empty pod selector in this example means "select all pods in the namespace".

This policy only allows access to 8.8.8.8; access to any other IP is prohibited. So, in essence, you have blocked access to the internal Kubernetes DNS service. If you still want to open it, specify it explicitly.

Usually ipBlocks ΠΈ podSelectors are mutually exclusive, since the internal IP addresses of the pods are not used in ipBlocks. Pointing out internal IP pods, you will actually allow connections to/from pods with those addresses. In practice, you won't know which IP address to use, which is why you shouldn't use them to select pods.

As a counter example, the following policy includes all IPs and therefore allows access to all other pods:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0

An Introduction to Kubernetes Network Policies for Security Professionals

You can open access only to external IPs, excluding the internal IP addresses of the pods. For example, if your pod's subnet is 10.16.0.0/14:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.16.0.0/14

An Introduction to Kubernetes Network Policies for Security Professionals

Ports and protocols

Usually pods listen on one port. This means that you can simply leave out the port numbers in your policies and leave everything as default. However, it is recommended to make policies as restrictive as possible, so in some cases you can still specify ports:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
      - port: 443      # <<<
        protocol: TCP  # <<<
      - port: 80       # <<<
        protocol: TCP  # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

Note that the selector ports applies to all elements in the block to or from, which contains. To specify different ports for different item sets, break ingress or egress into several sub-sections to or from and in each write down your ports:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    ports:             # <<<
     - port: 443       # <<<
       protocol: TCP   # <<<
  - from:
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
     - port: 80        # <<<
       protocol: TCP   # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

An Introduction to Kubernetes Network Policies for Security Professionals

Default ports work:

  • If you omit the definition of ports entirely (ports), which means all protocols and all ports;
  • If you omit the protocol definition (protocol), which means TCP;
  • If you omit the port definition (port), which means all ports.

Best Practice: Don't rely on default values, specify what you need explicitly.

Note that you need to use pod ports, not services (more on this in the next paragraph).

Policies defined for pods or services?

Usually, pods in Kubernetes communicate with each other through a service - a virtual load balancer that redirects traffic to the pods that implement the service. You might think that network policies control access to services, but that's not the case. Kubernetes network policies work with pod ports, not services.

For example, if a service listens on port 80, but redirects traffic to port 8080 of its pods, you must specify 8080 in the network policy.

Such a mechanism should be recognized as suboptimal: if the internal device of the service (the ports of which listen to pods) changes, network policies will have to be updated.

New architectural approach using Service Mesh (for example, see about Istio below - approx. transl.) allows you to deal with this problem.

Is it necessary to write both Ingress and Egress?

The short answer is yes, in order for pod A to communicate with pod B, you need to allow it to create an outgoing connection (for this you need to configure the egress policy), and pod B must be able to accept an incoming connection (for this, accordingly, you need ingress- policy).

However, in practice, you can rely on the default policy to allow connections in one or both directions.

If some pod-source will be selected by one or more egress-politicians, the restrictions imposed on it will be determined by their disjunction. In this case, you will need to explicitly allow the connection to the podaddressee. If a pod is not selected by any policy, its outgoing (egress) traffic is allowed by default.

Similarly, the fate of the pod'a-the addressselected by one or more ingress-policies will be determined by their disjunction. In this case, you must explicitly allow it to receive traffic from the source pod. If a pod is not selected by any policy, all ingress traffic to it is allowed by default.

See "Stateful or Stateless" below.

Logs

Kubernetes network policies do not know how to log traffic. This makes it difficult to determine if a policy is working as expected and makes security analysis very difficult.

Traffic control to external services

Kubernetes network policies do not allow you to specify a fully qualified domain name (DNS) in egress sections. This fact leads to a significant inconvenience when trying to restrict traffic to external destinations that do not have a fixed IP address (such as aws.com).

Policy Check

Firewalls will warn you or even refuse to accept an erroneous policy. Kubernetes does some verification too. When setting a network policy via kubectl, Kubernetes may declare that the policy is incorrect and refuse to accept it. In other cases, Kubernetes will take the policy and fill it in with the missing details. You can see them with the command:

kubernetes get networkpolicy <policy-name> -o yaml

Keep in mind that the Kubernetes validation system is not infallible and may miss some types of errors.

Execution

Kubernetes does not enforce network policies on its own, but is merely an API gateway that places the burden of control on an underlying system called the Container Networking Interface (CNI). Setting policies on a Kubernetes cluster without assigning an appropriate CNI is similar to setting policies on a firewall management server without subsequently setting them on firewalls. It's up to you to make sure you have a decent CNI or, in the case of Kubernetes platforms, hosted in the cloud (For a list of providers see here - approx. trans.), enable network policies that will set the CNI for you.

Note that Kubernetes will not warn you if you set a network policy without the appropriate helper CNI.

Stateful or Stateless?

All Kubernetes CNIs I've come across are stateful (for example, Calico uses Linux conntrack). This allows the pod to receive responses on the TCP connection it initiated without having to re-establish it. However, I am not aware of a Kubernetes standard that would guarantee statefulness.

Advanced Security Policy Management

Here are some ways to improve the efficiency of security policy enforcement in Kubernetes:

  1. The Service Mesh architectural pattern uses sidecars to provide detailed telemetry and traffic control at the service layer. As an example, one can take Istio.
  2. Some of the CNI vendors have extended their tools to go beyond Kubernetes network policies.
  3. Tufin Orca provides transparency and automation of Kubernetes network policies.

The Tufin Orca package manages Kubernetes network policies (and is the source of the screenshots above).

Additional Information

Conclusion

Kubernetes network policies offer a good set of tools for segmenting clusters, but they are not intuitive and have many subtleties. I believe that because of this complexity, the policies of many existing clusters are buggy. Possible solutions to this problem are automating policy definitions or using other segmentation tools.

I hope this guide will help clear up some questions and solve problems you may encounter.

PS from translator

Read also on our blog:

Source: habr.com

Add a comment