Skip to content

Commit 356e51a

Browse files
committed
feat(chart): opt in to shared control plane and CAS client endpoints
Add useSharedEndpoints, an opt-in chart flag that defaults to false, consistent with the chainloop-ee chart. Enabling it moves the control plane CAS connection to the shared CAS Service and the CLI addresses in the installation notes to the shared ingress hostnames. Legacy serviceAPI and ingressAPI settings remain functional and are marked deprecated. Document the single-port endpoints, available since v1.126.0 (chart 1.469.0), and the migration in the chart README. Assisted-by: Claude Code Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev> Chainloop-Trace-Sessions: d94c7fb6-8aa3-404c-aad0-7496f9dea754
1 parent fa944d6 commit 356e51a

6 files changed

Lines changed: 97 additions & 39 deletions

File tree

‎deployment/chainloop/Chart.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ description: Chainloop is an open source software supply chain control plane, a
77

88
type: application
99
# Bump the patch (not minor, not major) version on each change in the Chart Source code
10-
version: 1.481.0
10+
version: 1.481.1
1111
# Do not update appVersion, this is handled automatically by the release process
1212
appVersion: v1.131.0
1313

‎deployment/chainloop/README.md‎

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ or as shown before, provide them as imperative inputs during Helm Install/Upgrad
241241

242242
### Enable a custom domain with TLS
243243

