mirror of
https://github.com/kerberos-io/helm-charts.git
synced 2026-11-05 20:20:24 +00:00
Compare commits
10
Commits
hub-0.169.1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e018357d8 | ||
|
|
0b9d07339f | ||
|
|
78cf3c7e2b | ||
|
|
f0b79bea0c | ||
|
|
535ddc847d | ||
|
|
1c1593a8a0 | ||
|
|
5dfaaf0363 | ||
|
|
56ea65c6e7 | ||
|
|
af4e1c36a9 | ||
|
|
166b4a31e6 |
@@ -20,3 +20,9 @@ jobs:
|
||||
helm lint charts/hub
|
||||
bash scripts/check-admin-runtime.sh
|
||||
bash scripts/check-hardened-workers.sh
|
||||
bash scripts/check-frontend-runtime.sh
|
||||
bash scripts/check-hub-api-runtime.sh
|
||||
- name: Smoke test hardened frontend images and Service routing
|
||||
env:
|
||||
CLUSTER_SMOKE: "true"
|
||||
run: bash scripts/check-frontend-runtime.sh
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.169.1
|
||||
version: 0.175.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
+76
-5
@@ -31,12 +31,41 @@ Uninstall the Kerberos Hub chart
|
||||
|
||||
helm uninstall hub -n kerberos-hub
|
||||
|
||||
### Hardened Hub API
|
||||
|
||||
Starting with chart **`0.170.1`**, `kerberoshub.api.securityContext` is rendered
|
||||
on the Hub API container and `kerberoshub.api.podSecurityContext` on its pod.
|
||||
The current image runs as `65532:65532` with a read-only root filesystem,
|
||||
privilege escalation disabled, all capabilities dropped and `RuntimeDefault`
|
||||
seccomp. A disk-backed `hub-api-tmp` emptyDir mounted at `/tmp`, with pod
|
||||
`fsGroup: 65532`, keeps attachment uploads and multipart parsing writable.
|
||||
API Service, ingress and port settings are unchanged.
|
||||
|
||||
Append custom mounts and volumes to the default lists rather than replacing
|
||||
`hub-api-tmp`. Helm replaces lists in overrides. Existing MongoDB TLS, API TLS,
|
||||
catalog and workflow-configuration mounts remain supported.
|
||||
|
||||
For a legacy image that requires its original identity or writable root
|
||||
filesystem, explicitly set both `kerberoshub.api.securityContext: null` and
|
||||
`kerberoshub.api.podSecurityContext: null`. Custom security settings are
|
||||
per-API; other workloads do not inherit them. When upgrading, check retained
|
||||
values (`--reuse-values` or GitOps overrides) so the security context and
|
||||
writable scratch mount stay aligned.
|
||||
|
||||
Run `bash scripts/check-hub-api-runtime.sh` to validate defaults, overrides,
|
||||
legacy opt-out, TLS/configuration mounts and deployment modes.
|
||||
|
||||
### Hardened frontend images
|
||||
|
||||
New shell-free frontend images run as `65532:65532` and listen on port `8080`.
|
||||
Before selecting such an image tag, set the following values together. Defaults
|
||||
remain compatible with legacy images on port `80`; this chart does not upgrade
|
||||
the frontend image automatically. The Service and ingress remain on port `80`.
|
||||
Starting with chart **`0.170.0`**, both frontends default to shell-free
|
||||
`ghcr.io/uug-ai/hub-frontend:v1.19.28`, running as `65532:65532` on port `8080`
|
||||
with a read-only root filesystem and writable `/tmp`. The Service and ingress
|
||||
remain on port `80`. Admin retains its legacy image and port `80`; its hardened
|
||||
runtime remains opt-in.
|
||||
|
||||
The following frontend runtime settings are now the defaults. When upgrading,
|
||||
remove stale port `80` overrides and coordinate image/runtime values; Helm
|
||||
`--reuse-values` and GitOps overrides may retain the old settings.
|
||||
Use chart `0.167.2` or newer when the demo frontend is enabled; `0.167.1`
|
||||
supports these settings only on the primary frontend.
|
||||
|
||||
@@ -73,6 +102,26 @@ the primary and demo frontends, which share the frontend image tag. Update the
|
||||
live Argo CD Application's chart pin as well as its values: an image-only
|
||||
upgrade leaves older charts forwarding to port `80` and causes gateway errors.
|
||||
|
||||
For legacy frontend images or a rollback, explicitly restore **all** runtime
|
||||
settings together (including removing inherited security defaults):
|
||||
|
||||
```yaml
|
||||
kerberoshub:
|
||||
frontend:
|
||||
tag: v1.13.9
|
||||
containerPort: 80
|
||||
securityContext: null
|
||||
volumes: []
|
||||
volumeMounts: []
|
||||
```
|
||||
|
||||
Keep any application-specific branding mounts when adjusting these lists.
|
||||
Chart upgrades do not rewrite separately managed NodePort Services: ensure they
|
||||
target the named `http` port, not numeric `80`. Follow the duplicate-port recovery
|
||||
instructions below if the existing Deployment cannot be patched to `8080`.
|
||||
Run `bash scripts/check-frontend-runtime.sh` for default, demo, legacy override,
|
||||
and deployment-values regression coverage.
|
||||
|
||||
### Hardened Admin image (opt-in, chart 0.167.3)
|
||||
|
||||
`charts/hub` deploys Admin in `all` and `ui` modes. Shell-free Admin `v1.4.3`
|
||||
@@ -743,6 +792,7 @@ kerberospipeline:
|
||||
| `kerberoshub.frontend.features.organisations.switcherEnabled` | Enable or disable the organisation dropdown and switching. The current organisation remains visible when disabled. | `"false"` |
|
||||
| `kerberoshub.frontend.features.organisations.creationEnabled` | Enable or disable organisation creation. Requires organisation switching to be enabled. | `"false"` |
|
||||
| `kerberoshub.frontend.features.organisations.settingsEnabled` | Enable or disable the organisation identity link to organisation settings. | `"false"` |
|
||||
| `kerberoshub.frontend.features.organisations.membersAccessPreviewEnabled` | Show the "Users (preview)" tab in organisation settings to organisation owners: a mockup of project, role and resource assignments with mocked users and data, nothing saved. Sets `FEATURE_MEMBERS_ACCESS_PREVIEW_ENABLED`. | `"false"` |
|
||||
| `kerberoshub.frontend.features.projects.enabled` | Fallback project group switch used when the organisations umbrella is unset. | `""` |
|
||||
| `kerberoshub.frontend.features.projects.switcherEnabled` | Enable or disable the read-only project dropdown. | `"false"` |
|
||||
| `kerberoshub.frontend.features.projects.creationEnabled` | Reserved for the project creation UI. | `"false"` |
|
||||
@@ -852,7 +902,26 @@ kerberospipeline:
|
||||
| `kerberoshub.audit.dispatchInterval` | How often the mounted destination configuration is reloaded and eligible destinations are polled. | `"5s"` |
|
||||
| `kerberoshub.audit.leaseDuration` | Per-destination lease duration. It must exceed every destination timeout by at least 30 seconds. | `"2m"` |
|
||||
| `kerberoshub.audit.terminationGracePeriodSeconds` | Pod termination grace period. Keep this longer than `leaseDuration` so an in-flight cycle can finish. | `150` |
|
||||
| `kerberoshub.audit.destinations` | Audit destinations. Every entry supports `id`, `type` (`webhook` by default, or `s3`), `enabled`, delivery limits and filters. Webhooks add `url`, public `headers`, `bearerTokenSecret` and arbitrary `secretHeaders`. S3 destinations add `s3.bucket`, `s3.region`, optional `s3.prefix`, `s3.endpoint` and `s3.forcePathStyle` for S3-compatible stores, and an optional `credentialsSecret` (`name`, `accessKeyIdKey`, `secretAccessKeyKey`); without it the pod's AWS identity is used. The bucket must have Object Lock with a `COMPLIANCE` default retention unless `s3.allowUnlockedBucket` is `true` (stores without Object Lock such as Garage; the archive is then deletable). Every field, the delivery semantics and per-provider S3 settings are documented at https://learn.uug.ai/docs/hub/audit-events/#export-audit-events. Destination IDs retain independent checkpoints. | `[]` |
|
||||
| `kerberoshub.audit.destinations` | Audit destinations: webhooks that receive batches as JSON, or S3 buckets that archive them. Every entry is validated when the chart renders. Credentials (`bearerToken`, `secretHeaders.<name>.value`, `s3.accessKey` / `s3.secretKey`) are set inline; the chart stores them in Secret `hub-audit-<id>-credentials`, and changes take effect within a few minutes without a restart. Delivery semantics and per-provider S3 settings: https://learn.uug.ai/docs/hub/audit-events/#export-audit-events. | `[]` |
|
||||
| `kerberoshub.audit.destinations[].id` | Required. Unique name, `^[a-z][a-z0-9-]{0,62}$`. The delivery checkpoint is stored under it, so renaming starts a new destination. | |
|
||||
| `kerberoshub.audit.destinations[].type` | Optional. `webhook` or `s3`. | `webhook` |
|
||||
| `kerberoshub.audit.destinations[].enabled` | Optional. `false` pauses delivery and keeps the checkpoint. | `true` |
|
||||
| `kerberoshub.audit.destinations[].timeoutSeconds` | Optional. Timeout for one delivery, at most 60. | `10` |
|
||||
| `kerberoshub.audit.destinations[].batchSize` | Optional. Events per batch, at most 1000. | `100` |
|
||||
| `kerberoshub.audit.destinations[].maxAttempts` | Optional. Attempts before a batch is dead-lettered. Keep it high for S3 archives. | `10` |
|
||||
| `kerberoshub.audit.destinations[].startAt` | Optional. `latest` or `beginning`; only applies to a new `id`. | `latest` |
|
||||
| `kerberoshub.audit.destinations[].filters` | Optional. Lists `organisationIds`, `projectIds` (ObjectIds), `actions`, `categories` and `outcomes` (`success`, `failure`). An event must match every list that is set. | all events |
|
||||
| `kerberoshub.audit.destinations[].url` | Required for webhooks. `http` or `https` endpoint that receives each batch. | |
|
||||
| `kerberoshub.audit.destinations[].headers` | Optional, webhooks. Public request headers. `Authorization` and `Idempotency-Key` are reserved. | `{}` |
|
||||
| `kerberoshub.audit.destinations[].bearerToken` | Optional, webhooks. Sent as `Authorization: Bearer <token>`. | |
|
||||
| `kerberoshub.audit.destinations[].secretHeaders.<name>.value` | Optional, webhooks. Header with a secret value, such as an API key. | |
|
||||
| `kerberoshub.audit.destinations[].s3.bucket` | Required for S3. Bucket with versioning, Object Lock and a `COMPLIANCE` default retention. | |
|
||||
| `kerberoshub.audit.destinations[].s3.region` | Required for S3, also for S3-compatible stores. | |
|
||||
| `kerberoshub.audit.destinations[].s3.prefix` | Optional. Key prefix; objects are written as `<prefix>/<id>/yyyy/mm/dd/<firstId>-<lastId>.ndjson.gz`. | |
|
||||
| `kerberoshub.audit.destinations[].s3.endpoint` | Optional. Base URL of an S3-compatible store, without the bucket. Omit for AWS S3. | |
|
||||
| `kerberoshub.audit.destinations[].s3.forcePathStyle` | Optional. Path-style URLs, usually needed for Ceph RGW, MinIO and Garage. | `false` |
|
||||
| `kerberoshub.audit.destinations[].s3.allowUnlockedBucket` | Optional. Skips the Object Lock check for stores without Object Lock, such as Garage; archived batches are then deletable. | `false` |
|
||||
| `kerberoshub.audit.destinations[].s3.accessKey` / `kerberoshub.audit.destinations[].s3.secretKey` | Optional, both or neither, not empty. Without them the pod's AWS identity is used (AWS S3 only). | |
|
||||
| `kerberoshub.audit.serviceAccount.create` | Create a ServiceAccount used only by hub-audit, for example for S3 access through IRSA. | `false` |
|
||||
| `kerberoshub.audit.serviceAccount.name` | Name of the hub-audit ServiceAccount; with `create: false`, an existing ServiceAccount to use. Defaults to `hub-audit` when created; when empty and not created, `kerberoshub.serviceAccount` applies. | `""` |
|
||||
| `kerberoshub.audit.serviceAccount.annotations` | Annotations for the hub-audit ServiceAccount, such as `eks.amazonaws.com/role-arn`. | `{}` |
|
||||
@@ -862,6 +931,8 @@ kerberospipeline:
|
||||
| `kerberoshub.audit.volumes` | Additional pod volumes, for example a private webhook CA bundle. | `[]` |
|
||||
| `kerberoshub.audit.volumeMounts` | Additional audit service container volume mounts. | `[]` |
|
||||
| `kerberoshub.audit.extraEnv` | Additional audit service environment variables. | `[]` |
|
||||
| `kerberoshub.audit.resources` | Resource requests and limits for the audit service container. | `{}` |
|
||||
| `kerberoshub.audit.topologySpreadConstraints` | Topology spread constraints for audit service pods. | `[]` |
|
||||
| `kerberoshub.monitordevice.repository` | The monitoring microservice, following up the status of your cameras and Kerberos Agents. | `"ghcr.io/uug-ai/hub-monitor-device"` |
|
||||
| `kerberoshub.monitordevice.pullPolicy` | The Docker registry pull policy. | `"IfNotPresent"` |
|
||||
| `kerberoshub.monitordevice.tag` | The Docker image tag/version. | `"v1.4.0"` |
|
||||
|
||||
@@ -106,3 +106,66 @@ Usage: {{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
hub.audit.destinations resolves the audit destinations into JSON. Inline
|
||||
credentials (s3.accessKey / s3.secretKey on S3 destinations, bearerToken and
|
||||
secretHeaders.<name>.value on webhooks) are the only way to pass credentials.
|
||||
They are stored in a chart-created Secret named hub-audit-<id>-credentials;
|
||||
the internal credentialsSecret / bearerTokenSecret / secretHeaders entries
|
||||
below describe that Secret for the other templates.
|
||||
Use: fromJsonArray (include "hub.audit.destinations" .)
|
||||
*/}}
|
||||
{{- define "hub.audit.destinations" -}}
|
||||
{{- $resolved := list -}}
|
||||
{{- range $index, $original := .Values.kerberoshub.audit.destinations -}}
|
||||
{{- $destination := deepCopy $original -}}
|
||||
{{- $label := default (printf "%d" $index) $destination.id -}}
|
||||
{{- if hasKey $destination "credentialsSecret" -}}
|
||||
{{- fail (printf "audit destination %s: credentialsSecret is not supported; set s3.accessKey and s3.secretKey" $label) -}}
|
||||
{{- end -}}
|
||||
{{- if hasKey $destination "bearerTokenSecret" -}}
|
||||
{{- fail (printf "audit destination %s: bearerTokenSecret is not supported; set bearerToken" $label) -}}
|
||||
{{- end -}}
|
||||
{{- $s3 := default dict $destination.s3 -}}
|
||||
{{- if or (hasKey $s3 "accessKey") (hasKey $s3 "secretKey") -}}
|
||||
{{- $id := required (printf "id is required for audit destination %d" $index) $destination.id -}}
|
||||
{{- if not (and $s3.accessKey $s3.secretKey) -}}
|
||||
{{- fail (printf "audit destination %s must set both s3.accessKey and s3.secretKey, and neither may be empty" $id) -}}
|
||||
{{- end -}}
|
||||
{{- $_ := set $destination "credentialsSecret" (dict
|
||||
"name" (printf "hub-audit-%s-credentials" $id)
|
||||
"create" true
|
||||
"accessKeyId" $s3.accessKey
|
||||
"secretAccessKey" $s3.secretKey) -}}
|
||||
{{- $_ := unset $s3 "accessKey" -}}
|
||||
{{- $_ := unset $s3 "secretKey" -}}
|
||||
{{- end -}}
|
||||
{{- if hasKey $destination "bearerToken" -}}
|
||||
{{- $id := required (printf "id is required for audit destination %d" $index) $destination.id -}}
|
||||
{{- if not $destination.bearerToken -}}
|
||||
{{- fail (printf "audit destination %s sets an empty bearerToken" $id) -}}
|
||||
{{- end -}}
|
||||
{{- $_ := set $destination "bearerTokenSecret" (dict
|
||||
"name" (printf "hub-audit-%s-credentials" $id)
|
||||
"key" "bearer-token"
|
||||
"create" true
|
||||
"value" $destination.bearerToken) -}}
|
||||
{{- $_ := unset $destination "bearerToken" -}}
|
||||
{{- end -}}
|
||||
{{- range $header, $secret := (default dict $destination.secretHeaders) -}}
|
||||
{{- if or (not (kindIs "map" $secret)) (not (hasKey $secret "value")) (hasKey $secret "secretName") (hasKey $secret "secretKey") -}}
|
||||
{{- fail (printf "audit destination %s header %s: set secretHeaders.%s.value" $label $header $header) -}}
|
||||
{{- end -}}
|
||||
{{- $id := required (printf "id is required for audit destination %d" $index) $destination.id -}}
|
||||
{{- if not $secret.value -}}
|
||||
{{- fail (printf "audit destination %s header %s sets an empty value" $id $header) -}}
|
||||
{{- end -}}
|
||||
{{- $_ := set $secret "secretName" (printf "hub-audit-%s-credentials" $id) -}}
|
||||
{{- $_ := set $secret "secretKey" (printf "header-%s" (sha256sum $header | trunc 12)) -}}
|
||||
{{- $_ := set $secret "create" true -}}
|
||||
{{- end -}}
|
||||
{{- $resolved = append $resolved $destination -}}
|
||||
{{- end -}}
|
||||
{{- toJson $resolved -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{- if .Values.audit.enabled -}}
|
||||
{{- $destinations := list -}}
|
||||
{{- $destinationIDs := dict -}}
|
||||
{{- range $index, $destination := .Values.kerberoshub.audit.destinations -}}
|
||||
{{- range $index, $destination := fromJsonArray (include "hub.audit.destinations" .) -}}
|
||||
{{- $id := required (printf "id is required for audit destination %d" $index) $destination.id -}}
|
||||
{{- if not (regexMatch "^[a-z][a-z0-9-]{0,62}$" $id) -}}
|
||||
{{- fail (printf "audit destination id %q must match ^[a-z][a-z0-9-]{0,62}$" $id) -}}
|
||||
@@ -14,7 +14,7 @@
|
||||
{{- $entry := dict
|
||||
"id" $id
|
||||
"type" $type
|
||||
"enabled" $destination.enabled
|
||||
"enabled" (ternary $destination.enabled true (hasKey $destination "enabled"))
|
||||
"timeoutSeconds" (default 10 $destination.timeoutSeconds)
|
||||
"batchSize" (default 100 $destination.batchSize)
|
||||
"maxAttempts" (default 10 $destination.maxAttempts)
|
||||
@@ -44,7 +44,7 @@
|
||||
{{- end -}}
|
||||
{{- else if eq $type "s3" -}}
|
||||
{{- if or $destination.url $destination.headers $destination.bearerTokenSecret $destination.secretHeaders -}}
|
||||
{{- fail (printf "audit destination %s is s3 and cannot set url, headers, bearerTokenSecret or secretHeaders" $id) -}}
|
||||
{{- fail (printf "audit destination %s is s3 and cannot set url, headers, bearerToken, bearerTokenSecret or secretHeaders" $id) -}}
|
||||
{{- end -}}
|
||||
{{- $s3 := required (printf "s3 is required for audit destination %s" $id) $destination.s3 -}}
|
||||
{{- $settings := dict
|
||||
|
||||
@@ -140,6 +140,10 @@ spec:
|
||||
labels:
|
||||
app: hub-api
|
||||
spec:
|
||||
{{- with .Values.kerberoshub.api.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.kerberoshub.serviceAccount.create }}
|
||||
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
|
||||
{{- end }}
|
||||
@@ -229,6 +233,10 @@ spec:
|
||||
- name: hub-api
|
||||
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.api.repository }}:{{ .Values.kerberoshub.api.tag }}"
|
||||
imagePullPolicy: {{ .Values.kerberoshub.api.pullPolicy }}
|
||||
{{- with .Values.kerberoshub.api.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.kerberoshub.api.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{{- if .Values.audit.enabled }}
|
||||
{{- /*
|
||||
Secret the chart creates per audit destination from its inline credentials
|
||||
(s3.accessKey / s3.secretKey, bearerToken, secretHeaders.<name>.value).
|
||||
*/}}
|
||||
{{- $created := dict }}
|
||||
{{- range $index, $destination := fromJsonArray (include "hub.audit.destinations" .) }}
|
||||
{{- $data := dict }}
|
||||
{{- $name := "" }}
|
||||
{{- $credentials := default dict $destination.credentialsSecret }}
|
||||
{{- if $credentials.create }}
|
||||
{{- $name = required (printf "credentialsSecret.name is required for destination %s" $destination.id) $credentials.name }}
|
||||
{{- $accessKeyIdKey := default "access-key-id" $credentials.accessKeyIdKey }}
|
||||
{{- $secretAccessKeyKey := default "secret-access-key" $credentials.secretAccessKeyKey }}
|
||||
{{- if eq $accessKeyIdKey $secretAccessKeyKey }}
|
||||
{{- fail (printf "credentialsSecret.accessKeyIdKey and secretAccessKeyKey must differ for destination %s" $destination.id) }}
|
||||
{{- end }}
|
||||
{{- $_ := set $data $accessKeyIdKey (required (printf "credentialsSecret.accessKeyId is required for destination %s when credentialsSecret.create is true" $destination.id) $credentials.accessKeyId) }}
|
||||
{{- $_ := set $data $secretAccessKeyKey (required (printf "credentialsSecret.secretAccessKey is required for destination %s when credentialsSecret.create is true" $destination.id) $credentials.secretAccessKey) }}
|
||||
{{- end }}
|
||||
{{- $bearer := default dict $destination.bearerTokenSecret }}
|
||||
{{- if $bearer.create }}
|
||||
{{- $name = $bearer.name }}
|
||||
{{- $_ := set $data $bearer.key $bearer.value }}
|
||||
{{- end }}
|
||||
{{- range $header, $secret := (default dict $destination.secretHeaders) }}
|
||||
{{- if $secret.create }}
|
||||
{{- $name = $secret.secretName }}
|
||||
{{- $_ := set $data $secret.secretKey $secret.value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $name }}
|
||||
{{- if hasKey $created $name }}
|
||||
{{- fail (printf "audit destinations %s and %s both create Secret %q" (get $created $name) $destination.id $name) }}
|
||||
{{- end }}
|
||||
{{- $_ := set $created $name $destination.id }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
app: hub-audit
|
||||
audit-destination: {{ $destination.id }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- range $key, $value := $data }}
|
||||
{{ $key | quote }}: {{ toString $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -43,7 +43,7 @@ spec:
|
||||
- name: destinations
|
||||
configMap:
|
||||
name: hub-audit
|
||||
{{- range $index, $destination := .Values.kerberoshub.audit.destinations }}
|
||||
{{- range $index, $destination := fromJsonArray (include "hub.audit.destinations" $) }}
|
||||
{{- $bearer := default dict $destination.bearerTokenSecret }}
|
||||
{{- $secretHeaders := default dict $destination.secretHeaders }}
|
||||
{{- $credentials := default dict $destination.credentialsSecret }}
|
||||
@@ -112,7 +112,7 @@ spec:
|
||||
- name: destinations
|
||||
mountPath: /etc/hub-audit
|
||||
readOnly: true
|
||||
{{- range $index, $destination := .Values.kerberoshub.audit.destinations }}
|
||||
{{- range $index, $destination := fromJsonArray (include "hub.audit.destinations" $) }}
|
||||
{{- $bearer := default dict $destination.bearerTokenSecret }}
|
||||
{{- $secretHeaders := default dict $destination.secretHeaders }}
|
||||
{{- $credentials := default dict $destination.credentialsSecret }}
|
||||
|
||||
@@ -110,7 +110,7 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.kerberoshub.frontend.containerPort | default 80 }}
|
||||
- containerPort: {{ .Values.kerberoshub.frontend.containerPort | default 8080 }}
|
||||
name: http
|
||||
{{- with .Values.kerberoshub.frontend.volumeMounts}}
|
||||
volumeMounts:
|
||||
@@ -259,6 +259,8 @@ spec:
|
||||
value: "{{ .Values.kerberoshub.frontend.features.organisations.creationEnabled }}"
|
||||
- name: FEATURE_ORGANISATION_SETTINGS_ENABLED
|
||||
value: "{{ .Values.kerberoshub.frontend.features.organisations.settingsEnabled }}"
|
||||
- name: FEATURE_MEMBERS_ACCESS_PREVIEW_ENABLED
|
||||
value: "{{ .Values.kerberoshub.frontend.features.organisations.membersAccessPreviewEnabled }}"
|
||||
- name: FEATURE_PROJECTS_ENABLED
|
||||
value: "{{ .Values.kerberoshub.frontend.features.projects.enabled }}"
|
||||
- name: FEATURE_PROJECT_SWITCHER_ENABLED
|
||||
|
||||
@@ -191,7 +191,7 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.kerberoshub.frontend.containerPort | default 80 }}
|
||||
- containerPort: {{ .Values.kerberoshub.frontend.containerPort | default 8080 }}
|
||||
name: http
|
||||
{{- with .Values.kerberoshub.frontend.volumeMounts}}
|
||||
volumeMounts:
|
||||
@@ -338,6 +338,8 @@ spec:
|
||||
value: "{{ .Values.kerberoshub.frontend.features.organisations.creationEnabled }}"
|
||||
- name: FEATURE_ORGANISATION_SETTINGS_ENABLED
|
||||
value: "{{ .Values.kerberoshub.frontend.features.organisations.settingsEnabled }}"
|
||||
- name: FEATURE_MEMBERS_ACCESS_PREVIEW_ENABLED
|
||||
value: "{{ .Values.kerberoshub.frontend.features.organisations.membersAccessPreviewEnabled }}"
|
||||
- name: FEATURE_PROJECTS_ENABLED
|
||||
value: "{{ .Values.kerberoshub.frontend.features.projects.enabled }}"
|
||||
- name: FEATURE_PROJECT_SWITCHER_ENABLED
|
||||
|
||||
+101
-67
@@ -50,7 +50,6 @@ mongodb:
|
||||
# hub-pipeline-monitor, ...) instead of the one in uri, so the Atlas query
|
||||
# profiler and currentOp show which service issued an operation.
|
||||
appNamePerService: true
|
||||
|
||||
# Self-hosted mongodb, you could also use the uri property above.
|
||||
host: mongodb.mongodb
|
||||
adminDatabase: admin
|
||||
@@ -73,7 +72,6 @@ mongodb:
|
||||
caFileName: ""
|
||||
mountPath: "/etc/mongodb/tls"
|
||||
insecureSkipVerify: false
|
||||
|
||||
# Classifications supported by Hub filters, alerts, markers, and other
|
||||
# downstream processing. Classifier output keys must match these values.
|
||||
# Disable this to use the legacy classification catalog stored in MongoDB.
|
||||
@@ -115,7 +113,6 @@ deviceTags:
|
||||
# - key: anpr-pilot
|
||||
# label: ANPR pilot
|
||||
# description: Runs licence plate recognition on this camera
|
||||
|
||||
# Configuration packaging only: consuming contracts requires a compatible
|
||||
# API/frontend. Enabling this mounts files but does not register stage workers.
|
||||
workflowConfiguration:
|
||||
@@ -339,8 +336,27 @@ kerberoshub:
|
||||
api:
|
||||
repository: ghcr.io/uug-ai/hub-api
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.9.51"
|
||||
tag: "v1.11.31"
|
||||
replicas: 2
|
||||
podSecurityContext:
|
||||
fsGroup: 65532
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65532
|
||||
runAsGroup: 65532
|
||||
readOnlyRootFilesystem: true
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
# Keep writable scratch space for attachment uploads and multipart parsing.
|
||||
volumes:
|
||||
- name: hub-api-tmp
|
||||
emptyDir: {}
|
||||
volumeMounts:
|
||||
- name: hub-api-tmp
|
||||
mountPath: /tmp
|
||||
audit:
|
||||
enabled: true
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
@@ -375,6 +391,7 @@ kerberoshub:
|
||||
memory: 100Mi
|
||||
cpu: 250m
|
||||
# E-mail templates
|
||||
# Append custom mounts/volumes to the lists above; retain hub-api-tmp.
|
||||
#volumeMounts:
|
||||
# - name: custom-email-templates
|
||||
# mountPath: /mail
|
||||
@@ -482,11 +499,28 @@ kerberoshub:
|
||||
frontend:
|
||||
repository: ghcr.io/uug-ai/hub-frontend
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.13.9"
|
||||
tag: "v1.19.28"
|
||||
replicas: 2
|
||||
# Hardened frontend images listen on 8080; retain 80 for existing images.
|
||||
containerPort: 80
|
||||
securityContext: {}
|
||||
containerPort: 8080
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65532
|
||||
runAsGroup: 65532
|
||||
readOnlyRootFilesystem: true
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
# Keep these entries when adding custom branding/translation mounts.
|
||||
volumes:
|
||||
- name: frontend-tmp
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 16Mi
|
||||
volumeMounts:
|
||||
- name: frontend-tmp
|
||||
mountPath: /tmp
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Set to false to skip rendering the hub-frontend Service (e.g. when an
|
||||
# external/shared Service is managed elsewhere).
|
||||
@@ -621,6 +655,7 @@ kerberoshub:
|
||||
switcherEnabled: "false" # Enable or disable organisation switching 'true' or 'false'
|
||||
creationEnabled: "false" # Enable or disable organisation creation; requires switcherEnabled 'true' or 'false'
|
||||
settingsEnabled: "false" # Enable or disable the organisation settings link 'true' or 'false'
|
||||
membersAccessPreviewEnabled: "false" # Show the mocked "Users (preview)" tab in organisation settings to owners 'true' or 'false'
|
||||
projects:
|
||||
enabled: "" # Fallback project group switch used only when organisations.enabled is empty
|
||||
switcherEnabled: "false" # Enable or disable the read-only project dropdown 'true' or 'false'
|
||||
@@ -776,7 +811,7 @@ kerberoshub:
|
||||
podSecurityContext: {}
|
||||
repository: ghcr.io/uug-ai/hub-cleanup
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.4.19"
|
||||
tag: "v1.4.26"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -826,12 +861,17 @@ kerberoshub:
|
||||
cpu: 10m
|
||||
# Dispatches canonical audit_events to one or more destinations: webhook
|
||||
# sinks, or S3 Object Lock buckets for immutable storage.
|
||||
# Credentials are always read from existing Secrets and never stored here.
|
||||
# Destination credentials are set inline on each destination.
|
||||
audit:
|
||||
repository: ghcr.io/uug-ai/hub-audit
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.0.10"
|
||||
replicas: 1
|
||||
resources: {}
|
||||
# resources:
|
||||
# requests:
|
||||
# memory: 32Mi
|
||||
# cpu: 10m
|
||||
dispatchInterval: "5s"
|
||||
leaseDuration: "2m"
|
||||
terminationGracePeriodSeconds: 150 # Keep above leaseDuration so an in-flight cycle can finish.
|
||||
@@ -852,63 +892,57 @@ kerberoshub:
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
interval: 15s
|
||||
# Each destination is optional; see the README for every field. Webhook:
|
||||
destinations: []
|
||||
# - id: primary-siem
|
||||
# type: webhook
|
||||
# enabled: true
|
||||
# url: https://siem.example.com/api/audit
|
||||
# timeoutSeconds: 10
|
||||
# batchSize: 100
|
||||
# maxAttempts: 10
|
||||
# startAt: latest # latest | beginning, applied only on first creation
|
||||
# headers:
|
||||
# - id: primary-siem # required; ^[a-z][a-z0-9-]{0,62}$, keeps the checkpoint
|
||||
# type: webhook # optional: webhook (default) | s3
|
||||
# enabled: true # optional, default true; false pauses delivery
|
||||
# url: https://siem.example.com/api/audit # required, http or https
|
||||
# timeoutSeconds: 10 # optional, default 10, at most 60
|
||||
# batchSize: 100 # optional, default 100, at most 1000
|
||||
# maxAttempts: 10 # optional, default 10; then the batch is dead-lettered
|
||||
# startAt: latest # optional: latest (default) | beginning, for a new id only
|
||||
# headers: # optional; not Authorization or Idempotency-Key
|
||||
# X-Source: kerberos-hub
|
||||
# bearerTokenSecret:
|
||||
# name: audit-primary-siem
|
||||
# key: token
|
||||
# # Optional inline credentials. The chart stores them in Secret
|
||||
# # hub-audit-<id>-credentials and mounts them.
|
||||
# bearerToken: "xxx" # sent as Authorization: Bearer <token>
|
||||
# secretHeaders:
|
||||
# X-Api-Key:
|
||||
# secretName: audit-primary-siem
|
||||
# secretKey: api-key
|
||||
# filters:
|
||||
# value: "xxx"
|
||||
# filters: # optional, default all events; an event must match every list set
|
||||
# organisationIds: []
|
||||
# projectIds: []
|
||||
# actions: []
|
||||
# categories: []
|
||||
# outcomes: [] # success | failure
|
||||
# S3 Object Lock destination (hub-audit v1.0.9 or later). The bucket needs
|
||||
# versioning, Object Lock and a COMPLIANCE default retention; hub-audit
|
||||
# refuses to deliver otherwise. Each batch is written as
|
||||
# <prefix>/<id>/yyyy/mm/dd/<firstId>-<lastId>.ndjson.gz. Per-provider
|
||||
# region/endpoint values (AWS, Wasabi, B2, Ceph RGW, MinIO, Garage):
|
||||
# S3 Object Lock destination. The bucket needs versioning, Object Lock and a
|
||||
# COMPLIANCE default retention; hub-audit refuses to deliver otherwise. Each
|
||||
# batch is written as <prefix>/<id>/yyyy/mm/dd/<firstId>-<lastId>.ndjson.gz.
|
||||
# Per-provider region/endpoint values (AWS, Wasabi, B2, Ceph RGW, MinIO, Garage):
|
||||
# https://learn.uug.ai/docs/hub/audit-events/#s3-providers
|
||||
# - id: immutable-archive
|
||||
# type: s3
|
||||
# enabled: true
|
||||
# - id: immutable-archive # required
|
||||
# type: s3 # required for S3
|
||||
# enabled: true # optional, default true
|
||||
# timeoutSeconds: 30
|
||||
# batchSize: 500
|
||||
# maxAttempts: 100 # keep high: exhausted batches are dead-lettered, not archived
|
||||
# startAt: beginning
|
||||
# s3:
|
||||
# bucket: hub-audit-archive
|
||||
# region: eu-west-1
|
||||
# prefix: hub
|
||||
# endpoint: https://s3.example.com # S3-compatible stores only; omit for AWS S3
|
||||
# forcePathStyle: true # usually needed for Ceph RGW, MinIO and Garage
|
||||
# # Only for stores without Object Lock (e.g. Garage): skips the lock
|
||||
# # check, so archived batches are deletable. Needs hub-audit v1.0.10.
|
||||
# bucket: hub-audit-archive # required
|
||||
# region: eu-west-1 # required, also for S3-compatible stores
|
||||
# prefix: hub # optional, default none
|
||||
# endpoint: https://s3.example.com # optional; S3-compatible stores only, omit for AWS S3
|
||||
# forcePathStyle: true # optional, default false; usually true for Ceph RGW, MinIO and Garage
|
||||
# # Optional, default false. Only for stores without Object Lock (e.g. Garage):
|
||||
# # skips the lock check, so archived batches are deletable.
|
||||
# allowUnlockedBucket: false
|
||||
# # Omit credentialsSecret to use the pod's AWS identity (IRSA via
|
||||
# # kerberoshub.audit.serviceAccount, or an instance profile). That only
|
||||
# # works for AWS S3; every other store needs credentialsSecret.
|
||||
# credentialsSecret:
|
||||
# name: audit-immutable-archive
|
||||
# accessKeyIdKey: access-key-id
|
||||
# secretAccessKeyKey: secret-access-key
|
||||
# resources:
|
||||
# requests:
|
||||
# memory: 32Mi
|
||||
# cpu: 10m
|
||||
# # Optional inline credentials, both or neither. The chart stores them
|
||||
# # in Secret hub-audit-<id>-credentials and mounts them.
|
||||
# accessKey: "xxx"
|
||||
# secretKey: "xxx"
|
||||
# # Without them, hub-audit uses the pod's AWS identity (IRSA via
|
||||
# # kerberoshub.audit.serviceAccount, or an instance profile): AWS S3 only.
|
||||
# hub-workflows is the standalone, queue-driven workflow engine. It consumes
|
||||
# pipeline events and dispatches the stages declared in its workflow
|
||||
# definitions, tracking each run in its own `workflow_runs` collection. It shares events
|
||||
@@ -1141,7 +1175,7 @@ kerberoshub:
|
||||
podSecurityContext: {}
|
||||
repository: ghcr.io/uug-ai/hub-monitor-device
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.4.2"
|
||||
tag: "v1.4.10"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
logLevel: "info" # possible values: trace, debug, info, warn, error
|
||||
@@ -1229,7 +1263,7 @@ kerberospipeline:
|
||||
# argocd.argoproj.io/sync-wave: "10"
|
||||
repository: ghcr.io/uug-ai/hub-pipeline-event
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.3.1"
|
||||
tag: "v1.3.9"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1250,7 +1284,7 @@ kerberospipeline:
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "70"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.3.13"
|
||||
tag: "v1.3.29"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1271,7 +1305,7 @@ kerberospipeline:
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "60"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.6.26"
|
||||
tag: "v1.7.14"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1289,12 +1323,12 @@ kerberospipeline:
|
||||
throttler:
|
||||
securityContext: {}
|
||||
podSecurityContext: {}
|
||||
repository: uugai/hub-pipeline-throttler
|
||||
repository: ghcr.io/uug-ai/hub-pipeline-throttler
|
||||
deploymentAnnotations: {}
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "30"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.2.1"
|
||||
tag: "v1.2.10"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1317,7 +1351,7 @@ kerberospipeline:
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "20"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.3.18"
|
||||
tag: "v1.3.46"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
audit:
|
||||
enabled: true
|
||||
@@ -1337,9 +1371,9 @@ kerberospipeline:
|
||||
# persistentVolumeClaim:
|
||||
# claimName: custom-layout-claim
|
||||
notifyTest:
|
||||
repository: uugai/hub-pipeline-notification-test
|
||||
repository: ghcr.io/uug-ai/hub-pipeline-notification-test
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.2.2"
|
||||
tag: "v1.2.6"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
resources:
|
||||
@@ -1360,7 +1394,7 @@ kerberospipeline:
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "40"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.8.22"
|
||||
tag: "v1.8.29"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1398,7 +1432,7 @@ kerberospipeline:
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "50"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v2.0.3"
|
||||
tag: "v2.0.9"
|
||||
replicas: 3 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1424,7 +1458,7 @@ kerberospipeline:
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "50"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.3.15"
|
||||
tag: "v1.3.22"
|
||||
replicas: 2 # Number of pods for the service.
|
||||
prefetchCount: 0 # Max unacknowledged RabbitMQ messages per pod; 0 = service default (5).
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
@@ -1452,12 +1486,12 @@ kerberospipeline:
|
||||
counting:
|
||||
securityContext: {}
|
||||
podSecurityContext: {}
|
||||
repository: uugai/hub-pipeline-counting
|
||||
repository: ghcr.io/uug-ai/hub-pipeline-counting
|
||||
deploymentAnnotations: {}
|
||||
# deploymentAnnotations:
|
||||
# argocd.argoproj.io/sync-wave: "50"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v2.0.0"
|
||||
tag: "v2.0.6"
|
||||
replicas: 1 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
# Optional extra volumes / volumeMounts for this deployment (empty = none).
|
||||
@@ -1479,7 +1513,7 @@ kerberospipeline:
|
||||
# argocd.argoproj.io/sync-wave: "50"
|
||||
repository: ghcr.io/uug-ai/hub-pipeline-sprite
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.1.21"
|
||||
tag: "v1.1.27"
|
||||
replicas: 5 # Number of pods for the service.
|
||||
prefetchCount: 0 # Max unacknowledged RabbitMQ messages per pod; 0 = service default (5).
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
@@ -1506,7 +1540,7 @@ kerberospipeline:
|
||||
export:
|
||||
repository: ghcr.io/uug-ai/hub-pipeline-export
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "v1.2.10"
|
||||
tag: "v1.2.20"
|
||||
replicas: 2 # Number of pods for the service.
|
||||
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
|
||||
logLevel: "info" # possible values: trace, debug, info, warn, error
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CHART_DIR="${1:-charts/hub}"
|
||||
values=()
|
||||
if [[ $# -ge 2 ]]; then values=(--values "$2"); fi
|
||||
|
||||
resource() {
|
||||
local kind="$1" name="$2"
|
||||
awk -v kind="$kind" -v name="$name" '
|
||||
function emit() { if (matchedKind && matchedName) printf "%s", block }
|
||||
/^---$/ { emit(); block=""; matchedKind=0; matchedName=0 }
|
||||
{ block=block $0 "\n" }
|
||||
$0 == "kind: " kind { matchedKind=1 }
|
||||
$0 == " name: " name { matchedName=1 }
|
||||
END { emit() }
|
||||
'
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
if ! grep -Eq -- "$2" <<< "$1"; then
|
||||
printf 'Missing expected frontend setting: %s\n' "$2" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for mode in all ui; do
|
||||
rendered="$(helm template hub "$CHART_DIR" "${values[@]}" --set "mode=$mode" \
|
||||
--set kerberoshub.frontend.demoEnabled=true)"
|
||||
for name in hub-frontend hub-frontend-demo; do
|
||||
deployment="$(resource Deployment "$name" <<< "$rendered")"
|
||||
assert_contains "$deployment" 'image: "ghcr.io/uug-ai/hub-frontend:v1.19.28"$'
|
||||
assert_contains "$deployment" 'containerPort: 8080$'
|
||||
[[ "$(grep -c 'containerPort:' <<< "$deployment")" == 1 ]]
|
||||
for setting in 'name: http' 'runAsNonRoot: true' 'runAsUser: 65532' \
|
||||
'runAsGroup: 65532' 'readOnlyRootFilesystem: true' \
|
||||
'allowPrivilegeEscalation: false' 'type: RuntimeDefault' 'drop:' '- ALL' \
|
||||
'medium: Memory' 'sizeLimit: 16Mi' 'mountPath: /tmp' 'name: frontend-tmp'; do
|
||||
assert_contains "$deployment" "^[[:space:]]*(- )?$setting$"
|
||||
done
|
||||
service="$(resource Service "$name-svc" <<< "$rendered")"
|
||||
assert_contains "$service" 'port: 80$'
|
||||
assert_contains "$service" 'targetPort: http$'
|
||||
echo "OK ($mode): $name hardened image, security, scratch and named routing"
|
||||
done
|
||||
admin="$(resource Deployment admin <<< "$rendered")"
|
||||
assert_contains "$admin" 'containerPort: 80$'
|
||||
|
||||
legacy="$(helm template hub "$CHART_DIR" "${values[@]}" --set "mode=$mode" \
|
||||
--set kerberoshub.frontend.demoEnabled=true \
|
||||
--set kerberoshub.frontend.tag=v1.13.9 \
|
||||
--set kerberoshub.frontend.containerPort=80 \
|
||||
--set kerberoshub.frontend.securityContext=null \
|
||||
--set-json 'kerberoshub.frontend.volumes=[]' \
|
||||
--set-json 'kerberoshub.frontend.volumeMounts=[]')"
|
||||
for name in hub-frontend hub-frontend-demo; do
|
||||
deployment="$(resource Deployment "$name" <<< "$legacy")"
|
||||
assert_contains "$deployment" 'containerPort: 80$'
|
||||
assert_contains "$deployment" 'image: "ghcr.io/uug-ai/hub-frontend:v1.13.9"$'
|
||||
if grep -Eq 'securityContext:|mountPath: /tmp' <<< "$deployment"; then
|
||||
echo "Legacy frontend retains incompatible hardened runtime settings" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if [[ "${CLUSTER_SMOKE:-false}" == true ]]; then
|
||||
namespace=frontend-runtime-test
|
||||
kubectl create namespace "$namespace"
|
||||
helm template runtime "$CHART_DIR" "${values[@]}" --namespace "$namespace" \
|
||||
--set mode=ui --set ingress="" --set kerberoshub.frontend.demoEnabled=true \
|
||||
--show-only templates/kerberos-hub/hub-frontend.yaml \
|
||||
--show-only templates/kerberos-hub/hub-frontend-demo.yaml | kubectl apply -f -
|
||||
pid=""
|
||||
cleanup() {
|
||||
if [[ -n "$pid" ]]; then kill "$pid"; fi
|
||||
if [[ "$1" != 0 ]]; then
|
||||
kubectl -n "$namespace" get pods
|
||||
kubectl -n "$namespace" describe pods
|
||||
kubectl -n "$namespace" logs -l app=hub-frontend --all-containers=true
|
||||
kubectl -n "$namespace" logs -l app=hub-frontend-demo --all-containers=true
|
||||
fi
|
||||
}
|
||||
trap 'cleanup "$?"' EXIT
|
||||
for name in hub-frontend hub-frontend-demo; do
|
||||
kubectl -n "$namespace" rollout status "deployment/$name" --timeout=180s
|
||||
kubectl -n "$namespace" port-forward "service/$name-svc" 18080:80 &
|
||||
pid=$!
|
||||
for attempt in {1..30}; do
|
||||
if curl --fail --silent http://127.0.0.1:18080/healthz > /dev/null; then break; fi
|
||||
sleep 1
|
||||
done
|
||||
[[ "$(curl --fail --silent http://127.0.0.1:18080/healthz)" == ok ]]
|
||||
curl --fail --silent http://127.0.0.1:18080/assets/env.js | grep 'window' > /dev/null
|
||||
kill "$pid"
|
||||
wait "$pid" || [[ "$?" == 143 ]]
|
||||
pid=""
|
||||
echo "OK: $name serves health and generated runtime configuration through Service port 80"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Frontend runtime checks passed."
|
||||
@@ -60,10 +60,19 @@ assert_line() {
|
||||
fi
|
||||
}
|
||||
|
||||
without_frontends() {
|
||||
awk '
|
||||
/^---$/ { skip=0 }
|
||||
/^# Source: hub\/templates\/kerberos-hub\/(hub-frontend(-demo)?|hub-api)\.yaml$/ { skip=1 }
|
||||
!skip { print }
|
||||
'
|
||||
}
|
||||
|
||||
for mode in all pipeline ui; do
|
||||
defaults="$(helm template hub "$CHART_DIR" --set "mode=$mode")"
|
||||
if grep -q 'securityContext:' <<< "$defaults"; then
|
||||
echo "Default $mode mode unexpectedly enables security settings" >&2
|
||||
worker_defaults="$(without_frontends <<< "$defaults")"
|
||||
if grep -q 'securityContext:' <<< "$worker_defaults"; then
|
||||
echo "Default $mode mode unexpectedly enables worker security settings" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -111,8 +120,8 @@ for mode in all pipeline ui; do
|
||||
fi
|
||||
done
|
||||
expected="${#names[@]}"
|
||||
[[ "$(grep -c 'runAsUser: 65532' <<< "$hardened")" == "$expected" ]]
|
||||
[[ "$(grep -c 'fsGroup: 65532' <<< "$hardened")" == "$expected" ]]
|
||||
[[ "$(without_frontends <<< "$hardened" | grep -c 'runAsUser: 65532')" == "$expected" ]]
|
||||
[[ "$(without_frontends <<< "$hardened" | grep -c 'fsGroup: 65532')" == "$expected" ]]
|
||||
|
||||
# Image selection, Services, env and TLS mounts must not change.
|
||||
for pattern in '^[ ]+image:' '^[ ]+(port|targetPort|containerPort):' 'mongodb-tls'; do
|
||||
@@ -179,7 +188,7 @@ for mode in all ui pipeline; do
|
||||
[[ "$(resource Service oauth2-proxy-admin <<< "$legacy")" == "$(resource Service oauth2-proxy-admin <<< "$configured")" ]]
|
||||
[[ "$(grep 'image:' <<< "$legacy")" == "$(grep 'image:' <<< "$configured")" ]]
|
||||
# No other workload inherits Admin's container port or security settings.
|
||||
[[ "$(grep -c 'runAsUser: 65532' <<< "$configured")" == 1 ]]
|
||||
[[ "$(without_frontends <<< "$configured" | grep -c 'runAsUser: 65532')" == 1 ]]
|
||||
echo "OK ($mode): Admin opt-in port/security/tmpfs; legacy image, Service port, ingress and OAuth2-proxy preserved"
|
||||
done
|
||||
echo "All hardened Admin checks passed."
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CHART_DIR="${1:-charts/hub}"
|
||||
|
||||
resource() {
|
||||
local kind="$1" name="$2"
|
||||
awk -v kind="$kind" -v name="$name" '
|
||||
function emit() { if (matchedKind && matchedName) printf "%s", block }
|
||||
/^---$/ { emit(); block=""; matchedKind=0; matchedName=0 }
|
||||
{ block=block $0 "\n" }
|
||||
$0 == "kind: " kind { matchedKind=1 }
|
||||
$0 == " name: " name { matchedName=1 }
|
||||
END { emit() }
|
||||
'
|
||||
}
|
||||
|
||||
assert_line() {
|
||||
if ! grep -Eq -- "$2" <<< "$1"; then
|
||||
printf 'Missing expected Hub API setting: %s\n' "$2" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fixtures=(
|
||||
--set workflowConfiguration.enabled=true
|
||||
--set mongodb.tls.enabled=true
|
||||
--set mongodb.tls.existingSecret=mongodb-ca
|
||||
--set kerberoshub.api.serverTLS.enabled=true
|
||||
--set kerberoshub.api.serverTLS.secretName=api-tls
|
||||
)
|
||||
|
||||
for mode in all ui pipeline; do
|
||||
defaults="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${fixtures[@]}")"
|
||||
legacy="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${fixtures[@]}" \
|
||||
--set kerberoshub.api.securityContext=null \
|
||||
--set kerberoshub.api.podSecurityContext=null)"
|
||||
configured="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${fixtures[@]}" \
|
||||
--set kerberoshub.api.securityContext.runAsUser=1000 \
|
||||
--set kerberoshub.api.securityContext.runAsGroup=1000 \
|
||||
--set kerberoshub.api.podSecurityContext.fsGroup=1000)"
|
||||
helm lint "$CHART_DIR" --quiet --set "mode=$mode" "${fixtures[@]}"
|
||||
|
||||
if [[ "$mode" == pipeline ]]; then
|
||||
[[ -z "$(resource Deployment hub-api <<< "$defaults")" ]]
|
||||
[[ "$defaults" == "$legacy" && "$defaults" == "$configured" ]]
|
||||
echo "OK (pipeline): no Hub API resources or unrelated changes"
|
||||
continue
|
||||
fi
|
||||
|
||||
api="$(resource Deployment hub-api <<< "$defaults")"
|
||||
for pattern in \
|
||||
'^[ ]{6}securityContext:$' '^[ ]{8}fsGroup: 65532$' \
|
||||
'^[ ]{10}securityContext:$' '^[ ]{12}runAsUser: 65532$' \
|
||||
'^[ ]{12}runAsGroup: 65532$' '^[ ]{12}runAsNonRoot: true$' \
|
||||
'^[ ]{12}readOnlyRootFilesystem: true$' \
|
||||
'^[ ]{12}allowPrivilegeEscalation: false$' '^[ ]{12}capabilities:$' \
|
||||
'^[ ]{14}drop:$' '^[ ]{14}- ALL$' \
|
||||
'^[ ]{12}seccompProfile:$' '^[ ]{14}type: RuntimeDefault$' \
|
||||
'^[ ]+(- )?name: hub-api-tmp$' '^[ ]+(- )?emptyDir: \{\}$' \
|
||||
'^[ ]+(- )?mountPath: /tmp$' '^[ ]+secretName: mongodb-ca$' \
|
||||
'^[ ]+secretName: api-tls$' '^[ ]+mountPath: /etc/mongodb/tls$' \
|
||||
'^[ ]+mountPath: /etc/hub-api/tls$' \
|
||||
'^[ ]+mountPath: /etc/kerberos/configuration$' \
|
||||
'^[ ]+mountPath: /etc/kerberos/classifications$'; do
|
||||
assert_line "$api" "$pattern"
|
||||
done
|
||||
[[ "$(grep -c 'securityContext:' <<< "$api")" == 2 ]]
|
||||
old_api="$(resource Deployment hub-api <<< "$legacy")"
|
||||
if grep -q 'securityContext:' <<< "$old_api"; then
|
||||
echo "Legacy Hub API opt-out still renders a security context" >&2
|
||||
exit 1
|
||||
fi
|
||||
custom_api="$(resource Deployment hub-api <<< "$configured")"
|
||||
for field in runAsUser runAsGroup fsGroup; do
|
||||
assert_line "$custom_api" "^[ ]+$field: 1000$"
|
||||
done
|
||||
|
||||
# Only security settings change; preserve env, mounts, images and routing.
|
||||
for pattern in '^[ ]+image:' '^[ ]+(port|targetPort|containerPort):' \
|
||||
'^[ ]+(- )?(name|mountPath|secretName|value):'; do
|
||||
[[ "$(grep -E "$pattern" <<< "$defaults")" == "$(grep -E "$pattern" <<< "$legacy")" ]]
|
||||
[[ "$(grep -E "$pattern" <<< "$defaults")" == "$(grep -E "$pattern" <<< "$configured")" ]]
|
||||
done
|
||||
echo "OK ($mode): API security defaults, overrides, opt-out, scratch and TLS/config mounts"
|
||||
done
|
||||
Reference in New Issue
Block a user