Skip to content

Tenant Helm Chart Audit

Audit methodology: this document captures the expected classification based on chart inspection. Actual helm template runs and diff-vs-classification are required in pre-release validation. Any object found in a real render that isn't listed here becomes a review gate.

Scope of audit

Charts to audit:

UpstreamUpstream sourceTarget version
Wazuhwazuh/wazuh-kubernetes Helm chart (community) or official OCI chartLatest stable 4.x supporting single-manager HA
TheHiveStrangeBee/thehive4 Helm chart or community5.x
CortexTheHive-Project/Cortex Helm chart or community3.x
MISPdeferred a future release

For each chart we vendor the manifest templates (with patches if needed) as subchart dependencies of charts/soctalk-tenant/: Version pinning is strict. Chart.yaml uses exact semver with digest (OCI) where available.

Classification rules

For every rendered object, classify as:

  • NS-OK: namespace-scoped object that lives inside tenant-<slug>. Safe, expected.
  • CLUSTER-PREREQ: cluster-scoped object that must be installed once by the soctalk-system chart or documented as MSSP cluster-admin responsibility. Tenant chart must not re-install these per tenant.
  • FORBIDDEN: object type or capability we refuse to allow in a tenant chart even when upstream declares it (e.g., cluster-wide ClusterRoleBinding giving Wazuh privileged access). Must be patched out.
  • PATCH: keep the object but modify it (e.g., drop hostPath volumes, remove privileged securityContext, reduce default resource requests).

Expected classification per upstream chart

Wazuh

Wazuh charts typically render:

ObjectExpected classNotes
Deployment / StatefulSet (manager, indexer, dashboard)NS-OKCore stack pods
Service (manager API, indexer, dashboard, agent ingress 1514/1515)NS-OK
ConfigMap (ossec.conf, indexer.yml, dashboard.yml)NS-OK
Secret (admin pw, mutual TLS certs)NS-OKSeeded per-tenant at provisioning
PersistentVolumeClaim (indexer data, manager data)NS-OKSize set via tenant values
ServiceAccountNS-OKPer-tenant SA
Role + RoleBinding (for leader election if used)NS-OKNamespace-scoped only
NetworkPolicy (chart-provided)PATCHReplace with SocTalk-rendered NP for consistent posture; don't allow upstream defaults to override default-deny
StorageClass referencesCLUSTER-PREREQMSSP must provide a dynamic provisioner; storageClassName is a values input
IngressPATCH or disableWazuh's agent protocol on 1514 is not standard TLS, so HTTP/HTTPS Ingress is not appropriate. Strip any Ingress resources. For the agent-ingress Service, the chart should render the variant matching tenant.wazuhIngress.mode: a LoadBalancer Service for per-tenant LB IPs (default) or a ClusterIP Service when the install uses the in-cluster HAProxy fallback. See Wazuh Ingress.
PodSecurityPolicy / SecurityContextConstraintsCLUSTER-PREREQ if present; forbidden otherwisePSP is deprecated; if present, remove. OpenShift SCC is not in scope for this release
CustomResourceDefinitionFORBIDDEN in tenant chartIf the chart tries to install a CRD, move to soctalk-system chart or document as prerequisite
ClusterRole / ClusterRoleBindingFORBIDDEN in tenant chartNever install cluster-wide RBAC from a tenant namespace
Privileged/host-network/hostPath podsFORBIDDEN; patch outWazuh manager doesn't require these for standard operation; indexer doesn't either. If a subchart demands hostPath for logs, patch to emptyDir + PVC
PodDisruptionBudgetNS-OKOptional; depends on Wazuh HA mode. Single-manager topology may skip

Expected patches:

  1. Remove any ClusterRole/ClusterRoleBinding from rendered output.
  2. Remove any cluster-scoped resources (ValidatingWebhookConfiguration, etc.).
  3. Render the agent-ingress Service to match tenant.wazuhIngress.mode (LoadBalancer for per-tenant LB IPs, ClusterIP for the in-cluster HAProxy fallback).
  4. Strip Ingress resources. Wazuh dashboards are exposed via a separate SocTalk-managed path; the agent protocol on 1514 is not HTTP, so K8s Ingress does not apply.
  5. Ensure all pods have securityContext: { runAsNonRoot: true, allowPrivilegeEscalation: false }; patch if upstream sets otherwise.
  6. Pin images to digests, not latest.

TheHive