244+
Since Chainloop v1.126.0 (chart version 1.469.0), the control plane and the Artifact CAS each serve native gRPC and HTTP on one port, exposed through the shared ingress (`controlplane.ingress` and `cas.ingress`). The separate gRPC-only endpoints (`serviceAPI` and `ingressAPI`) are deprecated but remain available. See [Opt in to shared client endpoints](#opt-in-to-shared-client-endpoints).
245+
244246
The control plane ingress serves HTTP, gRPC-Web, and native gRPC on the same hostname.
245247
Its HTTP server routes each request, so these protocols can share an upstream HTTP/2 connection.
246248
The existing gRPC ingress stays available. Existing clients can keep their current endpoints.
@@ -263,7 +265,7 @@ cas:
263265

264266
With `tls: true`, configure a certificate source — the cert-manager issuer annotation above, or a pre-created Secret named `cas.example.com-tls` — so the rendered Ingress references a Secret that exists.
265267

266-
`cas.ingress.enabled` defaults to `false`, so a setup that only copies the documented `cas.ingressAPI` block leaves the shared hostname disabled. Retain `cas.ingressAPI` only while the legacy gRPC endpoint is also required. `cas.serviceAPI`, and the control plane's connection to the legacy CAS endpoint keep their existing settings. CAS adds no gRPC-Web or Connect support. Deployed-controller qualification and the full streaming-performance evidence still need work. See the [experiment instructions](../../app/artifact-cas/README.md#shared-endpoint).
268+
`cas.ingress.enabled` defaults to `false`, so a setup that only copies the documented `cas.ingressAPI` block leaves the shared hostname disabled. Retain `cas.ingressAPI` only while the legacy gRPC endpoint is also required. `cas.serviceAPI` keeps its existing settings. The control plane connects to the legacy CAS endpoint unless `useSharedEndpoints` is enabled. CAS adds no gRPC-Web or Connect support. Deployed-controller qualification and the full streaming-performance evidence still need work. See the [experiment instructions](../../app/artifact-cas/README.md#shared-endpoint).
267269

268270
The chart configures HTTP/2 upstream traffic for these controllers:
269271

@@ -299,72 +301,74 @@ The NGINX gRPC module path supports the shared endpoint without path or content-
299301
The regression suite checks that path with NGINX Open Source. It does not certify every controller or NGINX Plus release.
300302
See the [F5 annotation reference](https://docs.nginx.com/nginx-ingress-controller/configuration/ingress-resources/advanced-configuration-with-annotations/) for controller requirements.
301303

302-
Enable the shared control plane ingress and the existing gRPC ingresses as needed.
303-
304304
See below an example of a `values.yaml` override
305305

306306
```yaml
307+
useSharedEndpoints: true
308+
307309
controlplane:
308310
ingress:
309311
enabled: true
310312
hostname: cp.chainloop.dev
311313
312-
ingressAPI:
313-
enabled: true
314-
hostname: api.cp.chainloop.dev
315-
316314
cas:
317-
ingressAPI:
318-
enabled: true
319-
hostname: api.cas.chainloop.dev
315+
ingress:
316+
enabled: true
317+
hostname: cas.chainloop.dev
320318
```
321319

322320
A complete setup that uses
323321

324322
- [NGINX as ingress Controller](https://kubernetes.github.io/ingress-nginx)
325323
- [cert-manager](https://cert-manager.io/) as TLS provider
326324

327-
would look like
325+
would look like the following. The chart already sets the gRPC backend protocol and the CAS upload body-size annotations on the shared ingresses.
328326

329327
```yaml
328+
useSharedEndpoints: true
329+
330330
controlplane:
331331
ingress:
332332
enabled: true
333333
tls: true
334334
ingressClassName: nginx
335335
hostname: cp.chainloop.dev
336336
annotations:
337-
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
338337
# This depends on your configured issuer
339338
cert-manager.io/cluster-issuer: "letsencrypt-prod"
340339
341-
ingressAPI:
342-
enabled: true
343-
tls: true
344-
ingressClassName: nginx
345-
hostname: api.cp.chainloop.dev
346-
annotations:
347-
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
348-
cert-manager.io/cluster-issuer: "letsencrypt-prod"
349-
350340
cas:
351-
ingressAPI:
341+
ingress:
352342
enabled: true
353343
tls: true
354344
ingressClassName: nginx
355-
hostname: api.cas.chainloop.dev
345+
hostname: cas.chainloop.dev
356346
annotations:
357-
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
358347
cert-manager.io/cluster-issuer: "letsencrypt-prod"
359-
# limit the size of the files that go through the proxy
360-
# 0 means to not check the size of the request so we do not get 413 error.
361-
# For now we are going to set a limit on 100MB files
362-
# Even though we send data in chunks of 1MB, this size refers to all the data sent in the streaming connection
363-
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
364348
```
365349

366350
Remember, once you have set up your domain, make sure you use the [CLI pointing](#configure-chainloop-cli-to-point-to-your-instance) to it instead of the defaults.
367351

352+
#### Opt in to shared client endpoints
353+
354+
The chart keeps the existing client endpoint selection by default. Enable `useSharedEndpoints` to move native gRPC clients to the shared HTTP endpoints:
355+
356+
```yaml
357+
useSharedEndpoints: true
358+
```
359+
360+
This flag switches the control plane CAS client to the shared CAS Service. It also changes the CLI addresses in the installation notes to the shared ingress hostnames. With the examples above, the CLI uses `cp.chainloop.dev:443` and `cas.chainloop.dev:443`.
361+
362+
The separate control plane and CAS `ingressAPI` and `serviceAPI` settings are deprecated. They remain functional in this release. The flag changes client selection, not endpoint exposure. Removal belongs to a later release after existing clients migrate.
363+
364+
An installed CLI retains its saved addresses. Reconfigure it explicitly when migrating:
365+
366+
```bash
367+
chainloop config save --control-plane cp.chainloop.dev:443 --artifact-cas cas.chainloop.dev:443
368+
```
369+
370+
Set `useSharedEndpoints: false` to restore the previous client endpoint selection. Reconfigure installed CLIs separately if they need to return to the legacy addresses.
371+
368372
### Connect to an external PostgreSQL database
369373

370374
```yaml
@@ -581,6 +585,7 @@ Once done, you can access with [two predefined users](https://github.com/chainlo
581585
| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` |
582586
| `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` |
583587
| `development` | Deploys Chainloop pre-configured FOR DEVELOPMENT ONLY. It includes a Vault instance in development mode and pre-configured authentication certificates and passphrases | `false` |
588+
| `useSharedEndpoints` | Opt in to shared control plane and CAS HTTP endpoints for native gRPC clients and the CLI addresses in the installation notes. Legacy endpoints remain available. | `false` |
584589

585590
### Common parameters
586591

@@ -697,7 +702,7 @@ Once done, you can access with [two predefined users](https://github.com/chainlo
697702
| `controlplane.service.extraPorts` | Extra ports to expose in controlplane service (normally used with the `sidecars` value) | `[]` |
698703
| `controlplane.service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` |
699704
| `controlplane.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` |
700-
| `controlplane.serviceAPI.type` | Service type | `ClusterIP` |
705+
| `controlplane.serviceAPI.type` | Deprecated gRPC-only Service type. Use the shared service with useSharedEndpoints enabled. | `ClusterIP` |
701706
| `controlplane.serviceAPI.ports.http` | controlplane service HTTP port | `80` |
702707
| `controlplane.serviceAPI.ports.https` | controlplane service HTTPS port | `443` |
703708
| `controlplane.serviceAPI.nodePorts.http` | Node port for HTTP | `""` |
@@ -723,7 +728,7 @@ Once done, you can access with [two predefined users](https://github.com/chainlo
723728
| `controlplane.ingress.extraTls` | TLS configuration for additional hostname(s) to be covered with this ingress record | `[]` |
724729
| `controlplane.ingress.secrets` | Custom TLS certificates as secrets | `[]` |
725730
| `controlplane.ingress.extraRules` | Additional rules to be covered with this ingress record | `[]` |
726-
| `controlplane.ingressAPI.enabled` | Enable ingress record generation for controlplane | `false` |
731+
| `controlplane.ingressAPI.enabled` | Enable the deprecated gRPC-only ingress. Retained during migration. | `false` |
727732
| `controlplane.ingressAPI.pathType` | Ingress path type | `ImplementationSpecific` |
728733
| `controlplane.ingressAPI.hostname` | Default host for the ingress record | `api.cp.dev.local` |
729734
| `controlplane.ingressAPI.ingressClassName` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `""` |
@@ -879,7 +884,7 @@ Once done, you can access with [two predefined users](https://github.com/chainlo
879884
| `cas.service.extraPorts` | Extra ports to expose in cas service (normally used with the `sidecars` value) | `[]` |
880885
| `cas.service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` |
881886
| `cas.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` |
882-
| `cas.serviceAPI.type` | Service type | `ClusterIP` |
887+
| `cas.serviceAPI.type` | Deprecated gRPC-only Service type. Use the shared service with useSharedEndpoints enabled. | `ClusterIP` |
883888
| `cas.serviceAPI.ports.http` | cas service HTTP port | `80` |
884889
| `cas.serviceAPI.ports.https` | cas service HTTPS port | `443` |
885890
| `cas.serviceAPI.nodePorts.http` | Node port for HTTP | `""` |
@@ -905,7 +910,7 @@ Once done, you can access with [two predefined users](https://github.com/chainlo
905910
| `cas.ingress.extraTls` | TLS configuration for additional hostname(s) to be covered with this ingress record | `[]` |
906911
| `cas.ingress.secrets` | Custom TLS certificates as secrets | `[]` |
907912
| `cas.ingress.extraRules` | Additional rules to be covered with this ingress record | `[]` |
908-
| `cas.ingressAPI.enabled` | Enable ingress record generation for controlplane | `false` |
913+
| `cas.ingressAPI.enabled` | Enable the deprecated gRPC-only ingress. Retained during migration. | `false` |
909914
| `cas.ingressAPI.pathType` | Ingress path type | `ImplementationSpecific` |
910915
| `cas.ingressAPI.hostname` | Default host for the ingress record | `api.cas.dev.local` |
911916
| `cas.ingressAPI.ingressClassName` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `""` |

‎deployment/chainloop/chart_test.go‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,36 @@ type chartProbe struct {
277277
} `yaml:"httpGet"`
278278
}
279279

280+
// useSharedEndpoints moves the control plane CAS client to the shared CAS
281+
// Service. The legacy gRPC Services and ingresses remain available.
282+
func TestUseSharedEndpoints(t *testing.T) {
283+
for _, tc := range []struct {
284+
name string
285+
args []string
286+
casAddr string
287+
}{
288+
{name: "defaults", casAddr: "test-chainloop-cas-api:80"},
289+
{name: "explicitly disabled", args: []string{helmSet, "useSharedEndpoints=false"}, casAddr: "test-chainloop-cas-api:80"},
290+
{name: "enabled", args: []string{helmSet, "useSharedEndpoints=true"}, casAddr: "test-chainloop-cas:80"},
291+
{
292+
name: "enabled with custom service port",
293+
args: []string{helmSet, "useSharedEndpoints=true", helmSet, "cas.service.port=8083"},
294+
casAddr: "test-chainloop-cas:8083",
295+
},
296+
} {
297+
t.Run(tc.name, func(t *testing.T) {
298+
resources := renderChart(t, tc.args)
299+
require.Contains(t, resources["ConfigMap/test-chainloop-controlplane"].Data["config.yaml"], "addr: "+tc.casAddr+"\n")
300+
for _, name := range []string{"test-chainloop-controlplane-api", "test-chainloop-cas-api"} {
301+
_, ok := resources["Service/"+name]
302+
require.True(t, ok, name)
303+
_, ok = resources["Ingress/"+name]
304+
require.True(t, ok, name)
305+
}
306+
})
307+
}
308+
}
309+
280310
func TestCASSharedIngressTLS(t *testing.T) {
281311
resources := renderChart(t, []string{helmSet, casIngressEnabled, helmSet, "cas.ingress.tls=true",
282312
helmSetString, `cas.ingress.annotations.cert-manager\.io/cluster-issuer=test-issuer`})

‎deployment/chainloop/templates/_helpers.tpl‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,10 @@ NOTE: Load balancer service type is not supported
337337
{{- define "chainloop.controlplane.external_grpc_url" -}}
338338
{{- $service := .Values.controlplane.serviceAPI }}
339339
{{- $ingress := .Values.controlplane.ingressAPI }}
340+
{{- if .Values.useSharedEndpoints }}
341+
{{- $service = .Values.controlplane.service }}
342+
{{- $ingress = .Values.controlplane.ingress }}
343+
{{- end }}
340344

341345
{{- if (and $ingress $ingress.enabled $ingress.hostname) }}
342346
{{- printf "%s:%s" $ingress.hostname (ternary "443" "80" $ingress.tls) }}
@@ -439,9 +443,24 @@ External gRPC URL the CAS API can be reached at
439443
This endpoint is used by the CLI to connect via gRPC
440444
NOTE: Load balancer service type is not supported
441445
*/}}
446+
{{/*
447+
Artifact CAS gRPC address used by the control plane (host:port)
448+
*/}}
449+
{{- define "chainloop.cas.internal_url" -}}
450+
{{- if .Values.useSharedEndpoints }}
451+
{{- printf "%s:%d" (include "chainloop.cas.fullname" .) (coalesce .Values.cas.service.port .Values.cas.service.ports.http | int) }}
452+
{{- else }}
453+
{{- printf "%s-api:%d" (include "chainloop.cas.fullname" .) (.Values.cas.serviceAPI.ports.http | int) }}
454+
{{- end }}
455+
{{- end -}}
456+
442457
{{- define "chainloop.cas.external_grpc_url" -}}
443458
{{- $service := .Values.cas.serviceAPI }}
444459
{{- $ingress := .Values.cas.ingressAPI }}
460+
{{- if .Values.useSharedEndpoints }}
461+
{{- $service = .Values.cas.service }}
462+
{{- $ingress = .Values.cas.ingress }}
463+
{{- end }}
445464

446465
{{- if (and $ingress $ingress.enabled $ingress.hostname) }}
447466
{{- printf "%s:%s" $ingress.hostname (ternary "443" "80" $ingress.tls) }}

‎deployment/chainloop/templates/controlplane/configmap.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ data:
5151
{{- end }}
5252
cas_server:
5353
grpc:
54-
addr: {{ printf "%s-api:%.0f" (include "chainloop.cas.fullname" .) .Values.cas.serviceAPI.ports.http }}
54+
addr: {{ include "chainloop.cas.internal_url" . }}
5555
insecure: {{ empty (include "controlplane.tls-secret-name" .) }}
5656
download_url: {{ include "chainloop.cas.external_url" . }}/download
5757
{{- if .Values.cas.defaultMaxEntrySize }}

0 commit comments

Comments
 (0)