Using Helm dashboard and intents-based access control for pain-free network segmentation
Tags: kubernetes, devops, opensource, cloud
Published: 2023-08-09 11:35:13

Try out [Otterize](https://docs.otterize.com/quick-tutorials/k8s-network-policies) with [Helm Dashboard](https://github.com/komodorio/helm-dashboard)– both are completely open source and super simple to get started with. Use the mapper export feature of Otterize to generate ClientIntents for one of your charts, and get to zero trust in no time.

Helm Dashboard is an open-source project which graphically shows installed Helm charts, revisions and changes to their Kubernetes resources.

The intents operator is an open-source Kubernetes operator which makes it possible to roll out network policies in a Kubernetes cluster, chart by chart, and gradually achieve zero trust or network segmentation.

Modern engineering organizations may want to achieve network segmentation as part of adhering to the OWASP Kubernetes Top 10 recommendations, in particular [K07: Missing Network Segmentation Controls](https://owasp.org/www-project-kubernetes-top-ten/2022/en/src/K07-network-segmentation), where Kubernetes network policies and service meshes are the recommended way to achieve segmentation controls.

Network policies are notoriously hard to manage, requiring you to label all client services and server services, and then create an ingress network policy for each server.

This means that each server’s chart would need to reference labels for services that live in other charts – this can be difficult to achieve and requires coordination across multiple teams, since different charts may be owned by different teams.

For example, here’s a network policy that allows access for multiple services, owned by two teams, team2 and team1, to a server owned by team3. Notice how it refers to pod labels in the `from` and the `podSelector` section.

This network policy would live in the Helm chart for the `ledger` service, owned by team3. The labels for the other two services, which call the `ledger`, would need to be in the other charts that deploy those services. This means that the 3 teams would need to coordinate the deployment of all three services, so that the labels appear on all services first, then the network policy is added. If the network policy is added before all the labels are verified to be there, then whoever is misconfigured will be blocked.

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-access-to-ledger
  namespace: team3
spec:
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              namespace-name: team1
          podSelector:
            matchLabels:
              how-team1-labels-their-pods: transaction-service
        - namespaceSelector:
            matchLabels:
              namespace-name: team2
          podSelector:
            matchLabels:
              how-team2-labels-their-pods: some-other-transaction-service
  podSelector:
    matchLabels:
      how-team3-labels-their-pods: ledger
  policyTypes:
    - Ingress
```

What if you’ve done all that hard work of coordinating the different charts and different teams, and now due to an unrelated problem, you want to roll back the server? This would result in also rolling back the network policy for the server, since that’s part of the same Helm chart, blocking any clients who were allowed by the newer network policy. But you may not want that: the rollback will often happen due to an unrelated reason, such as a bug.

With the intents operator, you can declare a separate resource for each client, and the operator then collects those into a network policy per server. This is more in line with how people manage Helm charts - each client is managed on its own, without affecting other Helm charts.

Instead of the network policy we saw before, where the server declares which clients can access, we’ll now have two ClientIntents resources which declare which servers the clients want to access.

For transaction-service in namespace team1, we will declare we want to access ledger in namespace team3:

```yaml
apiVersion: k8s.otterize.com/v1alpha2
kind: ClientIntents
metadata:
  name: transaction-service-intents
  namespace: team1
spec:
  service:
    name: transaction-service
  calls:
    - name: ledger.team3
```

For some-other-transaction-service in namespace team2, we will also declare we want to access ledger in namespace team3:

```yaml
apiVersion: k8s.otterize.com/v1alpha2
kind: ClientIntents
metadata:
  name: some-other-transaction-service-intents
  namespace: team2
spec:
  service:
    name: transaction-service
  calls:
    - name: ledger.team3
```

Once you apply these ClientIntents, both the client and server pods are labeled, and a network policy is created for the server. The server’s chart did not have to change! How cool is that?

For each client namespace, team1 and team2, the following network policies were created in namespace team3:

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  labels:
    intents.otterize.com/network-policy: ledger-team3-7e16db
  name: access-to-ledger-from-team1
  namespace: team3
spec:
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              intents.otterize.com/namespace-name: team1
        - podSelector:
            matchLabels:
              intents.otterize.com/access-ledger-team3-7e16db: "true"
  podSelector:
    matchLabels:
      intents.otterize.com/server: ledger-team3-7e16db
  policyTypes:
    - Ingress
```

And the client pods, transaction-service and some-other-transaction-service, had this label applied to them automatically:

**intents.otterize.com/access-ledger-team3-7e16db: "true"**

While the server, ledger, had this label applied to it automatically:

**intents.otterize.com/server: ledger-team3-7e16db**

Now that each chart contains only the intended access for the services managed within it, you can diff the chart and track changes over time. If you see that a service is being blocked, you can check its chart and see what’s changed.

In this example, let’s look how we can determine what happened when we see that the **transaction-service** is no longer able to connect to **ledger**. We need only look at **transaction-service**’s chart. Let’s do that using Helm-Dashboard:

![](/assets/images/posts/helm-dashboard/service-deploy-1.png)

Oh noes! It looks like somebody accidentally removed the ledger service from the ClientIntents while adding the telemetry service. Let’s correct it:

![](/assets/images/posts/helm-dashboard/service-deploy-2.png)

With Komodor, you’ll be able to see that a service is unable to call another service, and then see whether its ClientIntents changed – which could be the cause for it being blocked, or if its code has changed and it now requires different access, you could use Otterize to map existing traffic, and autogenerate the new client intents:

~ ❯ otterize mapper export -n team1 -n team2

```yaml
apiVersion: k8s.otterize.com/v1alpha2
kind: ClientIntents
metadata:
  name: some-other-transaction-service
  namespace: team2
spec:
  service:
    name: some-other-transaction-service
  calls:
    - name: ledger.team3
---
apiVersion: k8s.otterize.com/v1alpha2
kind: ClientIntents
metadata:
  name: transaction-service
  namespace: team1
spec:
  service:
    name: transaction-service
  calls:
    - name: ledger.team3
```

Stay tuned for more news from Komodor and Otterize! We have an exciting announcement coming up soon 🤫