ObjectExpected classNotes
Deployment (TheHive app)NS-OK
StatefulSet (Cassandra or external-DB-backed variants)NS-OKuses embedded Cassandra; external Cassandra is a future release option
Service (TheHive web + API on 9000)NS-OK
ConfigMap (application.conf)NS-OKPer-tenant config rendered by SocTalk
Secret (admin credentials, Cortex API key for this tenant's Cortex)NS-OK
PersistentVolumeClaim (Cassandra data, index data)NS-OK
ServiceAccountNS-OK
IngressPATCH or disableSame as Wazuh: dashboard exposure via MSSP-side proxy with tenant routing, not per-namespace Ingress
Job (bootstrap / init)NS-OKOK for first-run cert generation / DB init
CustomResourceDefinitionFORBIDDEN: must be in soctalk-system chart if present
ClusterRole / ClusterRoleBindingFORBIDDEN in tenant chart

Expected patches:

  1. Strip Ingress; use ClusterIP Services only.
  2. Pin Cassandra to digest; set resource limits matching sizing sizing.
  3. Ensure init Job is idempotent (re-runs harmless).
  4. No CRD dependencies.

Cortex

ObjectExpected classNotes
Deployment (Cortex app)NS-OK
StatefulSet (Elasticsearch or compatible index)NS-OKembedded ES; external ES is a future release
Service (Cortex API on 9001)NS-OK
ConfigMap (application.conf, analyzer lists)NS-OK
Secret (admin, inter-service tokens)NS-OK
PersistentVolumeClaimNS-OK
ServiceAccountNS-OK
Job (analyzer registration)NS-OK if idempotent
IngressPATCH or disable
PrivilegedContainer (Docker-in-Docker for analyzer sandboxing, if upstream uses this pattern)FORBIDDEN: patchCortex analyzers that require Docker sandboxing are out of scope for this release. Use only analyzers that run in-process or call out to sandboxed external services

Known risk: Cortex historically runs some analyzers as subprocesses or Docker containers. This release limits to "pure-code" analyzers that don't require privileged host access. Analyzer list is pinned in values; analyzers requiring Docker-in-Docker are rejected at provisioning time.

Cluster prerequisites list (rolled into install guide + soctalk-system chart prereq check)

Following the audit, these are out-of-scope for the tenant chart and must exist in the cluster before soctalk-tenant is applied to any namespace:

PrerequisiteWhysource
K3s 1.30+ (or compatible K8s 1.30+)Baseline plus ValidatingAdmissionPolicy v1MSSP responsibility
NP-enforcing CNI (Cilium primary, Calico alternate)Isolation enforcementMSSP responsibility
cert-managerTLS for Ingress, per-tenant Wazuh cert issuanceMSSP responsibility; install guide provides helm install recipe
Ingress controller (Traefik default in K3s, ingress-nginx common)MSSP UI + Customer UI + per-tenant WebUI routingMSSP responsibility
Dynamic StorageClass (local-path, longhorn, cloud-provider CSI, etc.)PVC provisioningMSSP responsibility
VolumeSnapshotClass if using CSI snapshotsBackup/restore runbook (docs only)Optional

The soctalk-system chart includes a pre-install hook (helm.sh/hook: pre-install) that verifies:

  • NP-enforcing CNI active (probes for Cilium or Calico markers)
  • cert-manager CRDs present
  • Default StorageClass set

Hook fails fast with actionable error message if any are missing.

Patching strategy

Two paths:

  1. Values-driven overrides: prefer upstream chart values that disable the unwanted object (e.g., ingress.enabled: false, networkPolicy.enabled: false if upstream's is looser than ours, rbac.create: true scoped to namespace only).
  2. Kustomize-style overlay (Helm's kustomize integration or post-render hook) for objects that can't be disabled via values: strip ClusterRoles, remove hostPath volumes, set securityContext.

We vendor upstream charts as pinned subchart dependencies in charts/soctalk-tenant/charts/, not as helm repo references. This lets us:

  • Pin to exact versions (no upstream surprise updates)
  • Apply patches as needed without depending on upstream PR acceptance
  • Sign our bundle as a single artifact (a future release when cosign lands)

If upstream doesn't meet our needs after patches, the fallback is to write SocTalk-native templates that call the same container images with our own manifests. pre-release validation decides this per chart.

Known unknowns (pre-release validation resolves)

Items that require actual helm template runs + inspection to confirm:

  • [ ] Wazuh: does the chosen chart version require CRDs for operator-driven deployment? If yes, move CRDs to soctalk-system chart.
  • [ ] TheHive: does Cassandra require StorageClass with specific features (e.g., RWO only, minimum IOPS)? Document in sizing sizing.
  • [ ] Cortex: what analyzers are enabled by default, and do any require Docker-in-Docker? Produce an allowlist of-safe analyzers.
  • [ ] All charts: any Job or CronJob that runs with ServiceAccount beyond the namespace? Patch to ns-local SA.
  • [ ] All charts: any initContainer with privileged: true or hostPath mounts? Patch or replace.
  • [ ] All charts: default resources.requests and limits: Compare to sizing sizing profile; override in values where needed.

Each open item becomes a pre-release validation checklist entry. The spike's output is a filled-in classification table and the patched chart ready for charts/soctalk-tenant/charts/.

Output artifact (produced before shipping)

The spike produces:

  1. Classified object inventory (filling in section 3 tables with actual rendered objects).
  2. Patched chart bundles checked into charts/soctalk-tenant/charts/wazuh/, thehive/, cortex/ with pinned versions.
  3. Cluster prerequisites list merged into install guide.
  4. Analyzer allowlist for Cortex (safe-only set).
  5. Values schema fragment for each subchart (inputs SocTalk will provide per-tenant).

The spike's completion is a prerequisite for Helm chart implementation.

Released under the Apache 2.0 License.