Secure egress access with DNS Policy and NetworkSets

One of the common concerns about migrating applications to Kubernetes is the control over the network traffic egressing your environment. Due to its highly dynamic architecture, Kubernetes will not tie a specific IP address to an application by default. Instead, it will lease a different IP address from an IP pool whenever the application restarts.

Suppose you use traditional network security appliances like firewalls to provide network perimeter protection. In this case, enforcing the least privilege principle by allowing only a specific application to egress traffic outside your network is impossible. In a firewall configuration, you must specify the application IP address when creating the egress rule. As it is impossible to determine the application IP address, you must allow access to the nodes’ IP addresses if you are using overlay, or to the entire IP range you use in the IP pool. By doing this, you will also allow access to any application running on that Kubernetes cluster.

Learn more: Kubernetes Network Policy: Code Example and Best Practices

A better option would be to use Kubernetes network policies, which enable you to create rules to allow ingress and egress traffic to a workload based on the labels applied to it. This approach works better than allowing a whole IP address range on the firewall. However, there are cases where the access you need to authorize is not to a fixed IP address. Instead, it is to a service addressed by a domain name, which is very common for API endpoints. In this case, the native Kubernetes network policies cannot help as there is no way to specify an URL address as a parameter in the allow rule; for this, Calico Cloud comes to the rescue. Let’s learn more about creating network security policies to control access based on domain names and all the options to address this issue adequately with Calico Cloud.

Learn more about Kubernetes networking: Container Networking: What You Should Know

Using DNS Policy and Networksets

Calico security policy restricts the utilization of domain names to solely egress’ allow rules. When employing Calico Cloud, connections are permitted to IP addresses obtained from DNS lookups that are exclusively directed to trusted DNS servers. The accepted DNS record types include A, AAAA, and CNAME records. It is essential for the domain name to match exactly—google.com and www.google.com are considered separate entities. Wildcards can be used to match one or more path components at that position. For example,

*.google.com matches www.google.com and www.ipv6.google.com, but not google.com

Let’s see how it works with a real example.

A local application needs to perform API calls to a third-party application that provides information about the weather forecast for a specific location. This third-party application can be accessed by the URL https://api.weather.com/endpoint.

There are multiple ways to indicate permissible domain names within security policies. You have the option to directly specify domain names in either a GlobalNetworkPolicy or a namespaced NetworkPolicy. Alternatively, you can define domain names within a GlobalNetworkSet and refer to this set in a GlobalNetworkPolicy, or with a NetworkSet and refer to this set in a NetworkPolicy.

Using domain names in GlobalNetworkPolicy and NetworkPolicy

There are two approaches to this method: Using GlobalNetworkPolicy or NetworkPolicy.

The first approach involves creating a GlobalNetworkPolicy that includes egress rules with the action set to Allow. In the rules, you define the domain names to which outbound traffic is permitted by utilizing the destination.domains field.

Here is an example to illustrate this method:

The YAML would look like this:

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: default.allow-egress-to-domain
spec:
  tier: default
  selector: app == "weather-app"
  egress:
    - action: Allow
      protocol: UDP
      source: {}
      destination:
        ports:
          - '53'
    - action: Allow
      source: {}
      destination:
        domains:
          - api.weather.com
  types:
    - Egress
  • The first rule authorizes DNS traffic
  • The second rule allows connections from any workload in any namespace in the cluster (with labels matching the selector) to the domain api.weather.com.

In the second approach, you would generate a NetworkPolicy that incorporates egress rules with the action set to Allow. In these rules, you define the domain names to which outbound traffic is permitted by utilizing the destination.domains field.

Consider the following example:

The YAML would look like this:

apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: default.allow-egress-to-domain
  namespace: default
spec:
  tier: default
  egress:
    - action: Allow
      protocol: UDP
      source: {}
      destination:
        ports:
          - '53'
    - action: Allow
      source: {}
      destination:
        domains:
          - api.weather.com
  types:
    - Egress
  • The initial rule grants permission for DNS traffic
  • The following rule permits connections from any workload in a specific namespace in the cluster (matching the selector) to the domain api.weather.com.

In contrast to the GlobalNetworkPolicy example, the distinction here lies in the fact that the namespaced NetworkPolicy can exclusively provide egress access, limited to the specified domains, for workload endpoints within the default namespace.

Using GlobalNetworkSets and NetworkSets

When you require the same set of domains to be referenced in multiple policies or desire a combination of domains, IPs from workload endpoints and host endpoints as allowed destinations, utilizing a GlobalNetworkSets is recommended as best practice. By utilizing a single destination selector within a GlobalNetworkSets, you have the potential to match all of these resources efficiently.

To implement this method, follow these steps:

1. Create a GlobalNetworkSet: Generate a GlobalNetworkSet and specify the allowed destination domain names in the allowedEgressDomains field. This set will include the desired domain names.

2. Create a GlobalNetworkPolicy: Create a GlobalNetworkPolicy and set the destination.selector to match the GlobalNetworkSet created in the previous step. This ensures that the policy will be applied to the endpoints that match the domains specified in the GlobalNetworkSet.

The YAML would look like this:

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: default.allow-egress-to-domain
spec:
  tier: default
  selector: app == "weather-app"
  egress:
    - action: Allow
      source: {}
      destination:
        selector: color == "red"
    - Egress

By using this approach, you establish a GlobalNetworkSet with the allowed destination domain name and then reference this set by setting the appropriate destination.selector in the GlobalNetworkPolicy. This ensures that the policy is applied to the relevant endpoints matching the specified domains in the GlobalNetworkSet.

And finally, you can refer to domain names in a NetworkSet and use a NetworkPolicy.

To utilize domain names in a NetworkSet, you can follow this method:

1. Create a NetworkSet: Generate a NetworkSet and specify the allowed destination domain names in the allowedEgressDomains field. This set will include the desired domain names.

2. Create a NetworkPolicy: Create a NetworkPolicy and set the destination.selector to match the NetworkSet created in the previous step. This ensures that the policy will be applied to the endpoints that match the domains specified in the NetworkSet.

The YAML would look like this:

apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: default.allow-egress-to-domain
  namespace: default
spec:
  tier: default
  selector: app == "weather-app"
  serviceAccountSelector: ''
  egress:
    - action: Allow
      source: {}
      destination:
        selector: color == "yellow"
  types:
    - Egress

By following this approach, you can effectively utilize domain names in a NetworkSet and create NetworkPolicies that align with the specified domains in the set.

Conclusion

There are several methods for incorporating domain names in network policies when using Calico Cloud. You can restrict domain name usage to egress’ allow rules. You can directly specify allowed domain names within a GlobalNetworkPolicy or a namespaced NetworkPolicy. Alternatively, you can leverage GlobalNetworkSets to define domain names and reference them in GlobalNetworkPolicies. Similarly, you can use NetworkSets in Calico NetworkPolicies to specify allowed destination domain names. By employing these methods, you can effectively control egress traffic and define policies based on domain names, allowing or restricting connections to specific domains or subdomains.

Want to learn more? Get started with a free Calico Cloud trial.

Join our mailing list

Get updates on blog posts, workshops, certification programs, new releases, and more!

X