Compare commits

..
Author SHA1 Message Date
KilianandClaude Opus 5.5 2e018357d8 hub: audit destination credentials inline only (0.175.0) (#227)
Destinations take credentials only as inline values: s3.accessKey /
s3.secretKey, bearerToken and secretHeaders.<name>.value. credentialsSecret,
bearerTokenSecret and secretHeaders secretName/secretKey are removed from the
values and README and fail the render with the inline field to use.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:03:44 +01:00
KilianandClaude Opus 5.5 0b9d07339f hub: audit destination field reference, enabled by default (0.174.0) (#226)
- README documents every destination field in its own row: required or
  optional, default and limits. Adds kerberoshub.audit.resources and
  topologySpreadConstraints.
- values.yaml examples mark each field required/optional with its default;
  kerberoshub.audit.resources is a real key next to replicas.
- A destination without `enabled` is now enabled (it rendered null, which
  hub-audit reads as false). `enabled: false` still pauses it.
- Empty or one-sided s3.accessKey/s3.secretKey fail the render instead of
  falling back to the pod's AWS identity, like an empty bearerToken.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 11:29:59 +01:00
KilianandClaude Opus 5.5 78cf3c7e2b hub: flag for the Users (preview) organisation tab (0.173.0) (#225)
Adds kerberoshub.frontend.features.organisations.membersAccessPreviewEnabled
(default "false"), setting FEATURE_MEMBERS_ACCESS_PREVIEW_ENABLED on the
frontend and the demo frontend.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 10:45:38 +01:00
KilianandClaude Opus 5.5 f0b79bea0c docs(hub): plain wording for audit destination credentials (0.172.1) (#224)
Describe inline audit destination credentials on their own terms in the
values comments and the README.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 10:44:59 +01:00
KilianandClaude Opus 5.5 535ddc847d hub: inline credentials for every audit destination (0.172.0) (#223)
Audit destinations now take credentials as plain values, like the other
Hub services: s3.accessKey / s3.secretKey on S3 destinations, bearerToken
and secretHeaders.<name>.value on webhooks. The chart stores them in a
Secret hub-audit-<id>-credentials and mounts it where hub-audit already
reads credential files, so no hub-audit change is needed and changed
values are picked up without a restart.

A shared hub.audit.destinations helper resolves inline values for the
ConfigMap, the Deployment volumes and the Secret template. Referencing an
existing Secret and credentialsSecret.create keep working and render
unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 09:26:05 +01:00
KilianandClaude Opus 5.5 1c1593a8a0 hub: optionally create the hub-audit S3 credentials Secret (0.171.0) (#222)
credentialsSecret.create: true makes the chart render the Secret from
credentialsSecret.accessKeyId / secretAccessKey, so the audit S3 keys can
live in values like the chart's other credentials. The default stays
"bring your own Secret".

Inline keys without create: true now fail instead of being ignored, two
destinations creating the same Secret fail, and the docs spell out that
accessKeyIdKey / secretAccessKeyKey name keys inside the Secret.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 08:33:48 +01:00
Cédric Verstraeten 5dfaaf0363 Merge pull request #221 from kerberos-io/fix/hub-api-security-context
Add hardened Hub API security contexts (0.170.1)
2026-11-04 15:47:29 +01:00
9 changed files with 191 additions and 49 deletions
+1 -1
View File
@@ -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.170.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
+23 -1
View File
@@ -792,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"` |
@@ -901,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`. | `{}` |
@@ -911,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"` |
+63
View File
@@ -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
@@ -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 }}
@@ -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
@@ -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
+42 -42
View File
@@ -655,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'
@@ -860,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.
@@ -886,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