diff --git a/Makefile b/Makefile index 374b69d..381ac7e 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ all: build .PHONY: manifests manifests: ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. go tool controller-gen crd paths="./..." output:crd:artifacts:config=helm/kubernetes-operator/crds + go tool crd-ref-docs --log-level error --output-path docs/api-reference.md --renderer markdown --source-path api/v1alpha1 --config docs/.crd-ref-docs.yaml .PHONY: generate generate: ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. diff --git a/README.md b/README.md index 3f280cb..67564be 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,42 @@ # NetBird Kubernetes Operator -For easily provisioning access to Kubernetes resources using NetBird. -https://github.com/user-attachments/assets/5472a499-e63d-4301-a513-ad84cfe5ca7b +The NetBird Kubernetes Operator automates the provisioning of NetBird network access for services running in your cluster. -## Description +## Documentation -This operator easily provides NetBird access on Kubernetes clusters, allowing users to access internal resources directly. +- [Getting Started](/docs/getting-started.md) +- [Usage](/docs/usage.md) +- [API Reference](/docs/api-reference.md) -## Getting Started +## How It Works -### Prerequisites -- (Recommended) helm version 3+ -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. -- (Recommended) Cert Manager. +A `NetworkRouter` registers a NetBird router peer for a given DNS zone in your cluster. - -### Deployment - -1. Add helm repository. -```sh -helm repo add netbirdio https://netbirdio.github.io/kubernetes-operator -``` -2. (Recommended) Install [cert-manager](https://cert-manager.io/docs/installation/#default-static-install) for k8s API to communicate with the NetBird operator. -```sh -kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml -``` -3. Add NetBird API token -```shell -kubectl create namespace netbird -kubectl -n netbird create secret generic netbird-mgmt-api-key --from-literal=NB_API_KEY=$(cat ~/nb-pat.secret) -``` -4. (Recommended) Create a [`values.yaml`](examples/ingress/values.yaml) file, check `helm show values netbirdio/kubernetes-operator` for more info. -5. Install using `helm install --create-namespace -f values.yaml -n netbird netbird-operator netbirdio/kubernetes-operator`. -6. (Recommended) Check pod status using `kubectl get pods -n netbird`. -6. (Optional) Create an [`exposed-nginx.yaml`](examples/ingress/exposed-nginx.yaml) file to create a Nginx service for testing. -7. (Optional) Apply the Nginx service: -```sh -kubectl apply -f exposed-nginx.yaml +```yaml +apiVersion: netbird.io/v1alpha1 +kind: NetworkRouter +metadata: + name: prod + namespace: netbird +spec: + dnsZoneRef: + name: prod.company.internal ``` -> Learn more about the values.yaml options [here](helm/kubernetes-operator/values.yaml) and [Granting controller access to NetBird Management](docs/usage.md#granting-controller-access-to-netbird-management). +A `NetworkResource` then exposes a Kubernetes service through that router to one or more NetBird groups. -### Uninstallation - -> [!IMPORTANT] -> Most operator resources are annotated with finalizers, attempting to delete the namespace will result in hanged deletion. - -1. (If ingress mode is enabled) Remove all instances of `netbird.io/expose` annotation on Services. -2. Run `helm uninstall -n netbird netbird-operator`. -3. Wait for all deletion jobs to finish. - -### Version -We have developed and executed tests against Kubernetes v1.31, but it should work with most recent Kubernetes version. - -Latest operator version: v0.1.1. - -Tested against: -|Distribution|Test status|Kubernetes Version| -|---|---|---| -|Google GKE|Pass|1.31.5| -|AWS EKS|Pass|1.31| -|Azure AKS|Not tested|N/A| -|OpenShift|Not tested|N/A| - -> We would love community feedback to improve the test matrix. Please submit a PR with your test results. - -### Usage - -Check the usage of [usage.md](docs/usage.md) and examples. - -## Contributing - -### Prerequisites - -To be able to develop this project, you need to have the following tools installed: - -- [Git](https://git-scm.com/). -- [Make](https://www.gnu.org/software/make/). -- [Go programming language](https://golang.org/dl/). -- [Docker CE](https://www.docker.com/community-edition). -- [Kubernetes cluster (v1.16+)](https://kubernetes.io/docs/setup/). [KIND](https://github.com/kubernetes-sigs/kind) is recommended. -- [Kubebuilder](https://book.kubebuilder.io/). - -### Running tests - -**Running unit tests** -```sh -make test +```yaml +apiVersion: netbird.io/v1alpha1 +kind: NetworkResource +metadata: + name: nginx + namespace: default +spec: + networkRouterRef: + name: prod + namespace: netbird + serviceRef: + name: nginx + groups: + - name: All ``` - -**Running E2E tests** -```sh -kind create cluster # If not already created, you can check with `kind get clusters` -make test-e2e -``` \ No newline at end of file diff --git a/docs/.crd-ref-docs.yaml b/docs/.crd-ref-docs.yaml new file mode 100644 index 0000000..e00e7c4 --- /dev/null +++ b/docs/.crd-ref-docs.yaml @@ -0,0 +1,5 @@ +processor: + ignoreTypes: + - "(.*)List$" +render: + kubernetesVersion: 1.35 diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 0000000..c88e342 --- /dev/null +++ b/docs/api-reference.md @@ -0,0 +1,413 @@ +# API Reference + +## Packages +- [netbird.io/v1alpha1](#netbirdiov1alpha1) + + +## netbird.io/v1alpha1 + +Package v1alpha1 contains API Schema definitions for the v1alpha1 API group. + +### Resource Types +- [Group](#group) +- [NetworkResource](#networkresource) +- [NetworkRouter](#networkrouter) +- [SetupKey](#setupkey) +- [SidecarProfile](#sidecarprofile) + + + +#### ContainerOverride + + + + + + + +_Appears in:_ +- [SidecarProfileSpec](#sidecarprofilespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `image` _string_ | Image overrides the image used by the client. | | Optional: \{\}
| +| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#envvar-v1-core) array_ | | | Optional: \{\}
| +| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#securitycontext-v1-core)_ | | | Optional: \{\}
| + + +#### CrossNamespaceReference + + + + + + + +_Appears in:_ +- [NetworkResourceSpec](#networkresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name of the referent. | | Required: \{\}
| +| `namespace` _string_ | Namespace of the referent. | | Required: \{\}
| + + +#### DNSZoneReference + + + +DNSZoneReference references a Netbird DNS zone by domain name. + + + +_Appears in:_ +- [NetworkRouterSpec](#networkrouterspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name is the domain name of an existing Netbird DNS zone, e.g. "example.com". | | Required: \{\}
| + + +#### Group + + + +Group is the Schema for the groups API. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `netbird.io/v1alpha1` | | | +| `kind` _string_ | `Group` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | Optional: \{\}
| +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | Optional: \{\}
| +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[GroupSpec](#groupspec)_ | | | Required: \{\}
| +| `status` _[GroupStatus](#groupstatus)_ | | \{ observedGeneration:-1 \} | | + + +#### GroupReference + + + + + + + +_Appears in:_ +- [NetworkResourceSpec](#networkresourcespec) +- [SetupKeySpec](#setupkeyspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name is the name of the group. | | Optional: \{\}
| +| `id` _string_ | ID is the id of the group. | | Optional: \{\}
| +| `localRef` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#localobjectreference-v1-core)_ | LocalReference is a reference to a group in the same namespace. | | Optional: \{\}
| + + +#### GroupSpec + + + +GroupSpec defines the desired state of Group. + + + +_Appears in:_ +- [Group](#group) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name of the group. | | MinLength: 1
| + + +#### GroupStatus + + + +GroupStatus defines the observed state of Group. + + + +_Appears in:_ +- [Group](#group) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | ObservedGeneration is the last reconciled generation. | | Optional: \{\}
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | Conditions holds the conditions for the Group. | | Optional: \{\}
| +| `groupID` _string_ | GroupID is the id of the created group. | | Optional: \{\}
| + + +#### InjectionMode + +_Underlying type:_ _string_ + +InjectionMode defines how the sidecar is injected into the pod. + +_Validation:_ +- Enum: [Sidecar Container] + +_Appears in:_ +- [SidecarProfileSpec](#sidecarprofilespec) + +| Field | Description | +| --- | --- | +| `Sidecar` | InjectionModeSidecar injects the client as a sidecar container.
| +| `Container` | InjectionModeContainer injects the client as a regular container.
| + + +#### NetworkResource + + + +NetworkResource is the Schema for the networkresources API. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `netbird.io/v1alpha1` | | | +| `kind` _string_ | `NetworkResource` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | Optional: \{\}
| +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | Optional: \{\}
| +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[NetworkResourceSpec](#networkresourcespec)_ | | | Required: \{\}
| +| `status` _[NetworkResourceStatus](#networkresourcestatus)_ | | \{ observedGeneration:-1 \} | | + + +#### NetworkResourceSpec + + + +NetworkResourceSpec defines the desired state of NetworkResource. + + + +_Appears in:_ +- [NetworkResource](#networkresource) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `networkRouterRef` _[CrossNamespaceReference](#crossnamespacereference)_ | NetworkRouterRef is a reference to the network and router where the resource will be created. | | | +| `serviceRef` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#localobjectreference-v1-core)_ | ServiceRef is a reference to the service to expose in the Network. | | | +| `groups` _[GroupReference](#groupreference) array_ | Groups are references to groups that the resource will be a part of. | | Optional: \{\}
| + + +#### NetworkResourceStatus + + + +NetworkResourceStatus defines the observed state of NetworkResource. + + + +_Appears in:_ +- [NetworkResource](#networkresource) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | ObservedGeneration is the last reconciled generation. | | Optional: \{\}
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | Conditions holds the conditions for the NetworkResource. | | Optional: \{\}
| +| `networkID` _string_ | NetworkID is the id of the network the resource is created in. | | Optional: \{\}
| +| `resourceID` _string_ | ResourceID is the id of the created resource. | | Optional: \{\}
| +| `dnsZoneID` _string_ | DNSZoneID is the id of the zone the DNS record is created in. | | Optional: \{\}
| +| `dnsRecordID` _string_ | DNSRecordID is the id of the created DNS record. | | Optional: \{\}
| + + +#### NetworkRouter + + + +NetworkRouter is the Schema for the networkrouters API. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `netbird.io/v1alpha1` | | | +| `kind` _string_ | `NetworkRouter` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | Optional: \{\}
| +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | Optional: \{\}
| +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[NetworkRouterSpec](#networkrouterspec)_ | | | Required: \{\}
| +| `status` _[NetworkRouterStatus](#networkrouterstatus)_ | | \{ observedGeneration:-1 \} | | + + +#### NetworkRouterSpec + + + +NetworkRouterSpec defines the desired state of NetworkRouter. + + + +_Appears in:_ +- [NetworkRouter](#networkrouter) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `dnsZoneRef` _[DNSZoneReference](#dnszonereference)_ | DNSZoneRef is a reference to the DNS zone used to create records for resources. | | Required: \{\}
| +| `workloadOverride` _[WorkloadOverride](#workloadoverride)_ | WorkloadOverride contains configuration that will override the default workload. | | Optional: \{\}
| + + +#### NetworkRouterStatus + + + +NetworkRouterStatus defines the observed state of NetworkRouter. + + + +_Appears in:_ +- [NetworkRouter](#networkrouter) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | ObservedGeneration is the last reconciled generation. | | Optional: \{\}
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | Conditions holds the conditions for the NetworkRouter. | | Optional: \{\}
| +| `routingPeerID` _string_ | RoutingPeerID is the id of the created routing peer. | | Optional: \{\}
| +| `networkID` _string_ | NetworkID is the id of the network the routing peer was created in. | | Optional: \{\}
| + + +#### SetupKey + + + +SetupKey is the Schema for the setupkeys API. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `netbird.io/v1alpha1` | | | +| `kind` _string_ | `SetupKey` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | Optional: \{\}
| +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | Optional: \{\}
| +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[SetupKeySpec](#setupkeyspec)_ | | | Required: \{\}
| +| `status` _[SetupKeyStatus](#setupkeystatus)_ | | \{ observedGeneration:-1 \} | | + + +#### SetupKeySpec + + + +SetupKeySpec defines the desired state of SetupKey. + + + +_Appears in:_ +- [SetupKey](#setupkey) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name of the setup key. | | MinLength: 1
| +| `ephemeral` _boolean_ | Ephemeral decides if peers added with the key are ephemeral or not. | | | +| `duration` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#duration-v1-meta)_ | Duration sets how long the setup key is valid for. | | Pattern: `^([0-9]+(\.[0-9]+)?(m\|h))+$`
Type: string
Optional: \{\}
| +| `autoGroups` _[GroupReference](#groupreference) array_ | AutoGroups are groups that will be automatically assigned to peers using setup key. | | Optional: \{\}
| + + +#### SetupKeyStatus + + + +SetupKeyStatus defines the observed state of SetupKey. + + + +_Appears in:_ +- [SetupKey](#setupkey) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `observedGeneration` _integer_ | ObservedGeneration is the last reconciled generation. | | Optional: \{\}
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | Conditions holds the conditions for the SetupKey. | | Optional: \{\}
| +| `setupKeyID` _string_ | SetupKeyID is the id of the created setup key. | | | + + +#### SidecarProfile + + + +SidecarProfile is the Schema for the sidecarprofiles API. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `netbird.io/v1alpha1` | | | +| `kind` _string_ | `SidecarProfile` | | | +| `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | Optional: \{\}
| +| `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | Optional: \{\}
| +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[SidecarProfileSpec](#sidecarprofilespec)_ | | | Required: \{\}
| +| `status` _[SidecarProfileStatus](#sidecarprofilestatus)_ | | \{ \} | | + + +#### SidecarProfileSpec + + + +SidecarProfileSpec defines the desired state of SidecarProfile. + + + +_Appears in:_ +- [SidecarProfile](#sidecarprofile) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `setupKeyRef` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#localobjectreference-v1-core)_ | SetupKeyRef is the reference to the setup key used in the client. | | Required: \{\}
| +| `podSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#labelselector-v1-meta)_ | PodSelector determines which pods the profile should apply to.
An empty slector means the profile will apply to all pods in the namespace. | | Optional: \{\}
| +| `injectionMode` _[InjectionMode](#injectionmode)_ | InjectionMode defines whether the sidecar is injected as a native Kubernetes sidecar container or as a regular container. | Sidecar | Enum: [Sidecar Container]
Optional: \{\}
| +| `extraDNSLabels` _string array_ | ExtraDNSLabels assigns additional DNS names to peers beyond their default hostname. | | Optional: \{\}
| +| `containerOverride` _[ContainerOverride](#containeroverride)_ | | | Optional: \{\}
| + + +#### SidecarProfileStatus + + + +SidecarProfileStatus defines the observed state of SidecarProfile. + + + +_Appears in:_ +- [SidecarProfile](#sidecarprofile) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | Conditions holds the conditions for the SidecarProfile. | | Optional: \{\}
| + + +#### WorkloadOverride + + + + + + + +_Appears in:_ +- [NetworkRouterSpec](#networkrouterspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `labels` _object (keys:string, values:string)_ | Labels that will be added. | | Optional: \{\}
| +| `annotations` _object (keys:string, values:string)_ | Annotations that will be added. | | Optional: \{\}
| +| `replicas` _integer_ | Replicas sets the amount of client replicas. | | Optional: \{\}
| +| `podTemplate` _[PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#podtemplatespec-v1-core)_ | PodTemplate overrides the pod template. | | Schemaless: \{\}
Optional: \{\}
| + + diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..a60fb5e --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,42 @@ +# Getting Started + +## Prerequisites + +- A NetBird [service user access token](https://docs.netbird.io/manage/public-api). +- Access to Kubernetes cluster. +- Kubectl and Helm installed locally. + +## Steps + +Add the Helm repository. + +```sh +helm repo add netbirdio https://netbirdio.github.io/kubernetes-operator +``` + +Install cert-manager, it is recommended so the Kubernetes API can communicate with the operator's admission webhooks. Skip this step if you already have cert-manager installed. + +```sh +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml +``` + +Create the NetBird namespace and API secret. The operator needs a NetBird personal access token to authenticate with the NetBird Management API. + +```sh +kubectl create namespace netbird +kubectl -n netbird create secret generic netbird-mgmt-api-key --from-literal=NB_API_KEY=${ACCESS_TOKEN} +``` + +Install the Netbird operator. + +```sh +helm install netbird-operator netbirdio/kubernetes-operator --create-namespace --namespace netbird +``` + +Verify the installation. All pods should be in a `Running` state before continuing. + +```sh +kubectl get pods -n netbird +``` + +Once the operator is running, see the [usage guide](/docs/usage.md) to start exposing services to your NetBird network. diff --git a/docs/usage.md b/docs/usage.md index 0825194..328dc89 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,210 +1,136 @@ # Usage -## Provision pods with NetBird access using side-cars +## Exposing Services -1. Create a Setup Key in your [NetBird console](https://docs.netbird.io/how-to/register-machines-using-setup-keys#using-setup-keys). -2. Create a Secret object in the namespace where you need to provision NetBird access (secret name and field can be anything). +The operator exposes Kubernetes services to your NetBird network by combining two resources, a `NetworkRouter` and a `NetworkResource`. + +### NetworkRouter + +A `NetworkRouter` creates a network in NetBird and deploys routing peer pods in the cluster. These pods are configured as routing peers for the network, handling traffic between NetBird clients and services running in the cluster. + +Before creating a `NetworkRouter`, you must first create a custom DNS zone in the [NetBird dashboard](https://docs.netbird.io/manage/dns/custom-zones). The DNS zone must exist before the operator can register it. ```yaml -apiVersion: v1 -stringData: - setupkey: "EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE" -kind: Secret +apiVersion: netbird.io/v1alpha1 +kind: NetworkRouter metadata: - name: test -``` -1. Create an NBSetupKey object referring to your secret. -```yaml -apiVersion: netbird.io/v1 -kind: NBSetupKey -metadata: - name: test + name: prod + namespace: netbird spec: - # Optional, overrides management URL for this setupkey only - # defaults to https://api.netbird.io - managementURL: https://netbird.example.com - secretKeyRef: - name: test # Required - key: setupkey # Required -``` -1. Annotate the pods you need to inject NetBird into with `netbird.io/setup-key`. -```yaml -kind: Deployment -... -spec: -... - template: - metadata: - annotations: - netbird.io/setup-key: test # Must match the name of an NBSetupKey object in the same namespace -... - spec: - containers: -... + dnsZoneRef: + name: prod.company.internal ``` -Since v0.27.0, NetBird supports extra DNS labels, which extends the DNS names that you can link to peers by grouping them and load balancing access using DNS round-robin. To enable this feature, add the following annotation to the pod: -```yaml - netbird.io/extra-dns-labels: "label1,label2" -``` -With this setup, all peers with the same extra label would be used in a DNS round-robin fashion. +### NetworkResource -### Init Sidecar Mode +A `NetworkResource` exposes a Kubernetes service in NetBird by creating a matching resource in the routers network. The cluster IP of the service will be used as the resource IP. A record in the routers zone will also be created using the name and namespace of the service. The following example creates an nignx deployment and exposes the service with the record `nginx.default.prod.company.internal`. -By default, the NetBird container is injected as a regular sidecar container. For workloads like Jobs and CronJobs where the pod should terminate after the main container completes, you can use init sidecar mode. This injects NetBird as an init container with `restartPolicy: Always`. - -To enable init sidecar mode, add the following annotation: -```yaml - netbird.io/init-sidecar: "true" -``` - -## Provisioning Networks (Ingress Functionality) - -### Granting controller access to NetBird Management - -> [!IMPORTANT] -> The NetBird Kubernetes operator generates configurations using NetBird API; editing or deleting these configurations in the NetBird console may cause temporary network disconnection until the operator reconciles the configuration. - -1. Create a Service User on your NetBird dashboard (Must be Admin). [Doc](https://docs.netbird.io/how-to/access-netbird-public-api#creating-a-service-user). -2. Create an access token for the Service User (Must be Admin). [Doc](https://docs.netbird.io/how-to/access-netbird-public-api#creating-a-service-user). -3. Add access token to your helm values file under `netbirdAPI.key`. - 1. Alternatively, provision secret in the same namespace as the operator and set the key `NB_API_KEY` to the access token generated. - 2. Set `netbirdAPI.keyFromSecret` to the name of the secret created. -4. Set `ingress.enabled` to `true`. - 1. Optionally, to provision the network immediately, set `ingress.router.enabled` to `true`. - 2. Optionally, to provision 1 network per namespace, set `ingress.namespacedNetworks` to `true`. -5. Run `helm install` or `helm upgrade`. - -Minimum values.yaml example: -```yaml -netbirdAPI: - key: "nbp_XXxxxxxxXXXXxxxxXXXXXxxx" - -ingress: - enabled: true -cluster: - name: kubernetes -``` -> Learn more about the values.yaml options [here](../helm/kubernetes-operator/values.yaml). - -### Exposing Kubernetes API - -1. Ensure Ingress functionality is enabled. -2. Set `ingress.kubernetesAPI.enabled` to true. -3. Set `ingress.kubernetesAPI.groups` to a list of groups to assign to the Network Resource to be created for kubernetes API. -4. Set `ingress.kubernetesAPI.policies` to a list of policy names to connect to the resource (See #managing-policies for more details). -5. Apply Helm changes through `helm upgrade`. -6. Replace the server URL in your kubeconfig file with `https://kubernetes.default.` (by default `https://kubernetes.default.svc.cluster.local`), for example: -```yaml -apiVersion: v1 -clusters: - - cluster: - certificate-authority: /home/user/.minikube/ca.crt - server: https://kubernetes.default.svc.cluster.local - name: minikube -``` - -### Exposing a Service - -> [!IMPORTANT] -> Ingress DNS Resolution requires DNS Wildcard Routing to be enabled and at least one DNS Nameserver configured for clients. - -|Annotation|Description|Default|Valid Values| -|---|---|---|---| -|`netbird.io/expose`| Expose service using NetBird Network Resource ||(`null`, `true`)| -|`netbird.io/groups`| Comma-separated list of group names to assign to Network Resource |`{ClusterName}-{Namespace}-{Service}`|Any comma-separated list of strings.| -|`netbird.io/resource-name`| Network Resource name |`{Namespace}-{Service}`|Any valid network resource name, make sure they're unique!| -|`netbird.io/policy`| Name(s) of NBPolicy to propagate service ports as destination. ||Comma-separated list of names of any NBPolicy resource| -|`netbird.io/policy-ports`| Narrow down exposed ports in a policy. Leave empty for all ports. ||Comma-separated integer list, integers must be between 0-65535| -|`netbird.io/policy-protocol`| Narrow down protocol for use in a policy. Leave empty for all protocols. ||(`tcp`,`udp`)| -|`netbird.io/policy-source-groups`| Specify source groups for auto-generated policies. Required for auto-generating policies||Any comma-separated list of strings.| -|`netbird.io/policy-name`| Specify human-friendly names for auto-generated policies. ||comma-separated list of `policy:friendly-name`, where policy is the name of the kubernetes object.| - -Example service: ```yaml apiVersion: apps/v1 kind: Deployment metadata: - name: nginx-deployment + name: nginx + namespace: default + labels: + app: nginx spec: - replicas: 0 + replicas: 1 selector: matchLabels: app: nginx + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate template: metadata: labels: app: nginx spec: containers: - - name: nginx - image: nginx:latest - ports: - - containerPort: 80 - + - image: nginx + imagePullPolicy: Always + name: nginx --- apiVersion: v1 kind: Service metadata: - name: nginx-service - annotations: - netbird.io/expose: "true" - netbird.io/groups: "groupA,groupB" + name: nginx + namespace: default + labels: + app: nginx spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 selector: app: nginx - ports: - - protocol: TCP - port: 8080 - targetPort: 80 - type: ClusterIP +--- +apiVersion: netbird.io/v1alpha1 +kind: NetworkResource +metadata: + name: nginx + namespace: default +spec: + networkRouterRef: + name: prod + namespace: netbird + serviceRef: + name: nginx + groups: + - name: All ``` -### Notes -* `netbird.io/expose` will interpret any string as a `true` value; the only `false` value is `null`. -* The operator does **not** handle duplicate resource names within the same network, it is up to you to ensure resource names are unique within the same network. -* While the NetBird console will allow group names to contain commas, this is not allowed in `netbird.io/groups` annotation as commas are used as separators. -* If a group already exists on NetBird console with the same name, NetBird Operator will use that group ID instead of creating a new group. -* NetBird Operator will attempt to clean up any resources created, including groups created for resources. - * If a group is used by resources that the operator cannot clean up, the operator will eventually ignore the group in NetBird. - * It's recommended that unique groups be used per NetBird Operator installation to remove any possible conflicts. -* The Operator does not validate service annotations on updates, as this may cause unnecessary overhead on any Service update. -### Managing Policies +Members of the `All` NetBird group can now reach the nginx service at `nginx.default.prod.company.internal` through the NetBird network. -Policies can be either created through the Helm chart or they can be auto-generated from Service annotation definitions. +## Client Sidecar -#### Helm +In certain situations we may want to have a pod act like a peer in the Netbird network instead of exposing it through a routing peer. In these cases a Netbird client container has to be added as a sidecar to the pod. + +Sidecars are appended to pods when created if they match the selector of a sidecar profile. A sidecar profile defines the configuration of the sidecar, like the setup key to be used along with other parameters. An empty selector will match with all pods in the namespace. The sidecar profile needs to be created first before any pod is created. -Simply add policies under `ingress.policies`, for example: -1. Add the following configuration in your `values.yaml` file. ```yaml -ingress: - policies: - default: - name: Kubernetes Default Policy # Required, name of policy in NetBird console - description: Default # Optional - sourceGroups: # Required, name of groups to assign as source in Policy. - - All - ports: # Optional, resources annotated 'netbird.io/policy=default' will append to this. - - 443 - protocols: # Optional, restricts protocols allowed to resources, defaults to ['tcp', 'udp']. - - tcp - - udp - bidirectional: true # Optional, defaults to true +apiVersion: netbird.io/v1alpha1 +kind: SetupKey +metadata: + name: sidecar + namespace: default +spec: + name: sidecar + ephemeral: true +--- +apiVersion: netbird.io/v1alpha1 +kind: SidecarProfile +metadata: + name: test + namespace: default +spec: + setupKeyRef: + name: sidecar + podSelector: + matchLabels: + app: ubuntu ``` -2. Reference policies in Services using `netbird.io/policy=default,otherpolicy,...`, this will add relevant ports and destination groups to policies. -3. (Optional) Limit specific ports in exposed service by adding `netbird.io/policy-ports=443`. -4. (Optional) Limit specific protocol in exposed service by adding `netbird.io/policy-protocol=tcp`. -#### Auto-Generated Policies +When a pod matching the selector is created it will receive a netbird sidecar container. -1. Ensure `ingress.allowAutomaticPolicyCreation` is set to true in the Helm chart and apply. -2. Annotate a service with `netbird.io/policy` with the name of the policy as a kubernetes object, for example `netbird.io/policy: default`. This will create an NBPolicy with the name `default--`. -3. Annotate the same service with `netbird.io/policy-source-groups` with a comma-separated list of group names to allow as a source, for example `netbird.io/policy-source-groups: dev`. -4. (Optional) Annotate the service with `netbird.io/policy-name` for a human-friendly name, for example `netbird.io/policy-name: "default:Default policy for kubernetes cluster"`. +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: ubuntu + namespace: default + labels: + app: ubuntu +spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "infinity"] +``` -#### Notes on Policies -* Each NBPolicy will only create policies in the NetBird console when the information provided is enough to create one. If no services act as a destination or specified services do not conform to the protocol(s) defined, the policy will not be created. -* Each NBPolicy will create one policy in the NetBird console per protocol specified as long as the protocol has destinations; this ensures better-secured policies by separating ports for TCP and UDP. -* Policies currently do not support ICMP protocol, as ICMP is not supported in Kubernetes services, and there are [no current plans to support it](https://discuss.kubernetes.io/t/icmp-support-for-kubernetes-service/21738). -* NetBird currently does not support SCTP protocol. +Once both containers have started the pod should show up like a peer in the Netbird dashboard. diff --git a/examples/ingress/exposed-nginx.yaml b/examples/ingress/exposed-nginx.yaml deleted file mode 100644 index 3e69657..0000000 --- a/examples/ingress/exposed-nginx.yaml +++ /dev/null @@ -1,48 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: nginx - name: nginx - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: nginx - strategy: - rollingUpdate: - maxSurge: 25% - maxUnavailable: 25% - type: RollingUpdate - template: - metadata: - labels: - app: nginx - spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - netbird.io/expose: "true" - netbird.io/policy: default - netbird.io/resource-name: nginx - netbird.io/groups: nginx-k8s-gke - labels: - app: nginx - name: nginx - namespace: default -spec: - ports: - - name: http - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: nginx - type: ClusterIP diff --git a/examples/ingress/values-kubernetes-operator.yaml b/examples/ingress/values-kubernetes-operator.yaml deleted file mode 100644 index 718e19e..0000000 --- a/examples/ingress/values-kubernetes-operator.yaml +++ /dev/null @@ -1,10 +0,0 @@ -#operator: -# image: -# tag: "0.1.0" -ingress: - enabled: true - -netbirdAPI: - keyFromSecret: - name: "netbird-mgmt-api-key" - key: "NB_API_KEY" diff --git a/examples/ingress/values-netbird-operator-config.yaml b/examples/ingress/values-netbird-operator-config.yaml deleted file mode 100644 index 3f948bc..0000000 --- a/examples/ingress/values-netbird-operator-config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -router: - enabled: true -policies: - default: - name: Kubernetes Default Policy - sourceGroups: - - All diff --git a/examples/refactor/networkresource.yaml b/examples/network/networkresource.yaml similarity index 96% rename from examples/refactor/networkresource.yaml rename to examples/network/networkresource.yaml index ec484ae..7db30ca 100644 --- a/examples/refactor/networkresource.yaml +++ b/examples/network/networkresource.yaml @@ -45,11 +45,11 @@ spec: apiVersion: netbird.io/v1alpha1 kind: NetworkResource metadata: - name: test + name: nginx namespace: default spec: networkRouterRef: - name: test + name: prod namespace: netbird serviceRef: name: nginx diff --git a/examples/refactor/networkrouter.yaml b/examples/network/networkrouter.yaml similarity index 69% rename from examples/refactor/networkrouter.yaml rename to examples/network/networkrouter.yaml index cdca337..189d32d 100644 --- a/examples/refactor/networkrouter.yaml +++ b/examples/network/networkrouter.yaml @@ -1,8 +1,8 @@ apiVersion: netbird.io/v1alpha1 kind: NetworkRouter metadata: - name: test + name: prod namespace: netbird spec: dnsZoneRef: - name: cluster.local + name: prod.company.internal diff --git a/examples/refactor/group.yaml b/examples/refactor/group.yaml deleted file mode 100644 index 70c726e..0000000 --- a/examples/refactor/group.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: netbird.io/v1alpha1 -kind: Group -metadata: - name: test - namespace: netbird -spec: - name: test diff --git a/examples/refactor/setup-key.yaml b/examples/refactor/setup-key.yaml deleted file mode 100644 index b881bb2..0000000 --- a/examples/refactor/setup-key.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: netbird.io/v1alpha1 -kind: SetupKey -metadata: - name: test - namespace: default -spec: - name: test - ephemeral: true diff --git a/examples/setup-keys/example.yaml b/examples/setup-keys/example.yaml deleted file mode 100644 index a2a8a8a..0000000 --- a/examples/setup-keys/example.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: test - namespace: default -stringData: - SETUP_KEY: 50445ABC-8901-4050-8047-0A390658A79B # Replace with valid setup key ---- -apiVersion: netbird.io/v1 -kind: NBSetupKey -metadata: - name: test - namespace: default -spec: - secretKeyRef: - name: test - key: SETUP_KEY ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: test - name: test - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: test - strategy: - rollingUpdate: - maxSurge: 25% - maxUnavailable: 25% - type: RollingUpdate - template: - metadata: - labels: - app: test - annotations: - netbird.io/setup-key: test - spec: - containers: - - image: ubuntu - imagePullPolicy: Always - name: ubuntu - command: - - sleep - - inf diff --git a/examples/sidecar/example.yaml b/examples/sidecar/example.yaml deleted file mode 100644 index 2cd0060..0000000 --- a/examples/sidecar/example.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: test - namespace: default -stringData: - SETUP_KEY: 50445ABC-8901-4050-8047-0A390658A79B # Replace with valid setup key ---- -apiVersion: netbird.io/v1 -kind: NBSetupKey -metadata: - name: test - namespace: default -spec: - secretKeyRef: - name: test - key: SETUP_KEY ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: job -spec: - template: - metadata: - annotations: - netbird.io/setup-key: test - netbird.io/init-sidecar: "true" - spec: - containers: - - name: worker - image: curlimages/curl:latest - command: ["sh", "-c", "curl -s https://example.com && echo done && sleep 60"] - restartPolicy: Never - backoffLimit: 3 ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: cronjob -spec: - schedule: "*/30 * * * *" - jobTemplate: - spec: - template: - metadata: - annotations: - netbird.io/setup-key: test - netbird.io/init-sidecar: "true" - spec: - containers: - - name: worker - image: curlimages/curl:latest - command: ["sh", "-c", "curl -s https://example.com && echo done"] - restartPolicy: Never diff --git a/examples/sidecar/pod.yaml b/examples/sidecar/pod.yaml new file mode 100644 index 0000000..7f49380 --- /dev/null +++ b/examples/sidecar/pod.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: ubuntu + namespace: default + labels: + app: ubuntu +spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "infinity"] diff --git a/examples/refactor/sidecarprofile.yaml b/examples/sidecar/sidecarprofile.yaml similarity index 61% rename from examples/refactor/sidecarprofile.yaml rename to examples/sidecar/sidecarprofile.yaml index f56cedb..a76a8a2 100644 --- a/examples/refactor/sidecarprofile.yaml +++ b/examples/sidecar/sidecarprofile.yaml @@ -18,17 +18,3 @@ spec: podSelector: matchLabels: app: ubuntu ---- -apiVersion: v1 -kind: Pod -metadata: - name: ubuntu - namespace: default - labels: - app: ubuntu -spec: - containers: - - name: ubuntu - image: ubuntu:latest - command: ["sleep", "infinity"] - diff --git a/go.mod b/go.mod index 3e5e53f..e54fee3 100644 --- a/go.mod +++ b/go.mod @@ -21,13 +21,17 @@ require ( ) require ( + dario.cat/mergo v1.0.2 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/cockroach-go v2.0.1+incompatible // indirect github.com/coreos/go-oidc v2.5.0+incompatible // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/elastic/crd-ref-docs v0.3.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect @@ -40,16 +44,20 @@ require ( github.com/go-openapi/swag v0.23.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect + github.com/goccy/go-yaml v1.19.2 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -61,7 +69,9 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.19.2 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.4 // indirect + github.com/spf13/cast v1.10.0 // indirect github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -69,6 +79,7 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.49.0 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/net v0.52.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect @@ -91,7 +102,7 @@ require ( k8s.io/code-generator v0.35.2 // indirect k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect sigs.k8s.io/controller-tools v0.20.1 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect @@ -100,4 +111,7 @@ require ( replace github.com/dexidp/dex => github.com/dexidp/dex v2.13.0+incompatible -tool sigs.k8s.io/controller-tools/cmd/controller-gen +tool ( + github.com/elastic/crd-ref-docs + sigs.k8s.io/controller-tools/cmd/controller-gen +) diff --git a/go.sum b/go.sum index 3cccbd0..189b5ab 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIi cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= @@ -16,8 +16,12 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= @@ -109,6 +113,8 @@ github.com/eko/gocache/store/go_cache/v4 v4.2.2 h1:tAI9nl6TLoJyKG1ujF0CS0n/IgTEM github.com/eko/gocache/store/go_cache/v4 v4.2.2/go.mod h1:T9zkHokzr8K9EiC7RfMbDg6HSwaV6rv3UdcNu13SGcA= github.com/eko/gocache/store/redis/v4 v4.2.2 h1:Thw31fzGuH3WzJywsdbMivOmP550D6JS7GDHhvCJPA0= github.com/eko/gocache/store/redis/v4 v4.2.2/go.mod h1:LaTxLKx9TG/YUEybQvPMij++D7PBTIJ4+pzvk0ykz0w= +github.com/elastic/crd-ref-docs v0.3.0 h1:9bGSUkBR56Z7TuDGQAu3KGbBkagwwZ6RkZmS+qvDuDM= +github.com/elastic/crd-ref-docs v0.3.0/go.mod h1:8td3UC8CaO5M+G115O3FRKLmplmX+p0EqLMLGM6uNdk= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= @@ -123,6 +129,8 @@ github.com/fluxcd/pkg/apis/meta v1.26.0 h1:dxP1FfBpTCYso6odzRcltVnnRuBb2VyhhgV0V github.com/fluxcd/pkg/apis/meta v1.26.0/go.mod h1:c7o6mJGLCMvNrfdinGZehkrdZuFT9vZdZNrn66DtVD0= github.com/fluxcd/pkg/runtime v0.104.0 h1:6isoyeCvYTXRozknz87pU/Z1eWdm4Hi+ojZFwcwnaqs= github.com/fluxcd/pkg/runtime v0.104.0/go.mod h1:I7KymH0BM5YUSd68ohjm/RTLXGkw59IXFuu8ISLbLvs= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= @@ -155,8 +163,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= -github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= -github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= +github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= @@ -204,6 +212,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -270,6 +280,10 @@ github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -350,10 +364,14 @@ github.com/russellhaering/goxmldsig v1.6.0/go.mod h1:TrnaquDcYxWXfJrOjeMBTX4mLBe github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.25.8 h1:NnAsw9lN7587WHxjJA9ryDnqhJpFH6A+wagYWTOH970= github.com/shirou/gopsutil/v4 v4.25.8/go.mod h1:q9QdMmfAOVIw7a+eF86P7ISEU6ka+NLgkUxlopV4RwI= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -535,8 +553,8 @@ k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYo k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= -k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY= +k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY= k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=