Skip to content

Auto-generated Policies Hardcoded to Bidirectional #71

@TonyBostonTB

Description

@TonyBostonTB

Summary

When using the Netbird Kubernetes operator's automatic policy creation feature (via allowAutomaticPolicyCreation: true and service annotations), all auto-generated policies are hardcoded to Bidirectional: true, ignoring any bidirectional settings from predefined policy bases in the Helm values.

Expected Behavior

When a predefined policy is configured with bidirectional: false in the Helm values, and a service references this policy via the netbird.io/policy annotation, the auto-generated policy should inherit the bidirectional setting from the predefined policy base.

Actual Behavior

The auto-generated policy always has Bidirectional: true, regardless of the predefined policy configuration.

Root Cause

In internal/controller/nbresource_controller.go, the handlePolicyCreate function hardcodes Bidirectional: true when creating auto-generated NBPolicy resources:

File: internal/controller/nbresource_controller.go
Lines: 145-158

func (r *NBResourceReconciler) handlePolicyCreate(ctx context.Context, nbResource *netbirdiov1.NBResource, req ctrl.Request, policy string, nbPolicy *netbirdiov1.NBPolicy, logger logr.Logger) error {
    // ... validation code ...

    *nbPolicy = netbirdiov1.NBPolicy{
        ObjectMeta: v1.ObjectMeta{
            Name:        generatedName,
            Annotations: map[string]string{"netbird.io/generated-by": req.NamespacedName.String()},
            Finalizers:  []string{"netbird.io/cleanup"},
            Labels:      r.DefaultLabels,
        },
        Spec: netbirdiov1.NBPolicySpec{
            Name:          name,
            Description:   "Generated by " + req.NamespacedName.String(),
            SourceGroups:  nbResource.Spec.PolicySourceGroups,
            Bidirectional: true,  // <-- HARDCODED TO TRUE
        },
    }
    // ...
}

Reproduction Steps

  1. Configure predefined policy in Helm values:
ingress:
  enabled: true
  allowAutomaticPolicyCreation: true
  policies:
    longhorn-ui:
      name: 'Longhorn UI Access'
      description: 'Team DevOps access to Longhorn UI'
      sourceGroups: ['team-devops']
      bidirectional: false  # <-- This setting is ignored
  1. Annotate a Kubernetes service:
service:
  ui:
    annotations:
      netbird.io/expose: 'true'
      netbird.io/groups: 'service-longhorn-ui'
      netbird.io/policy: 'longhorn-ui'
      netbird.io/policy-source-groups: 'team-devops'
      netbird.io/policy-ports: '80'
      netbird.io/policy-protocol: 'tcp'
  1. Apply the configuration

  2. Check the created NBPolicy:

kubectl get nbpolicies.netbird.io longhorn-ui-longhorn-system-longhorn-frontend -o yaml

Result:
The auto-generated policy shows bidirectional: true instead of inheriting bidirectional: false from the predefined policy.

Impact

This creates a security concern as it allows bidirectional traffic when only unidirectional access is desired (e.g., team-devops → service, but not service → team-devops).

In our use case, we want to expose internal services (like Longhorn UI) to DevOps teams via Netbird, but we don't want those services to be able to initiate connections back to team members' machines.

Observed Behavior

Two policies get created:

  1. Predefined policy longhorn-ui: Has bidirectional: false
  2. Auto-generated policy longhorn-ui-longhorn-system-longhorn-frontend: Has bidirectional: true

The NBResource status shows:

status:
  policyName: longhorn-ui
  policyNameMapping:
    longhorn-ui: longhorn-ui-longhorn-system-longhorn-frontend

The service uses the auto-generated bidirectional policy, not the predefined unidirectional one.

Suggested Fix

  1. Look up the predefined policy configuration when creating auto-generated policies
  2. Inherit the bidirectional setting from the predefined policy base
  3. If no predefined policy exists, fall back to a configurable default (or keep current behavior of true)

Example implementation approach:

bidirectional := true  // default
if predefPolicy := r.lookupPredefinedPolicy(policy); predefPolicy != nil {
    bidirectional = predefPolicy.Bidirectional
}

*nbPolicy = netbirdiov1.NBPolicy{
    // ...
    Spec: netbirdiov1.NBPolicySpec{
        // ...
        Bidirectional: bidirectional,
    },
}

Workaround

Disable allowAutomaticPolicyCreation and manually create NBPolicy resources with the correct bidirectional setting.

Environment

  • Kubernetes Operator Version: v0.1.1 (latest)
  • Kubernetes Version: 1.27
  • Helm Chart: netbirdio/kubernetes-operator

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions