From 4b98bf9ff987f31f527e6bfcf094adde8493d52d Mon Sep 17 00:00:00 2001 From: "M. Essam" Date: Tue, 7 Oct 2025 13:59:50 +0300 Subject: [PATCH 1/4] Add feature to add default labels to all resources (#62) Fixes #41 Thanks to @mhartmann-jaconi for the Helm changes in #42 --- cmd/main.go | 22 +++++++++++++++++++ .../templates/_helpers.tpl | 5 +++++ .../templates/deployment.yaml | 7 ++++++ helm/kubernetes-operator/values.yaml | 6 +++++ internal/controller/nbresource_controller.go | 4 ++++ .../controller/nbresource_controller_test.go | 11 ++++++---- .../controller/nbroutingpeer_controller.go | 21 +++++++++++++----- .../nbroutingpeer_controller_test.go | 22 +++++++++++++++++++ internal/controller/service_controller.go | 3 +++ .../controller/service_controller_test.go | 3 +++ 10 files changed, 94 insertions(+), 10 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 5b5d535..cfdc68b 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "path/filepath" + "strings" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -74,6 +75,7 @@ func main() { clusterDNS string netbirdAPIKey string allowAutomaticPolicyCreation bool + defaultLabels string ) flag.StringVar(&managementURL, "netbird-management-url", "https://api.netbird.io", "Management service URL") flag.StringVar(&clientImage, "netbird-client-image", "netbirdio/netbird:latest", "Image for netbird client container") @@ -97,6 +99,12 @@ func main() { false, "Allow creating NBPolicy resources from annotations on Services", ) + flag.StringVar( + &defaultLabels, + "default-labels", + "", + "Default labels used for all resources, in format key=value,key=value", + ) // Controller generic flags var ( @@ -129,6 +137,17 @@ func main() { opts.BindFlags(flag.CommandLine) flag.Parse() + defaultLabelsMap := make(map[string]string) + if defaultLabels != "" { + for _, s := range strings.Split(defaultLabels, ",") { + kv := strings.Split(s, "=") + if len(kv) != 2 { + panic(fmt.Errorf("invalid label format: %s", s)) + } + defaultLabelsMap[kv[0]] = kv[1] + } + } + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) disableHTTP2 := func(c *tls.Config) { @@ -216,6 +235,7 @@ func main() { APIKey: netbirdAPIKey, ManagementURL: managementURL, NamespacedNetworks: namespacedNetworks, + DefaultLabels: defaultLabelsMap, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "NBRoutingPeer") os.Exit(1) @@ -234,6 +254,7 @@ func main() { ClusterDNS: clusterDNS, NamespacedNetworks: namespacedNetworks, ControllerNamespace: controllerNamespace, + DefaultLabels: defaultLabelsMap, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Service") os.Exit(1) @@ -246,6 +267,7 @@ func main() { ManagementURL: managementURL, AllowAutomaticPolicyCreation: allowAutomaticPolicyCreation, ClusterName: clusterName, + DefaultLabels: defaultLabelsMap, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "NBResource") os.Exit(1) diff --git a/helm/kubernetes-operator/templates/_helpers.tpl b/helm/kubernetes-operator/templates/_helpers.tpl index 2c98e59..ebef1ea 100644 --- a/helm/kubernetes-operator/templates/_helpers.tpl +++ b/helm/kubernetes-operator/templates/_helpers.tpl @@ -40,6 +40,11 @@ helm.sh/chart: {{ include "kubernetes-operator.chart" . }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.general.labels }} +{{- range $key, $val := .Values.general.labels }} +{{ $key }}: "{{ $val }}" +{{- end }} +{{- end }} {{- end }} {{/* diff --git a/helm/kubernetes-operator/templates/deployment.yaml b/helm/kubernetes-operator/templates/deployment.yaml index 462f11e..117b3eb 100644 --- a/helm/kubernetes-operator/templates/deployment.yaml +++ b/helm/kubernetes-operator/templates/deployment.yaml @@ -66,6 +66,13 @@ spec: {{- if .Values.routingClientImage }} - --netbird-client-image={{.Values.routingClientImage}} {{- end }} + {{- if .Values.general.labels }} + {{- $list := list }} + {{- range $k, $v := .Values.general.labels }} + {{- $list = append $list (printf "%s=%s" $k $v) }} + {{- end }} + - --default-labels="{{ join ", " $list }}" + {{- end }} ports: - name: webhook-server containerPort: {{ .Values.webhook.service.port }} diff --git a/helm/kubernetes-operator/values.yaml b/helm/kubernetes-operator/values.yaml index 6bcaa17..b02113a 100644 --- a/helm/kubernetes-operator/values.yaml +++ b/helm/kubernetes-operator/values.yaml @@ -198,3 +198,9 @@ netbirdAPI: {} # key: "NB_API_KEY" #routingClientImage: "netbirdio/netbird:latest" + +general: + # General labels, applied to all created K8s resources + labels: {} + # acme_com_managed_by: platform-engineering + # acme_com_owned_by: release-engineering \ No newline at end of file diff --git a/internal/controller/nbresource_controller.go b/internal/controller/nbresource_controller.go index 21e4bbe..9d31586 100644 --- a/internal/controller/nbresource_controller.go +++ b/internal/controller/nbresource_controller.go @@ -31,6 +31,7 @@ type NBResourceReconciler struct { ManagementURL string AllowAutomaticPolicyCreation bool ClusterName string + DefaultLabels map[string]string netbird *netbird.Client } @@ -128,6 +129,7 @@ func (r *NBResourceReconciler) handlePolicyCreate(ctx context.Context, nbResourc 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, @@ -148,6 +150,7 @@ func (r *NBResourceReconciler) handlePolicyCreate(ctx context.Context, nbResourc if nbPolicy.Annotations == nil { nbPolicy.Annotations = make(map[string]string) } + nbPolicy.Labels = r.DefaultLabels nbPolicy.Annotations["netbird.io/generated-by"] = req.NamespacedName.String() nbPolicy.Spec = netbirdiov1.NBPolicySpec{ Name: name, @@ -505,6 +508,7 @@ func (r *NBResourceReconciler) handleGroups(ctx context.Context, req ctrl.Reques }, }, Finalizers: []string{"netbird.io/group-cleanup", "netbird.io/resource-cleanup"}, + Labels: r.DefaultLabels, }, Spec: netbirdiov1.NBGroupSpec{ Name: groupName, diff --git a/internal/controller/nbresource_controller_test.go b/internal/controller/nbresource_controller_test.go index 3a7aa51..98cb115 100644 --- a/internal/controller/nbresource_controller_test.go +++ b/internal/controller/nbresource_controller_test.go @@ -46,10 +46,11 @@ var _ = Describe("NBResource Controller", func() { server = httptest.NewServer(mux) netbirdClient = netbird.New(server.URL, "ABC") controllerReconciler = &NBResourceReconciler{ - Client: k8sClient, - Scheme: k8sClient.Scheme(), - netbird: netbirdClient, - ClusterName: "kubernetes", + Client: k8sClient, + Scheme: k8sClient.Scheme(), + netbird: netbirdClient, + ClusterName: "kubernetes", + DefaultLabels: map[string]string{"dog": "bark"}, } By("creating the custom resource for the Kind NBResource") @@ -125,6 +126,7 @@ var _ = Describe("NBResource Controller", func() { Expect(err).NotTo(HaveOccurred()) nbGroup := &netbirdiov1.NBGroup{} Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "meow"}, nbGroup)).To(Succeed()) + Expect(nbGroup.Labels).To(HaveKeyWithValue("dog", "bark")) nbGroup.Status.GroupID = util.Ptr("test") Expect(k8sClient.Status().Update(ctx, nbGroup)).To(Succeed()) }) @@ -453,6 +455,7 @@ var _ = Describe("NBResource Controller", func() { nbPolicy := &netbirdiov1.NBPolicy{} Expect(k8sClient.Get(ctx, types.NamespacedName{Name: nbresource.Status.PolicyNameMapping[policyGenName]}, nbPolicy)).To(Succeed()) Expect(nbPolicy.Status.ManagedServiceList).To(ContainElement("default/test-resource")) + Expect(nbPolicy.Labels).To(HaveKeyWithValue("dog", "bark")) }) When("Source groups is not defined", func() { diff --git a/internal/controller/nbroutingpeer_controller.go b/internal/controller/nbroutingpeer_controller.go index 24d853f..5c8b697 100644 --- a/internal/controller/nbroutingpeer_controller.go +++ b/internal/controller/nbroutingpeer_controller.go @@ -31,6 +31,7 @@ type NBRoutingPeerReconciler struct { APIKey string ManagementURL string NamespacedNetworks bool + DefaultLabels map[string]string netbird *netbird.Client } @@ -122,6 +123,13 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl return err } + labels := r.DefaultLabels + for k, v := range nbrp.Spec.Labels { + labels[k] = v + } + podLabels := labels + podLabels["app.kubernetes.io/name"] = "netbird-router" + // Create deployment if errors.IsNotFound(err) { var replicas int32 = 3 @@ -141,7 +149,7 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl BlockOwnerDeletion: util.Ptr(true), }, }, - Labels: nbrp.Spec.Labels, + Labels: labels, Annotations: nbrp.Spec.Annotations, }, Spec: appsv1.DeploymentSpec{ @@ -153,9 +161,7 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl }, Template: corev1.PodTemplateSpec{ ObjectMeta: v1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": "netbird-router", - }, + Labels: podLabels, }, Spec: corev1.PodSpec{ NodeSelector: nbrp.Spec.NodeSelector, @@ -217,7 +223,7 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl BlockOwnerDeletion: util.Ptr(true), }, } - updatedDeployment.ObjectMeta.Labels = nbrp.Spec.Labels + updatedDeployment.ObjectMeta.Labels = labels for k, v := range nbrp.Spec.Annotations { updatedDeployment.ObjectMeta.Annotations[k] = nbrp.Spec.Annotations[v] } @@ -233,6 +239,7 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl } updatedDeployment.Spec.Template.Spec.Tolerations = nbrp.Spec.Tolerations updatedDeployment.Spec.Template.Spec.NodeSelector = nbrp.Spec.NodeSelector + updatedDeployment.Spec.Template.ObjectMeta.Labels = podLabels updatedDeployment.Spec.Template.Spec.Volumes = nbrp.Spec.Volumes updatedDeployment.Spec.Template.ObjectMeta.Labels = map[string]string{ "app.kubernetes.io/name": "netbird-router", @@ -378,6 +385,7 @@ func (r *NBRoutingPeerReconciler) handleSetupKey(ctx context.Context, req ctrl.R BlockOwnerDeletion: util.Ptr(true), }, }, + Labels: r.DefaultLabels, }, StringData: map[string]string{ "setupKey": setupKey.Key, @@ -402,7 +410,7 @@ func (r *NBRoutingPeerReconciler) handleSetupKey(ctx context.Context, req ctrl.R return &ctrl.Result{}, err } - if (err != nil && strings.Contains(err.Error(), "not found")) || setupKey.Revoked { + if err != nil || setupKey.Revoked { if setupKey != nil && setupKey.Revoked { err = r.netbird.SetupKeys.Delete(ctx, *nbrp.Status.SetupKeyID) @@ -480,6 +488,7 @@ func (r *NBRoutingPeerReconciler) handleGroup(ctx context.Context, req ctrl.Requ }, }, Finalizers: []string{"netbird.io/group-cleanup", "netbird.io/routing-peer-cleanup"}, + Labels: r.DefaultLabels, }, Spec: netbirdiov1.NBGroupSpec{ Name: networkName, diff --git a/internal/controller/nbroutingpeer_controller_test.go b/internal/controller/nbroutingpeer_controller_test.go index af03663..b5ca41e 100644 --- a/internal/controller/nbroutingpeer_controller_test.go +++ b/internal/controller/nbroutingpeer_controller_test.go @@ -52,6 +52,7 @@ var _ = Describe("NBRoutingPeer Controller", func() { netbird: netbirdClient, ClientImage: "netbirdio/netbird:latest", ClusterName: "kubernetes", + DefaultLabels: make(map[string]string), NamespacedNetworks: false, } @@ -436,6 +437,7 @@ var _ = Describe("NBRoutingPeer Controller", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should create group and requeue to get its ID", func() { + controllerReconciler.DefaultLabels = map[string]string{"dog": "bark"} res, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: typeNamespacedName, }) @@ -445,6 +447,7 @@ var _ = Describe("NBRoutingPeer Controller", func() { group := &netbirdiov1.NBGroup{} Expect(k8sClient.Get(ctx, typeNamespacedName, group)).To(Succeed()) Expect(group.Spec.Name).To(Equal(controllerReconciler.ClusterName)) + Expect(group.Labels).To(HaveKeyWithValue("dog", "bark")) group.Status.GroupID = util.Ptr("test") Expect(k8sClient.Status().Update(ctx, group)).To(Succeed()) @@ -846,6 +849,25 @@ var _ = Describe("NBRoutingPeer Controller", func() { Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(Equal(controllerReconciler.ClientImage)) }) }) + + When("Default labels exist", func() { + It("should add labels to Deployment and Pod metadata", func() { + controllerReconciler.DefaultLabels = map[string]string{ + "cat": "meow", + "dog": "bark", + } + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + + deployment := &appsv1.Deployment{} + Expect(k8sClient.Get(ctx, typeNamespacedName, deployment)).To(Succeed()) + Expect(deployment.Labels).To(HaveKeyWithValue("cat", "meow")) + Expect(deployment.Labels).To(HaveKeyWithValue("dog", "bark")) + }) + }) + When("Deployment is out-of-date", func() { It("should update deployment", func() { _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ diff --git a/internal/controller/service_controller.go b/internal/controller/service_controller.go index d5082ef..dd26e2d 100644 --- a/internal/controller/service_controller.go +++ b/internal/controller/service_controller.go @@ -27,6 +27,7 @@ type ServiceReconciler struct { ClusterDNS string NamespacedNetworks bool ControllerNamespace string + DefaultLabels map[string]string } const ( @@ -138,6 +139,7 @@ func (r *ServiceReconciler) exposeService(ctx context.Context, req ctrl.Request, Name: "router", Namespace: routerNamespace, Finalizers: []string{"netbird.io/cleanup"}, + Labels: r.DefaultLabels, }, Spec: netbirdiov1.NBRoutingPeerSpec{}, } @@ -205,6 +207,7 @@ func (r *ServiceReconciler) reconcileNBResource(nbResource *netbirdiov1.NBResour nbResource.ObjectMeta.Name = req.Name nbResource.ObjectMeta.Namespace = req.Namespace + nbResource.ObjectMeta.Labels = r.DefaultLabels nbResource.Finalizers = []string{"netbird.io/cleanup"} nbResource.Spec.Name = resourceName nbResource.Spec.NetworkID = *routingPeer.Status.NetworkID diff --git a/internal/controller/service_controller_test.go b/internal/controller/service_controller_test.go index 63a7098..6077c30 100644 --- a/internal/controller/service_controller_test.go +++ b/internal/controller/service_controller_test.go @@ -67,6 +67,7 @@ var _ = Describe("Service Controller", func() { NamespacedNetworks: false, ClusterDNS: "svc.cluster.local", ControllerNamespace: "default", + DefaultLabels: map[string]string{"dog": "bark"}, } }) @@ -144,6 +145,7 @@ var _ = Describe("Service Controller", func() { Expect(res.RequeueAfter).NotTo(BeZero()) nbrp := &netbirdiov1.NBRoutingPeer{} Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: typeNamespacedName.Namespace, Name: "router"}, nbrp)).To(Succeed()) + Expect(nbrp.Labels).To(HaveKeyWithValue("dog", "bark")) res, err = controllerReconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: typeNamespacedName, }) @@ -203,6 +205,7 @@ var _ = Describe("Service Controller", func() { Expect(nbResource.Spec.PolicyName).To(BeEmpty()) Expect(nbResource.Spec.TCPPorts).To(BeEmpty()) Expect(nbResource.Spec.UDPPorts).To(BeEmpty()) + Expect(nbResource.Labels).To(HaveKeyWithValue("dog", "bark")) }) }) When("policy is specified", func() { From 408e20f999a69399b9a3f8e6b18297f8907f28de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:03:54 +0100 Subject: [PATCH 2/4] Bump golang.org/x/net from 0.33.0 to 0.38.0 (#75) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.38.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/net&package-manager=go_modules&previous-version=0.33.0&new-version=0.38.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/netbirdio/kubernetes-operator/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index dc1a956..0a7b498 100644 --- a/go.mod +++ b/go.mod @@ -52,12 +52,12 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.38.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.26.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index c071df6..852137d 100644 --- a/go.sum +++ b/go.sum @@ -336,8 +336,8 @@ goauthentik.io/api/v3 v3.2023051.3/go.mod h1:nYECml4jGbp/541hj8GcylKQG1gVBsKppHy golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -348,27 +348,27 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From d8eb7cb513a339adb479bebee900efb2d7f2fcc4 Mon Sep 17 00:00:00 2001 From: "M. Essam" Date: Sun, 23 Nov 2025 12:05:26 +0200 Subject: [PATCH 3/4] Bump Helm appVersion to 0.1.5 (#81) --- helm/kubernetes-operator/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helm/kubernetes-operator/Chart.yaml b/helm/kubernetes-operator/Chart.yaml index 40b2bda..29b99c0 100644 --- a/helm/kubernetes-operator/Chart.yaml +++ b/helm/kubernetes-operator/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: kubernetes-operator description: NetBird Kubernetes Operator type: application -version: 0.1.13 -appVersion: "0.1.4" +version: 0.1.15 +appVersion: "0.1.5" From 6c855c5d4eebb41adf587f687486ad7746435c12 Mon Sep 17 00:00:00 2001 From: Christian De Leon Date: Mon, 24 Nov 2025 12:00:58 -0500 Subject: [PATCH 4/4] Fix: extra-dns-labels not being applied to pods (#82) # Fix: NetBird extra-dns-labels not being applied to pods ## Problem The `netbird.io/extra-dns-labels` annotation was not working when applied to pods. Despite the webhook detecting the annotation and adding it to the NetBird container configuration, the extra DNS labels were not appearing in the NetBird UI or being applied to registered peers. ## Root Cause The pod webhook had two issues: 1. **Invalid setup key argument**: The webhook was passing `--setup-key-file /etc/nbkey` to the NetBird client, but this file path was never created. The setup key was already being passed via the `NB_SETUP_KEY` environment variable, making the file-based approach unnecessary and causing confusion in the client startup. 2. **NetBird CLI flag bug**: The webhook was using the `--extra-dns-labels` command line flag, but NetBird has a known issue ([netbirdio/netbird#4282](https://github.com/netbirdio/netbird/issues/4282)) where this flag is not properly processed. The workaround is to use the `NB_EXTRA_DNS_LABELS` environment variable instead. ## Solution - Removed the `--setup-key-file` argument entirely since the setup key is provided via environment variable - Removed all command line arguments from the NetBird container - Added `NB_EXTRA_DNS_LABELS` environment variable when the `netbird.io/extra-dns-labels` annotation is present - NetBird client now uses only environment variables for configuration, which is more reliable and matches the pattern used by the NBRoutingPeer controller ## Changes **Before:** ```go args := []string{ "--setup-key-file", "/etc/nbkey", "-m", managementURL, } // ... add extra-dns-labels to args ``` **After:** ```go envVars := []corev1.EnvVar{ {Name: "NB_SETUP_KEY", ValueFrom: ...}, {Name: "NB_MANAGEMENT_URL", Value: managementURL}, } // ... conditionally add NB_EXTRA_DNS_LABELS to envVars ``` ## Testing 1. Create a deployment with the `netbird.io/setup-key` and `netbird.io/extra-dns-labels` annotations: ```yaml annotations: netbird.io/setup-key: my-setup-key netbird.io/extra-dns-labels: "my-label,another-label" ``` 2. Verify the environment variable is set: ```bash kubectl get pod -o jsonpath='{.spec.containers[?(@.name=="netbird")].env[*]}' | jq . ``` 3. Check the NetBird UI to confirm the extra DNS labels appear on the registered peer 4. Verify the NetBird container logs show successful registration without errors ## References - NetBird issue: https://github.com/netbirdio/netbird/issues/4282 - Documentation: [Extra DNS Labels](https://docs.netbird.io/how-to/routing-traffic-to-private-networks#extra-dns-labels) --- This fix ensures that the `netbird.io/extra-dns-labels` annotation works as documented and provides a more robust configuration method by using environment variables consistently across all NetBird deployments in the operator. --- internal/webhook/v1/pod_webhook.go | 40 ++++++++++++++---------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/internal/webhook/v1/pod_webhook.go b/internal/webhook/v1/pod_webhook.go index 4d8a0d2..0cb4286 100644 --- a/internal/webhook/v1/pod_webhook.go +++ b/internal/webhook/v1/pod_webhook.go @@ -96,38 +96,36 @@ func (d *PodNetbirdInjector) Default(ctx context.Context, obj runtime.Object) er managementURL = nbSetupKey.Spec.ManagementURL } - // build the base arguments. - args := []string{ - "--setup-key-file", "/etc/nbkey", - "-m", managementURL, + // build environment variables + envVars := []corev1.EnvVar{ + { + Name: "NB_SETUP_KEY", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &nbSetupKey.Spec.SecretKeyRef, + }, + }, + { + Name: "NB_MANAGEMENT_URL", + Value: managementURL, + }, } - // check for extra DNS labels in annotations. + // check for extra DNS labels in annotations and add as environment variable if pod.Annotations != nil { if extra, ok := pod.Annotations["netbird.io/extra-dns-labels"]; ok && extra != "" { podlog.Info("Found extra DNS labels", "extra", extra) - // append extra DNS labels to the CLI args. - args = append(args, "--extra-dns-labels", extra) + envVars = append(envVars, corev1.EnvVar{ + Name: "NB_EXTRA_DNS_LABELS", + Value: extra, + }) } } - // Append the netbird container with the constructed args. + // Append the netbird container with the constructed env vars. pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{ Name: "netbird", Image: d.clientImage, - Args: args, - Env: []corev1.EnvVar{ - { - Name: "NB_SETUP_KEY", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &nbSetupKey.Spec.SecretKeyRef, - }, - }, - { - Name: "NB_MANAGEMENT_URL", - Value: managementURL, - }, - }, + Env: envVars, SecurityContext: &corev1.SecurityContext{ Capabilities: &corev1.Capabilities{ Add: []corev1.Capability{"NET_ADMIN"},