diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c957fe0..8e81846 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -59,7 +59,9 @@ jobs: cache: false - name: Install helmfmt - run: go install github.com/digitalstudium/helmfmt@latest + # Pinned: @latest is not reproducible and v0.6.1 fails to build + # (undefined: sprigStubNames), which broke this job for every PR. + run: go install github.com/digitalstudium/helmfmt@v0.6.0 - name: Check Helm template formatting run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index ae094b5..8aebd00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## Unreleased +### Changed + +- **netbird**: `server.ingressGrpc.annotations` is now empty by default + instead of carrying four `nginx.ingress.kubernetes.io/*` annotations. + `server.ingressGrpc.className` is configurable, so nginx-specific keys + were applied to Ingresses managed by HAProxy, Traefik, and other + controllers where they are meaningless. The nginx annotations remain in + `values.yaml` as a commented example. Fixes #134. + + **Migration** — if you use ingress-nginx and relied on the defaults, add + them explicitly: + + ```yaml + server: + ingressGrpc: + annotations: + nginx.ingress.kubernetes.io/backend-protocol: "GRPC" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + ``` + + You will not silently lose gRPC: the chart now **fails at template time** + when `ingressGrpc.className` contains `nginx` and the annotations omit + `nginx.ingress.kubernetes.io/backend-protocol`, since ingress-nginx + proxies the backend as HTTP/1.1 without it. Non-nginx controllers are + unaffected and need no annotations. +- **netbird**: Bump appVersion from 0.73.2 to 0.77.1, covering upstream + 0.74.x–0.77.x. Notable additions: Agent Network (a per-account LLM + gateway built on the existing reverse proxy, self-hosted only), a + rewritten desktop client, relay `X-Real-Ip` handling restricted to + configured trusted proxies, and privileged-caller checks for local SSH + daemon settings. No config keys, env vars, ports, or protocols used by + this chart changed, and no manual database migration is required. + See [v0.77.1 release notes](https://github.com/netbirdio/netbird/releases/tag/v0.77.1) + (#116–#132, #135). +- **netbird**: Bump dashboard image from v2.39.0 to v2.91.0 to stay paired + with server 0.77.x. The dashboard's environment contract is unchanged — + every variable the chart sets is still rendered by upstream's own + `dashboard.env` — so no values changes are required. + ## [0.6.0] — 2026-06-23 ### Added diff --git a/charts/keycloak/CHANGELOG.md b/charts/keycloak/CHANGELOG.md index d08f685..e53cb26 100644 --- a/charts/keycloak/CHANGELOG.md +++ b/charts/keycloak/CHANGELOG.md @@ -4,6 +4,36 @@ All notable changes to the Keycloak Helm chart will be documented in this file. ## Unreleased +### Changed + +- Use `KC_BOOTSTRAP_ADMIN_USERNAME` / `KC_BOOTSTRAP_ADMIN_PASSWORD` for the + initial admin instead of `KEYCLOAK_ADMIN` / `KEYCLOAK_ADMIN_PASSWORD`, + which upstream has deprecated and logs a warning for on every start + (`KC-SERVICES0110`). No values change is required — `admin.username` and + `admin.password` are unchanged; only the environment variable names the + chart emits differ. As before, these apply only when bootstrapping a + fresh database. + +### Security + +- Bump Keycloak appVersion from 26.6.3 to 26.7.2 (#115, #120, #129, #133) + - 26.7.2 fixes CVE-2026-59888 / CVE-2026-59889 (jackson-databind) and + 26.7.0 fixes CVE-2026-9796 (admin role rename TOCTOU allowing + realm-wide privilege escalation from `manage-clients`) + - 26.7.2 also fixes an upgrade failure where the stateless cluster + provider captured a null NodeInfo before `postInit` when preview + features were enabled — this is why the chart moves straight to + 26.7.2 rather than 26.7.0 + - No `KC_*` option used by this chart changed. Options removed upstream + in 26.7.0 (persistent-session batching, `token-exchange-external-internal:v2`) + are not used here, and ports, health endpoints, and the container + entrypoint are unchanged + - See upstream release notes for + [26.7.0](https://github.com/keycloak/keycloak/releases/tag/26.7.0) and + [26.7.2](https://github.com/keycloak/keycloak/releases/tag/26.7.2) + +## [26.6.3] — 2026-06-11 + ### Fixed - Set `publishNotReadyAddresses: true` on the JGroups headless service. diff --git a/charts/keycloak/Chart.yaml b/charts/keycloak/Chart.yaml index 8df3528..baeaea5 100644 --- a/charts/keycloak/Chart.yaml +++ b/charts/keycloak/Chart.yaml @@ -3,7 +3,7 @@ name: keycloak description: A Helm chart for deploying Keycloak IAM using the upstream quay.io/keycloak/keycloak image on Kubernetes type: application version: 26.6.3 -appVersion: "26.6.3" +appVersion: "26.7.2" keywords: - keycloak - iam diff --git a/charts/keycloak/README.md b/charts/keycloak/README.md index 204758b..f903a0b 100644 --- a/charts/keycloak/README.md +++ b/charts/keycloak/README.md @@ -233,11 +233,11 @@ This runs `kc.sh build` in an init container and passes `--optimized` to the mai ### Admin Credentials -| Key | Type | Default | Description | -| --------------------------- | ------ | ------------ | ----------------------------------------- | -| `admin.username` | string | `""` | Admin username (maps to `KEYCLOAK_ADMIN`) | -| `admin.password.secretName` | string | `""` | Secret containing the admin password | -| `admin.password.secretKey` | string | `"password"` | Key in the Secret | +| Key | Type | Default | Description | +| --------------------------- | ------ | ------------ | ------------------------------------------------------ | +| `admin.username` | string | `""` | Admin username (maps to `KC_BOOTSTRAP_ADMIN_USERNAME`) | +| `admin.password.secretName` | string | `""` | Secret containing the admin password | +| `admin.password.secretKey` | string | `"password"` | Key in the Secret | ### Observability diff --git a/charts/keycloak/templates/NOTES.txt b/charts/keycloak/templates/NOTES.txt index 2603683..a126aa9 100644 --- a/charts/keycloak/templates/NOTES.txt +++ b/charts/keycloak/templates/NOTES.txt @@ -47,7 +47,7 @@ Admin Credentials: IMPORTANT: The admin user is only created on the first startup of a fresh Keycloak instance. If the database already contains users, the - KEYCLOAK_ADMIN / KEYCLOAK_ADMIN_PASSWORD environment variables are + KC_BOOTSTRAP_ADMIN_USERNAME / KC_BOOTSTRAP_ADMIN_PASSWORD variables are ignored. To reset credentials on an existing instance, use the Keycloak CLI (kcadm.sh) or the Admin REST API. {{- else }} diff --git a/charts/keycloak/templates/_helpers.tpl b/charts/keycloak/templates/_helpers.tpl index b016692..2681191 100644 --- a/charts/keycloak/templates/_helpers.tpl +++ b/charts/keycloak/templates/_helpers.tpl @@ -114,52 +114,52 @@ KC_HEALTH_ENABLED: {{ .Values.healthEnabled | quote }} KC_METRICS_ENABLED: {{ .Values.metrics.enabled | quote }} KC_LOG_LEVEL: {{ .Values.logLevel | quote }} KC_HTTP_ENABLED: {{ .Values.httpEnabled | quote }} -{{- if .Values.hostname }} + {{- if .Values.hostname }} KC_HOSTNAME: {{ .Values.hostname | quote }} -{{- end }} + {{- end }} KC_HOSTNAME_STRICT: {{ .Values.hostnameStrict | quote }} -{{- if .Values.hostnameAdmin }} + {{- if .Values.hostnameAdmin }} KC_HOSTNAME_ADMIN: {{ .Values.hostnameAdmin | quote }} -{{- end }} -{{- if .Values.proxyHeaders }} + {{- end }} + {{- if .Values.proxyHeaders }} KC_PROXY_HEADERS: {{ .Values.proxyHeaders | quote }} -{{- end }} -{{- if .Values.features }} + {{- end }} + {{- if .Values.features }} KC_FEATURES: {{ .Values.features | quote }} -{{- end }} -{{- if .Values.tls.enabled }} + {{- end }} + {{- if .Values.tls.enabled }} KC_HTTPS_CERTIFICATE_FILE: "/opt/keycloak/conf/tls/tls.crt" KC_HTTPS_CERTIFICATE_KEY_FILE: "/opt/keycloak/conf/tls/tls.key" -{{- end }} -{{- if eq (include "keycloak.database.isExternal" .) "true" }} + {{- end }} + {{- if eq (include "keycloak.database.isExternal" .) "true" }} KC_DB: {{ include "keycloak.database.vendor" . | quote }} KC_DB_URL_HOST: {{ .Values.database.host | quote }} KC_DB_URL_PORT: {{ include "keycloak.database.port" . | quote }} KC_DB_URL_DATABASE: {{ .Values.database.name | quote }} KC_DB_USERNAME: {{ .Values.database.user | quote }} - {{- if .Values.database.poolMinSize }} + {{- if .Values.database.poolMinSize }} KC_DB_POOL_MIN_SIZE: {{ .Values.database.poolMinSize | quote }} - {{- end }} - {{- if .Values.database.poolInitialSize }} + {{- end }} + {{- if .Values.database.poolInitialSize }} KC_DB_POOL_INITIAL_SIZE: {{ .Values.database.poolInitialSize | quote }} - {{- end }} - {{- if .Values.database.poolMaxSize }} + {{- end }} + {{- if .Values.database.poolMaxSize }} KC_DB_POOL_MAX_SIZE: {{ .Values.database.poolMaxSize | quote }} - {{- end }} - {{- if .Values.database.sslMode }} - {{- if eq .Values.database.type "postgresql" }} + {{- end }} + {{- if .Values.database.sslMode }} + {{- if eq .Values.database.type "postgresql" }} KC_DB_URL_PROPERTIES: {{ printf "?sslmode=%s" .Values.database.sslMode | quote }} + {{- end }} {{- end }} {{- end }} -{{- end }} -{{- if eq .Values.database.type "dev" }} + {{- if eq .Values.database.type "dev" }} KC_CACHE: "local" -{{- else }} + {{- else }} KC_CACHE: "ispn" KC_CACHE_STACK: {{ .Values.cache.stack | quote }} -{{- if eq .Values.cache.stack "kubernetes" }} + {{- if eq .Values.cache.stack "kubernetes" }} KC_CACHE_CONFIG_FILE: "cache-ispn.xml" JAVA_OPTS_APPEND: {{ printf "-Djgroups.dns.query=%s" (include "keycloak.headlessServiceFQDN" .) | quote }} -{{- end }} -{{- end }} + {{- end }} + {{- end }} {{- end }} diff --git a/charts/keycloak/templates/deployment.yaml b/charts/keycloak/templates/deployment.yaml index 6515413..af0243c 100644 --- a/charts/keycloak/templates/deployment.yaml +++ b/charts/keycloak/templates/deployment.yaml @@ -43,13 +43,13 @@ spec: - configMapRef: name: {{ include "keycloak.fullname" . }}-env env: -{{- if eq (include "keycloak.database.isExternal" .) "true" }} + {{- if eq (include "keycloak.database.isExternal" .) "true" }} - name: KC_DB_PASSWORD valueFrom: secretKeyRef: name: {{ .Values.database.password.secretName }} key: {{ .Values.database.password.secretKey }} -{{- end }} + {{- end }} securityContext: runAsNonRoot: true runAsUser: 1000 @@ -85,9 +85,9 @@ spec: {{- if or $hasAdmin $hasExternalDB .Values.extraEnvVars }} env: {{- if $hasAdmin }} - - name: KEYCLOAK_ADMIN + - name: KC_BOOTSTRAP_ADMIN_USERNAME value: {{ .Values.admin.username | quote }} - - name: KEYCLOAK_ADMIN_PASSWORD + - name: KC_BOOTSTRAP_ADMIN_PASSWORD valueFrom: secretKeyRef: name: {{ .Values.admin.password.secretName }} diff --git a/charts/keycloak/templates/headless-service.yaml b/charts/keycloak/templates/headless-service.yaml index 35e63b7..3390e46 100644 --- a/charts/keycloak/templates/headless-service.yaml +++ b/charts/keycloak/templates/headless-service.yaml @@ -5,10 +5,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.allLabels" . | nindent 4 }} - {{- with .Values.headlessService.annotations }} +{{- with .Values.headlessService.annotations }} annotations: {{- toYaml . | nindent 4 }} - {{- end }} +{{- end }} spec: type: ClusterIP clusterIP: None diff --git a/charts/keycloak/templates/service.yaml b/charts/keycloak/templates/service.yaml index f0b7faf..fe85369 100644 --- a/charts/keycloak/templates/service.yaml +++ b/charts/keycloak/templates/service.yaml @@ -5,10 +5,10 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.allLabels" . | nindent 4 }} - {{- with .Values.service.annotations }} +{{- with .Values.service.annotations }} annotations: {{- toYaml . | nindent 4 }} - {{- end }} +{{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/keycloak/templates/servicemonitor.yaml b/charts/keycloak/templates/servicemonitor.yaml index 42187fb..84e14df 100644 --- a/charts/keycloak/templates/servicemonitor.yaml +++ b/charts/keycloak/templates/servicemonitor.yaml @@ -6,9 +6,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "keycloak.allLabels" . | nindent 4 }} - {{- with .Values.metrics.serviceMonitor.labels }} + {{- with .Values.metrics.serviceMonitor.labels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} spec: selector: matchLabels: @@ -16,10 +16,10 @@ spec: endpoints: - port: management path: /metrics - {{- with .Values.metrics.serviceMonitor.interval }} + {{- with .Values.metrics.serviceMonitor.interval }} interval: {{ . }} - {{- end }} - {{- with .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.scrapeTimeout }} scrapeTimeout: {{ . }} - {{- end }} + {{- end }} {{- end }} diff --git a/charts/keycloak/tests/deployment_test.yaml b/charts/keycloak/tests/deployment_test.yaml index 314d666..d04f99c 100644 --- a/charts/keycloak/tests/deployment_test.yaml +++ b/charts/keycloak/tests/deployment_test.yaml @@ -13,7 +13,7 @@ tests: asserts: - equal: path: spec.template.spec.containers[0].image - value: "quay.io/keycloak/keycloak:26.6.3" + value: "quay.io/keycloak/keycloak:26.7.2" - it: should use custom image tag when set set: @@ -29,7 +29,7 @@ tests: asserts: - equal: path: spec.template.spec.containers[0].image - value: "my-registry/keycloak:26.6.3" + value: "my-registry/keycloak:26.7.2" - it: should set replica count set: @@ -177,12 +177,12 @@ tests: - contains: path: spec.template.spec.containers[0].env content: - name: KEYCLOAK_ADMIN + name: KC_BOOTSTRAP_ADMIN_USERNAME value: "admin" - contains: path: spec.template.spec.containers[0].env content: - name: KEYCLOAK_ADMIN_PASSWORD + name: KC_BOOTSTRAP_ADMIN_PASSWORD valueFrom: secretKeyRef: name: admin-secret @@ -262,7 +262,7 @@ tests: asserts: - equal: path: spec.template.spec.initContainers[0].image - value: "quay.io/keycloak/keycloak:26.6.3" + value: "quay.io/keycloak/keycloak:26.7.2" - it: should set hardened securityContext on build init container set: diff --git a/charts/keycloak/tests/serviceaccount_test.yaml b/charts/keycloak/tests/serviceaccount_test.yaml index 3de3429..18914d9 100644 --- a/charts/keycloak/tests/serviceaccount_test.yaml +++ b/charts/keycloak/tests/serviceaccount_test.yaml @@ -54,4 +54,4 @@ tests: content: helm.sh/chart: keycloak-26.6.3 app.kubernetes.io/managed-by: Helm - app.kubernetes.io/version: "26.6.3" + app.kubernetes.io/version: "26.7.2" diff --git a/charts/keycloak/values.yaml b/charts/keycloak/values.yaml index 4797fda..ba6d9d4 100644 --- a/charts/keycloak/values.yaml +++ b/charts/keycloak/values.yaml @@ -109,7 +109,7 @@ features: "" # ── Admin Credentials ──────────────────────────────────────────────────── admin: - # -- Admin username (maps to KEYCLOAK_ADMIN). Leave empty to skip initial admin creation + # -- Admin username (maps to KC_BOOTSTRAP_ADMIN_USERNAME). Leave empty to skip initial admin creation username: "" # -- Admin password via Kubernetes Secret reference password: diff --git a/charts/netbird/Chart.yaml b/charts/netbird/Chart.yaml index c7c0ace..a1995dc 100644 --- a/charts/netbird/Chart.yaml +++ b/charts/netbird/Chart.yaml @@ -3,7 +3,7 @@ name: netbird description: A Helm chart for deploying NetBird VPN management, signal, dashboard, and relay services on Kubernetes type: application version: 0.6.0 -appVersion: "0.73.2" +appVersion: "0.77.1" keywords: - netbird - vpn diff --git a/charts/netbird/README.md b/charts/netbird/README.md index b5cdb3d..e2a212a 100644 --- a/charts/netbird/README.md +++ b/charts/netbird/README.md @@ -163,14 +163,20 @@ server: hosts: - netbird.example.com # ⚠ ingressGrpc requires TLS. Standard nginx-ingress cannot negotiate - # HTTP/2 cleartext (h2c), and the chart sets - # nginx.ingress.kubernetes.io/ssl-redirect: "true" by default, so - # plaintext gRPC is redirected to HTTPS and fails without a cert. + # HTTP/2 cleartext (h2c), so plaintext gRPC fails without a cert. # Enabling this block with an empty `tls:` is rejected at template time. + # ⚠ Annotations are NOT set by default — they are controller-specific and + # `className` is configurable. ingress-nginx needs the ones below; the + # chart fails fast if className is nginx and backend-protocol is missing. # For plaintext h2c, use server.grpcRoute (Gateway API) instead — see the # "Gateway API as an alternative to Ingress" section below. ingressGrpc: enabled: true + annotations: + nginx.ingress.kubernetes.io/backend-protocol: "GRPC" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" hosts: - host: netbird.example.com paths: @@ -796,23 +802,23 @@ instead — this disables the embedded relay and uses #### Server Ingress -| Key | Type | Default | Description | -| --------------------------------- | ------ | --------------- | ----------------------------------------------------------------------------------------------------------- | -| `server.ingress.enabled` | bool | `false` | Create HTTP ingress (API + OAuth2). Mutually exclusive with `server.httpRoute`. | -| `server.ingress.className` | string | `"nginx"` | Ingress class | -| `server.ingress.annotations` | object | `{}` | Ingress annotations | -| `server.ingress.hosts` | list | `[]` | Ingress host rules | -| `server.ingress.tls` | list | `[]` | TLS configuration | -| `server.ingressGrpc.enabled` | bool | `false` | Create gRPC ingress (Signal + Management). Mutually exclusive with `server.grpcRoute`. | -| `server.ingressGrpc.className` | string | `"nginx"` | Ingress class | -| `server.ingressGrpc.annotations` | object | see values.yaml | GRPC backend annotations | -| `server.ingressGrpc.hosts` | list | `[]` | Ingress host rules | -| `server.ingressGrpc.tls` | list | `[]` | TLS configuration | -| `server.ingressRelay.enabled` | bool | `false` | Create relay/WebSocket ingress. Mutually exclusive with `server.relayHttpRoute` and `server.relayTcpRoute`. | -| `server.ingressRelay.className` | string | `"nginx"` | Ingress class | -| `server.ingressRelay.annotations` | object | `{}` | Ingress annotations | -| `server.ingressRelay.hosts` | list | `[]` | Ingress host rules | -| `server.ingressRelay.tls` | list | `[]` | TLS configuration | +| Key | Type | Default | Description | +| --------------------------------- | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `server.ingress.enabled` | bool | `false` | Create HTTP ingress (API + OAuth2). Mutually exclusive with `server.httpRoute`. | +| `server.ingress.className` | string | `"nginx"` | Ingress class | +| `server.ingress.annotations` | object | `{}` | Ingress annotations | +| `server.ingress.hosts` | list | `[]` | Ingress host rules | +| `server.ingress.tls` | list | `[]` | TLS configuration | +| `server.ingressGrpc.enabled` | bool | `false` | Create gRPC ingress (Signal + Management). Mutually exclusive with `server.grpcRoute`. | +| `server.ingressGrpc.className` | string | `"nginx"` | Ingress class | +| `server.ingressGrpc.annotations` | object | `{}` | Controller-specific annotations. Empty by default; ingress-nginx requires `backend-protocol: GRPC` (enforced at template time). | +| `server.ingressGrpc.hosts` | list | `[]` | Ingress host rules | +| `server.ingressGrpc.tls` | list | `[]` | TLS configuration | +| `server.ingressRelay.enabled` | bool | `false` | Create relay/WebSocket ingress. Mutually exclusive with `server.relayHttpRoute` and `server.relayTcpRoute`. | +| `server.ingressRelay.className` | string | `"nginx"` | Ingress class | +| `server.ingressRelay.annotations` | object | `{}` | Ingress annotations | +| `server.ingressRelay.hosts` | list | `[]` | Ingress host rules | +| `server.ingressRelay.tls` | list | `[]` | TLS configuration | #### Server Gateway API routes @@ -875,7 +881,7 @@ terminated at the referenced Gateway's listeners, not in these values. | ---------------------------- | ------ | ----------------------- | ---------------------------- | | `dashboard.replicaCount` | int | `1` | Number of dashboard replicas | | `dashboard.image.repository` | string | `"netbirdio/dashboard"` | Dashboard image | -| `dashboard.image.tag` | string | `"v2.39.0"` | Dashboard image tag | +| `dashboard.image.tag` | string | `"v2.91.0"` | Dashboard image tag | | `dashboard.image.pullPolicy` | string | `"IfNotPresent"` | Image pull policy | | `dashboard.imagePullSecrets` | list | `[]` | Component-level pull secrets | diff --git a/charts/netbird/templates/_helpers.tpl b/charts/netbird/templates/_helpers.tpl index c8edce6..ae412cb 100644 --- a/charts/netbird/templates/_helpers.tpl +++ b/charts/netbird/templates/_helpers.tpl @@ -120,11 +120,11 @@ Accepts hostnames, IPv4, and bracketed IPv6. Empty exposedAddress passes here to keep `helm template` usable for partial inspection). */}} {{- define "netbird.validate.exposedAddress" -}} -{{- with .Values.server.config.exposedAddress -}} - {{- if not (regexMatch `^https?://(\[[^\]]+\]|[^/:?#]+):[0-9]+([/?#].*)?$` .) -}} - {{- fail (printf "server.config.exposedAddress %q must include an explicit port (e.g. \"https://netbird.example.com:443\"). NetBird clients require the port; without it the daemon fails with \"missing port in address\"." .) -}} + {{- with .Values.server.config.exposedAddress -}} + {{- if not (regexMatch `^https?://(\[[^\]]+\]|[^/:?#]+):[0-9]+([/?#].*)?$` .) -}} + {{- fail (printf "server.config.exposedAddress %q must include an explicit port (e.g. \"https://netbird.example.com:443\"). NetBird clients require the port; without it the daemon fails with \"missing port in address\"." .) -}} + {{- end -}} {{- end -}} -{{- end -}} {{- end }} {{/* @@ -134,31 +134,36 @@ resources would otherwise claim the same paths/hostnames and silently create duplicate or racing rules. */}} {{- define "netbird.validate.routeExclusion" -}} -{{- if and .Values.server.ingress.enabled .Values.server.httpRoute.enabled -}} - {{- fail "server.ingress.enabled and server.httpRoute.enabled are mutually exclusive — pick Kubernetes Ingress or Gateway API HTTPRoute for server HTTP traffic." -}} -{{- end -}} -{{- if and .Values.server.ingressGrpc.enabled .Values.server.grpcRoute.enabled -}} - {{- fail "server.ingressGrpc.enabled and server.grpcRoute.enabled are mutually exclusive — pick Kubernetes Ingress or Gateway API GRPCRoute for server gRPC traffic." -}} -{{- end -}} -{{- if and .Values.server.ingressRelay.enabled (or .Values.server.relayHttpRoute.enabled .Values.server.relayTcpRoute.enabled) -}} - {{- fail "server.ingressRelay.enabled conflicts with server.relayHttpRoute/relayTcpRoute — pick exactly one route type for relay/WebSocket traffic." -}} -{{- end -}} -{{- if and .Values.server.relayHttpRoute.enabled .Values.server.relayTcpRoute.enabled -}} - {{- fail "server.relayHttpRoute.enabled and server.relayTcpRoute.enabled are mutually exclusive — pick HTTPRoute or TCPRoute, not both." -}} -{{- end -}} -{{- if and .Values.dashboard.ingress.enabled .Values.dashboard.httpRoute.enabled -}} - {{- fail "dashboard.ingress.enabled and dashboard.httpRoute.enabled are mutually exclusive — pick Kubernetes Ingress or Gateway API HTTPRoute for the dashboard." -}} -{{- end -}} -{{- range $path := list "server.httpRoute" "server.grpcRoute" "server.relayHttpRoute" "server.relayTcpRoute" "dashboard.httpRoute" -}} - {{- $parts := splitList "." $path -}} - {{- $block := index $.Values (index $parts 0) (index $parts 1) -}} - {{- if and $block.enabled (not $block.parentRefs) -}} - {{- fail (printf "%s.enabled is true but %s.parentRefs is empty — Gateway API routes must reference at least one Gateway." $path $path) -}} + {{- if and .Values.server.ingress.enabled .Values.server.httpRoute.enabled -}} + {{- fail "server.ingress.enabled and server.httpRoute.enabled are mutually exclusive — pick Kubernetes Ingress or Gateway API HTTPRoute for server HTTP traffic." -}} + {{- end -}} + {{- if and .Values.server.ingressGrpc.enabled .Values.server.grpcRoute.enabled -}} + {{- fail "server.ingressGrpc.enabled and server.grpcRoute.enabled are mutually exclusive — pick Kubernetes Ingress or Gateway API GRPCRoute for server gRPC traffic." -}} + {{- end -}} + {{- if and .Values.server.ingressRelay.enabled (or .Values.server.relayHttpRoute.enabled .Values.server.relayTcpRoute.enabled) -}} + {{- fail "server.ingressRelay.enabled conflicts with server.relayHttpRoute/relayTcpRoute — pick exactly one route type for relay/WebSocket traffic." -}} + {{- end -}} + {{- if and .Values.server.relayHttpRoute.enabled .Values.server.relayTcpRoute.enabled -}} + {{- fail "server.relayHttpRoute.enabled and server.relayTcpRoute.enabled are mutually exclusive — pick HTTPRoute or TCPRoute, not both." -}} + {{- end -}} + {{- if and .Values.dashboard.ingress.enabled .Values.dashboard.httpRoute.enabled -}} + {{- fail "dashboard.ingress.enabled and dashboard.httpRoute.enabled are mutually exclusive — pick Kubernetes Ingress or Gateway API HTTPRoute for the dashboard." -}} + {{- end -}} + {{- range $path := list "server.httpRoute" "server.grpcRoute" "server.relayHttpRoute" "server.relayTcpRoute" "dashboard.httpRoute" -}} + {{- $parts := splitList "." $path -}} + {{- $block := index $.Values (index $parts 0) (index $parts 1) -}} + {{- if and $block.enabled (not $block.parentRefs) -}} + {{- fail (printf "%s.enabled is true but %s.parentRefs is empty — Gateway API routes must reference at least one Gateway." $path $path) -}} + {{- end -}} + {{- end -}} + {{- if and .Values.server.ingressGrpc.enabled (not .Values.server.ingressGrpc.tls) -}} + {{- fail "server.ingressGrpc.enabled is true but server.ingressGrpc.tls is empty. gRPC over Kubernetes Ingress requires TLS: standard nginx-ingress cannot negotiate HTTP/2 cleartext (h2c), so plaintext gRPC fails without a cert. Either configure server.ingressGrpc.tls, or disable server.ingressGrpc and expose gRPC via server.grpcRoute (Gateway API) with a controller that supports plaintext h2c." -}} + {{- end -}} + {{- if and .Values.server.ingressGrpc.enabled (contains "nginx" (toString .Values.server.ingressGrpc.className)) -}} + {{- if not (hasKey (.Values.server.ingressGrpc.annotations | default dict) "nginx.ingress.kubernetes.io/backend-protocol") -}} + {{- fail "server.ingressGrpc.className is nginx but server.ingressGrpc.annotations is missing `nginx.ingress.kubernetes.io/backend-protocol`. ingress-nginx proxies the backend as HTTP/1.1 without it, so gRPC fails. These annotations are no longer set by default (they are controller-specific and server.ingressGrpc.className is configurable). Add them to server.ingressGrpc.annotations:\n nginx.ingress.kubernetes.io/backend-protocol: \"GRPC\"\n nginx.ingress.kubernetes.io/ssl-redirect: \"true\"\n nginx.ingress.kubernetes.io/proxy-read-timeout: \"3600\"\n nginx.ingress.kubernetes.io/proxy-send-timeout: \"3600\"\nIf you are not using ingress-nginx, set server.ingressGrpc.className to your controller." -}} + {{- end -}} {{- end -}} -{{- end -}} -{{- if and .Values.server.ingressGrpc.enabled (not .Values.server.ingressGrpc.tls) -}} - {{- fail "server.ingressGrpc.enabled is true but server.ingressGrpc.tls is empty. gRPC over Kubernetes Ingress requires TLS: standard nginx-ingress cannot negotiate HTTP/2 cleartext (h2c) and the default `nginx.ingress.kubernetes.io/ssl-redirect: \"true\"` annotation redirects plaintext gRPC to HTTPS — without a cert, requests fail silently. Either configure server.ingressGrpc.tls, or disable server.ingressGrpc and expose gRPC via server.grpcRoute (Gateway API) with a controller that supports plaintext h2c." -}} -{{- end -}} {{- end }} {{/* diff --git a/charts/netbird/templates/dashboard-httproute.yaml b/charts/netbird/templates/dashboard-httproute.yaml index 4b198f9..d4edbc0 100644 --- a/charts/netbird/templates/dashboard-httproute.yaml +++ b/charts/netbird/templates/dashboard-httproute.yaml @@ -1,13 +1,13 @@ {{- if .Values.dashboard.httpRoute.enabled }} -{{- $serviceName := include "netbird.dashboard.fullname" . }} -{{- $rules := list }} -{{- range .Values.dashboard.httpRoute.rules }} - {{- $rule := deepCopy . }} - {{- if not (hasKey $rule "backendRefs") }} - {{- $_ := set $rule "backendRefs" (list (dict "name" $serviceName "port" 80)) }} + {{- $serviceName := include "netbird.dashboard.fullname" . }} + {{- $rules := list }} + {{- range .Values.dashboard.httpRoute.rules }} + {{- $rule := deepCopy . }} + {{- if not (hasKey $rule "backendRefs") }} + {{- $_ := set $rule "backendRefs" (list (dict "name" $serviceName "port" 80)) }} + {{- end }} + {{- $rules = append $rules $rule }} {{- end }} - {{- $rules = append $rules $rule }} -{{- end }} apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: @@ -15,9 +15,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "netbird.dashboard.labels" . | nindent 4 }} - {{- with .Values.dashboard.httpRoute.labels }} + {{- with .Values.dashboard.httpRoute.labels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} {{- with .Values.dashboard.httpRoute.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/netbird/templates/server-deployment.yaml b/charts/netbird/templates/server-deployment.yaml index ef1745d..9227389 100644 --- a/charts/netbird/templates/server-deployment.yaml +++ b/charts/netbird/templates/server-deployment.yaml @@ -41,7 +41,7 @@ spec: {{- $relayConfigured := gt (len .Values.server.config.relays.addresses) 0 }} {{- $relaySecretName := "" }} {{- if $relayConfigured }} -{{- $relaySecretName = include "netbird.server.resolveSecretName" (dict "ref" .Values.server.secrets.relaySecret "generated" $generated) }} + {{- $relaySecretName = include "netbird.server.resolveSecretName" (dict "ref" .Values.server.secrets.relaySecret "generated" $generated) }} {{- end }} {{- $isExternal := eq (include "netbird.database.isExternal" .) "true" }} {{- $patSidecar := and .Values.pat.enabled (not $isExternal) }} @@ -123,16 +123,16 @@ spec: value: "" {{- end }} {{- if $relayConfigured }} -{{- if $relaySecretName }} + {{- if $relaySecretName }} - name: RELAY_SECRET valueFrom: secretKeyRef: name: {{ $relaySecretName }} key: {{ .Values.server.secrets.relaySecret.secretKey }} -{{- else }} + {{- else }} - name: RELAY_SECRET value: "" -{{- end }} + {{- end }} {{- end }} {{- if $isExternal }} - name: DB_PASSWORD diff --git a/charts/netbird/templates/server-grpc-service.yaml b/charts/netbird/templates/server-grpc-service.yaml index acc0f73..120252d 100644 --- a/charts/netbird/templates/server-grpc-service.yaml +++ b/charts/netbird/templates/server-grpc-service.yaml @@ -17,9 +17,9 @@ spec: port: {{ .Values.server.grpcService.port }} targetPort: http protocol: TCP - {{- with .Values.server.grpcService.appProtocol }} + {{- with .Values.server.grpcService.appProtocol }} appProtocol: {{ . }} - {{- end }} + {{- end }} selector: {{- include "netbird.server.selectorLabels" . | nindent 4 }} {{- end }} diff --git a/charts/netbird/templates/server-grpcroute.yaml b/charts/netbird/templates/server-grpcroute.yaml index 984d8c0..8190e10 100644 --- a/charts/netbird/templates/server-grpcroute.yaml +++ b/charts/netbird/templates/server-grpcroute.yaml @@ -1,17 +1,17 @@ {{- if .Values.server.grpcRoute.enabled }} -{{- $serviceName := include "netbird.server.fullname" . }} -{{- $backendName := $serviceName }} -{{- if .Values.server.grpcService.enabled }} - {{- $backendName = printf "%s-grpc" $serviceName }} -{{- end }} -{{- $rules := list }} -{{- range .Values.server.grpcRoute.rules }} - {{- $rule := deepCopy . }} - {{- if not (hasKey $rule "backendRefs") }} - {{- $_ := set $rule "backendRefs" (list (dict "name" $backendName "port" 80)) }} + {{- $serviceName := include "netbird.server.fullname" . }} + {{- $backendName := $serviceName }} + {{- if .Values.server.grpcService.enabled }} + {{- $backendName = printf "%s-grpc" $serviceName }} + {{- end }} + {{- $rules := list }} + {{- range .Values.server.grpcRoute.rules }} + {{- $rule := deepCopy . }} + {{- if not (hasKey $rule "backendRefs") }} + {{- $_ := set $rule "backendRefs" (list (dict "name" $backendName "port" 80)) }} + {{- end }} + {{- $rules = append $rules $rule }} {{- end }} - {{- $rules = append $rules $rule }} -{{- end }} apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: @@ -19,9 +19,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "netbird.server.labels" . | nindent 4 }} - {{- with .Values.server.grpcRoute.labels }} + {{- with .Values.server.grpcRoute.labels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} {{- with .Values.server.grpcRoute.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/netbird/templates/server-httproute.yaml b/charts/netbird/templates/server-httproute.yaml index 945968d..732f48b 100644 --- a/charts/netbird/templates/server-httproute.yaml +++ b/charts/netbird/templates/server-httproute.yaml @@ -1,13 +1,13 @@ {{- if .Values.server.httpRoute.enabled }} -{{- $serviceName := include "netbird.server.fullname" . }} -{{- $rules := list }} -{{- range .Values.server.httpRoute.rules }} - {{- $rule := deepCopy . }} - {{- if not (hasKey $rule "backendRefs") }} - {{- $_ := set $rule "backendRefs" (list (dict "name" $serviceName "port" 80)) }} + {{- $serviceName := include "netbird.server.fullname" . }} + {{- $rules := list }} + {{- range .Values.server.httpRoute.rules }} + {{- $rule := deepCopy . }} + {{- if not (hasKey $rule "backendRefs") }} + {{- $_ := set $rule "backendRefs" (list (dict "name" $serviceName "port" 80)) }} + {{- end }} + {{- $rules = append $rules $rule }} {{- end }} - {{- $rules = append $rules $rule }} -{{- end }} apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: @@ -15,9 +15,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "netbird.server.labels" . | nindent 4 }} - {{- with .Values.server.httpRoute.labels }} + {{- with .Values.server.httpRoute.labels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} {{- with .Values.server.httpRoute.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/netbird/templates/server-relay-httproute.yaml b/charts/netbird/templates/server-relay-httproute.yaml index bffd239..7f9975e 100644 --- a/charts/netbird/templates/server-relay-httproute.yaml +++ b/charts/netbird/templates/server-relay-httproute.yaml @@ -1,17 +1,17 @@ {{- if .Values.server.relayHttpRoute.enabled }} -{{- $serviceName := include "netbird.server.fullname" . }} -{{- $backendName := $serviceName }} -{{- if .Values.server.relayService.enabled }} - {{- $backendName = printf "%s-relay" $serviceName }} -{{- end }} -{{- $rules := list }} -{{- range .Values.server.relayHttpRoute.rules }} - {{- $rule := deepCopy . }} - {{- if not (hasKey $rule "backendRefs") }} - {{- $_ := set $rule "backendRefs" (list (dict "name" $backendName "port" 80)) }} + {{- $serviceName := include "netbird.server.fullname" . }} + {{- $backendName := $serviceName }} + {{- if .Values.server.relayService.enabled }} + {{- $backendName = printf "%s-relay" $serviceName }} + {{- end }} + {{- $rules := list }} + {{- range .Values.server.relayHttpRoute.rules }} + {{- $rule := deepCopy . }} + {{- if not (hasKey $rule "backendRefs") }} + {{- $_ := set $rule "backendRefs" (list (dict "name" $backendName "port" 80)) }} + {{- end }} + {{- $rules = append $rules $rule }} {{- end }} - {{- $rules = append $rules $rule }} -{{- end }} apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: @@ -19,9 +19,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "netbird.server.labels" . | nindent 4 }} - {{- with .Values.server.relayHttpRoute.labels }} + {{- with .Values.server.relayHttpRoute.labels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} {{- with .Values.server.relayHttpRoute.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/netbird/templates/server-relay-service.yaml b/charts/netbird/templates/server-relay-service.yaml index 77129ec..9ae49fe 100644 --- a/charts/netbird/templates/server-relay-service.yaml +++ b/charts/netbird/templates/server-relay-service.yaml @@ -17,9 +17,9 @@ spec: port: {{ .Values.server.relayService.port }} targetPort: http protocol: TCP - {{- with .Values.server.relayService.appProtocol }} + {{- with .Values.server.relayService.appProtocol }} appProtocol: {{ . }} - {{- end }} + {{- end }} selector: {{- include "netbird.server.selectorLabels" . | nindent 4 }} {{- end }} diff --git a/charts/netbird/templates/server-relay-tcproute.yaml b/charts/netbird/templates/server-relay-tcproute.yaml index 8bff12f..70b8ed0 100644 --- a/charts/netbird/templates/server-relay-tcproute.yaml +++ b/charts/netbird/templates/server-relay-tcproute.yaml @@ -1,16 +1,16 @@ {{- if .Values.server.relayTcpRoute.enabled }} -{{- $serviceName := include "netbird.server.fullname" . }} -{{- $rules := list }} -{{- range .Values.server.relayTcpRoute.rules }} - {{- $rule := deepCopy . }} - {{- if not (hasKey $rule "backendRefs") }} - {{- $_ := set $rule "backendRefs" (list (dict "name" $serviceName "port" 80)) }} + {{- $serviceName := include "netbird.server.fullname" . }} + {{- $rules := list }} + {{- range .Values.server.relayTcpRoute.rules }} + {{- $rule := deepCopy . }} + {{- if not (hasKey $rule "backendRefs") }} + {{- $_ := set $rule "backendRefs" (list (dict "name" $serviceName "port" 80)) }} + {{- end }} + {{- $rules = append $rules $rule }} + {{- end }} + {{- if not $rules }} + {{- $rules = list (dict "backendRefs" (list (dict "name" $serviceName "port" 80))) }} {{- end }} - {{- $rules = append $rules $rule }} -{{- end }} -{{- if not $rules }} - {{- $rules = list (dict "backendRefs" (list (dict "name" $serviceName "port" 80))) }} -{{- end }} apiVersion: gateway.networking.k8s.io/v1alpha2 kind: TCPRoute metadata: @@ -18,9 +18,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "netbird.server.labels" . | nindent 4 }} - {{- with .Values.server.relayTcpRoute.labels }} + {{- with .Values.server.relayTcpRoute.labels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} {{- with .Values.server.relayTcpRoute.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/netbird/templates/server-stun-service.yaml b/charts/netbird/templates/server-stun-service.yaml index feb3af8..df1e66b 100644 --- a/charts/netbird/templates/server-stun-service.yaml +++ b/charts/netbird/templates/server-stun-service.yaml @@ -16,9 +16,9 @@ spec: port: {{ .Values.server.stunService.port }} targetPort: stun protocol: UDP - {{- if and (eq .Values.server.stunService.type "NodePort") (not (kindIs "invalid" .Values.server.stunService.nodePort)) }} +{{- if and (eq .Values.server.stunService.type "NodePort") (not (kindIs "invalid" .Values.server.stunService.nodePort)) }} nodePort: {{ .Values.server.stunService.nodePort }} - {{- end }} +{{- end }} selector: {{- include "netbird.server.selectorLabels" . | nindent 4 }} diff --git a/charts/netbird/tests/dashboard-deployment_test.yaml b/charts/netbird/tests/dashboard-deployment_test.yaml index ba360d0..77c5140 100644 --- a/charts/netbird/tests/dashboard-deployment_test.yaml +++ b/charts/netbird/tests/dashboard-deployment_test.yaml @@ -13,7 +13,7 @@ tests: asserts: - equal: path: spec.template.spec.containers[0].image - value: "netbirdio/dashboard:v2.39.0" + value: "netbirdio/dashboard:v2.91.0" - it: should set replica count set: diff --git a/charts/netbird/tests/server-configmap_test.yaml b/charts/netbird/tests/server-configmap_test.yaml index f574576..f537e09 100644 --- a/charts/netbird/tests/server-configmap_test.yaml +++ b/charts/netbird/tests/server-configmap_test.yaml @@ -441,7 +441,7 @@ tests: - failedTemplate: errorPattern: "server.ingressGrpc.tls is empty" - - it: should accept ingressGrpc when TLS is configured + - it: should accept ingressGrpc when TLS and nginx annotations are configured set: server.ingressGrpc.enabled: true server.ingressGrpc.hosts: @@ -452,6 +452,55 @@ tests: - secretName: netbird-tls hosts: - netbird.example.com + server.ingressGrpc.annotations: + nginx.ingress.kubernetes.io/backend-protocol: "GRPC" + asserts: + - hasDocuments: + count: 1 + + - it: should fail when className is nginx and backend-protocol annotation is missing + set: + server.ingressGrpc.enabled: true + server.ingressGrpc.hosts: + - host: netbird.example.com + paths: + - path: /signalexchange.SignalExchange + server.ingressGrpc.tls: + - secretName: netbird-tls + hosts: + - netbird.example.com + asserts: + - failedTemplate: + errorPattern: "backend-protocol" + + - it: should fail with a clear message when nginx annotations are explicitly null + set: + server.ingressGrpc.enabled: true + server.ingressGrpc.annotations: null + server.ingressGrpc.hosts: + - host: netbird.example.com + paths: + - path: /signalexchange.SignalExchange + server.ingressGrpc.tls: + - secretName: netbird-tls + hosts: + - netbird.example.com + asserts: + - failedTemplate: + errorPattern: "backend-protocol" + + - it: should accept a non-nginx ingressGrpc controller without annotations + set: + server.ingressGrpc.enabled: true + server.ingressGrpc.className: haproxy + server.ingressGrpc.hosts: + - host: netbird.example.com + paths: + - path: /signalexchange.SignalExchange + server.ingressGrpc.tls: + - secretName: netbird-tls + hosts: + - netbird.example.com asserts: - hasDocuments: count: 1 diff --git a/charts/netbird/tests/server-deployment_test.yaml b/charts/netbird/tests/server-deployment_test.yaml index 8caf00f..795c0f1 100644 --- a/charts/netbird/tests/server-deployment_test.yaml +++ b/charts/netbird/tests/server-deployment_test.yaml @@ -13,7 +13,7 @@ tests: asserts: - equal: path: spec.template.spec.containers[0].image - value: "netbirdio/netbird-server:0.73.2" + value: "netbirdio/netbird-server:0.77.1" - it: should use custom image tag when set set: diff --git a/charts/netbird/tests/server-grpc-ingress_test.yaml b/charts/netbird/tests/server-grpc-ingress_test.yaml index b94392c..13b918c 100644 --- a/charts/netbird/tests/server-grpc-ingress_test.yaml +++ b/charts/netbird/tests/server-grpc-ingress_test.yaml @@ -21,13 +21,29 @@ tests: - isKind: of: Ingress - - it: should include default gRPC annotations + - it: should not set controller-specific annotations by default set: server.ingressGrpc.enabled: true server.ingressGrpc.hosts: - host: netbird.example.com paths: - path: /signalexchange.SignalExchange + asserts: + - notExists: + path: metadata.annotations + + - it: should render user-supplied nginx annotations verbatim + set: + server.ingressGrpc.enabled: true + server.ingressGrpc.hosts: + - host: netbird.example.com + paths: + - path: /signalexchange.SignalExchange + server.ingressGrpc.annotations: + nginx.ingress.kubernetes.io/backend-protocol: "GRPC" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" asserts: - isSubset: path: metadata.annotations @@ -37,6 +53,24 @@ tests: nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + - it: should render annotations for a non-nginx controller + set: + server.ingressGrpc.enabled: true + server.ingressGrpc.className: haproxy + server.ingressGrpc.hosts: + - host: netbird.example.com + paths: + - path: /signalexchange.SignalExchange + server.ingressGrpc.annotations: + haproxy.org/server-proto: "h2" + asserts: + - equal: + path: metadata.annotations["haproxy.org/server-proto"] + value: "h2" + - equal: + path: spec.ingressClassName + value: haproxy + - it: should have -grpc suffix in name set: server.ingressGrpc.enabled: true diff --git a/charts/netbird/tests/serviceaccount_test.yaml b/charts/netbird/tests/serviceaccount_test.yaml index 40b4ae2..fc7363b 100644 --- a/charts/netbird/tests/serviceaccount_test.yaml +++ b/charts/netbird/tests/serviceaccount_test.yaml @@ -64,4 +64,4 @@ tests: content: helm.sh/chart: netbird-0.6.0 app.kubernetes.io/managed-by: Helm - app.kubernetes.io/version: "0.73.2" + app.kubernetes.io/version: "0.77.1" diff --git a/charts/netbird/values.yaml b/charts/netbird/values.yaml index 333f011..f7e1dba 100644 --- a/charts/netbird/values.yaml +++ b/charts/netbird/values.yaml @@ -495,11 +495,23 @@ server: ingressGrpc: enabled: false className: "nginx" - annotations: - nginx.ingress.kubernetes.io/backend-protocol: "GRPC" - nginx.ingress.kubernetes.io/ssl-redirect: "true" - nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" - nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + # -- Annotations are controller-agnostic (empty by default) because + # className is configurable — nginx-specific keys would be meaningless on + # HAProxy, Traefik, or any other controller. Supply the annotations your + # controller needs to carry gRPC (HTTP/2) to the backend. + # + # For ingress-nginx, these are required — without backend-protocol: GRPC + # the controller proxies gRPC as HTTP/1.1 and requests fail: + # + # annotations: + # nginx.ingress.kubernetes.io/backend-protocol: "GRPC" + # nginx.ingress.kubernetes.io/ssl-redirect: "true" + # nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + # nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + # + # The chart fails fast when className is nginx and backend-protocol is + # missing, so this cannot silently break a gRPC ingress. + annotations: {} hosts: [] tls: [] @@ -651,7 +663,7 @@ dashboard: image: repository: netbirdio/dashboard - tag: "v2.39.0" + tag: "v2.91.0" pullPolicy: IfNotPresent imagePullSecrets: []