Configuration reference

All configuration is supplied through Helm values. Read a chart's defaults with helm show values ./md-cluster-services (and the same for md-cluster-instances), then override what you need in your own values file, which is passed to both charts.

Only the keys you set are overridden — everything else falls back to the chart default. Keys under secrets: are rendered into the mdcluster-secrets Secret, keys under env: into the mdcluster-config ConfigMap, and both are exposed as environment variables to the MetaDefender Cluster Control Center, MetaDefender Cluster Identity Service, MetaDefender Cluster File Storage and MetaDefender Cluster Worker pods across both releases. The bundled PostgreSQL, Redis and RabbitMQ pods do not receive them — they read only the few credential values they need.

Images

Key

Default

Description

DOCKER_REPO

opswat/metadefendercluster-debian

Registry and repository. Images resolve to <DOCKER_REPO>:<component>-<version>.

MDCLS_VERSION

2.8.0

Default image tag version for every component.

imagePullPolicy

IfNotPresent

Pull policy for the five MetaDefender Cluster images. The bundled PostgreSQL, Redis and RabbitMQ ignore it — each has its own pullPolicy key.

imagePullSecrets

(unset)

List of pull secrets, e.g. - name: regcred. Required for private registries. Applied to the MetaDefender Cluster pods only, not the bundled infrastructure — if you mirror postgres:16 and friends into a private registry, they will not authenticate.

The five images pulled are control-center, identity-service, file-storage, worker and installers. The installers runs only as the MetaDefender Cluster Control Center's initContainer.

Per-component settings

Key

Description

version

Image tag override for this component, e.g. 2.8.0. Defaults to MDCLS_VERSION. Note that control-center.version also pins the installers initContainer image — the installer bundle has no separate version knob and always matches the MetaDefender Cluster Control Center tag.

replicas

Desired pod count. Ignored for control-center and identity-service, which are singletons.

imagePullPolicy

Overrides the chart-wide policy.

resources

Standard requests and limits. See Resource requirements.

nodeSelector

Standard node selection.

affinity

Standard affinity and anti-affinity rules.

tolerations

Standard taint tolerations.

probes

Per-phase probe tuning. See Health probes.

terminationGracePeriodSeconds

Graceful shutdown window. Kubernetes default (30s) unless set; MetaDefender Cluster Workers default to 1800.

Structural properties — Deployment versus StatefulSet, rollout strategy, pod security context, and whether a Service is headless — are fixed in the templates and not configurable. The Service settings that are exposed are listed below.

Service settings

Component

Key

Default

Notes

control-center

service.type

NodePort

ClusterIP, NodePort or LoadBalancer.

control-center

service.nodePort

(auto-assigned)

Only applied when set; otherwise Kubernetes picks a port from 30000–32767.

identity-service

service.type

(unset — Kubernetes defaults to ClusterIP)

Rarely changed — nothing outside the cluster needs it.

workers.api-gateway

service.type

(unset → ClusterIP)

LoadBalancer to publish the file-submission endpoint.

workers.api-gateway

service.clusterIP

None

The chart ships this as headless. Set to null to remove the headless setting before choosing a type.

workers.api-gateway

service.port

listenPort

External port; the target port is always listenPort.

The api-gateway Service is created by default — the chart ships service.clusterIP: None, so it exists as a headless Service until you change it. No other MetaDefender Cluster Worker may have one: setting service: on ometascan or callback-service fails the Helm render with an explicit error.

MetaDefender Cluster Worker specific settings

Key

Default

Description

listenPort

per instance

Port the deployed instance listens on, passed to the pod as WORKER_INSTANCE_PORT. ometascan 8008, api-gateway 8899, callback-service 8894. Required in practice but not validated — omit it when adding a new MetaDefender Cluster Worker entry and the render still succeeds, with an invalid instance port that leaves the MetaDefender Cluster Worker unable to deploy its instance.

logLevel

info

Log level of the deployed instance.

isolate.enabled

true

Isolate the instance before undeploying it on shutdown, so in-flight work drains.

isolate.timeout

1600

Seconds to wait for isolation to complete. terminationGracePeriodSeconds must exceed this plus GLOBAL_WAIT_TIMEOUT. 0 means no timeout, not "skip isolation" — see Graceful shutdown.

upgradeInstances

inherits the top-level flag

Run this instance's pre-upgrade Job on helm upgrade.

terminationGracePeriodSeconds

1800

Graceful shutdown window. Longer than other components because of isolation and undeploy.

upgradeInstances

false

Global opt-in to the per-instance pre-upgrade Jobs. Only takes effect on helm upgrade. See Upgrade and uninstall.

The map key under worker: is the instance type. Renaming ometascan to something else deploys a different (non-existent) instance type, not a renamed scan engine.

Bundled infrastructure

Key

Default

Description

postgres.enabled

true

Set to false when using an external PostgreSQL.

postgres.image

postgres:16


postgres.pullPolicy

IfNotPresent

These three components ignore the chart-wide imagePullPolicy — set their own if you mirror the upstream images into a private registry.

postgres.port

5432


postgres.database

postgres

Database created on first start. The four cluster databases are created separately by the MetaDefender Cluster Control Center.

postgres.maxConnections

200

Raise this if you run many replicas.

postgres.persistence.enabled

false

Enable for any real deployment.

postgres.persistence.size

8Gi


postgres.persistence.storageClassName

""

Empty uses the cluster default.

postgres.resources

{}


redis.enabled

true

Set to false when using an external Redis.

redis.image

redis:8


redis.pullPolicy

IfNotPresent


redis.port

6379


redis.resources

{}


rabbitmq.enabled

true

Set to false when using an external RabbitMQ.

rabbitmq.image

rabbitmq:4.2.5-management


rabbitmq.pullPolicy

IfNotPresent


rabbitmq.amqpPort

5672


rabbitmq.managementPort

15672


rabbitmq.resources

{}


file-storage.replicas

1

Number of MetaDefender Cluster File Storage pods. The chart builds the MetaDefender Cluster Control Center's endpoint list from this value at render time, so changing it requires helm upgrade — see Scaling.

file-storage.persistence.enabled

false

Enable for any real deployment. One PVC per replica.

file-storage.persistence.size

100Gi

Per replica, not total.

file-storage.persistence.storageClassName

(unset)


These three are single-pod deployments suitable for evaluation only. See High availability.

Secrets

Key

Default

Description

CONTROL_CENTER_ENCRYPTION_KEY

(empty)

Required. Must be exactly 32 characters — it is used directly as an AES-256 key, and the length is never validated. Empty stops the container immediately. Any other wrong length lets it launch but breaks every service registration, so the MetaDefender Cluster Control Center never becomes ready and ends up in CrashLoopBackOff with Failed to encrypt configuration in its log.

ADMIN_APIKEY

(empty)

Required. API key used for administrative and internal service calls.

IDENTITY_CONNECTION_KEY

1234abcd

Shared key between MetaDefender Cluster Control Center and MetaDefender Cluster Identity Service. Change this.

FILE_STORAGE_CONNECTION_KEY

1234abcd

Shared key between MetaDefender Cluster Control Center and MetaDefender Cluster File Storage. Change this.

WORKER_CONNECTION_KEY

1234abcd

Shared key workers register with. Change this.

ADMIN_USER

admin

Bootstrap administrator account.

ADMIN_PASSWORD

admin

Change this.

ADMIN_EMAIL

admin@admin


LICENSE_KEY

(empty)

Optional. See Licensing in Kubernetes.

CONTROL_CENTER_DB_USER

postgres

MetaDefender Cluster Control Center database credentials. Also used as POSTGRES_USER by the bundled PostgreSQL.

CONTROL_CENTER_DB_PASSWORD

postgres

Also used as POSTGRES_PASSWORD by the bundled PostgreSQL.

IDENTITY_DB_USER / IDENTITY_DB_PASSWORD

postgres

MetaDefender Cluster Identity Service database credentials.

DATALAKE_USER / DATALAKE_PASSWORD

postgres

Datalake database credentials.

WAREHOUSE_USER / WAREHOUSE_PASSWORD

postgres

Data warehouse database credentials.

RABBITMQ_USER / RABBITMQ_PASSWORD

admin

Broker credentials.

REDIS_USER / REDIS_PASSWORD

(unset)

Optional; only needed if your Redis requires authentication.

The connection keys are shared secrets, not per-service passwords: both sides of each link read the same value. Changing one after installation requires restarting both services involved.

The bundled PostgreSQL takes its superuser credentials from CONTROL_CENTER_DB_USER and CONTROL_CENTER_DB_PASSWORD, and that is the only role it creates. When using the bundled database, set all four credential pairs to the same values. If they differ, the MetaDefender Cluster Identity Service cannot log in and never becomes ready — which in turn crash-loops the MetaDefender Cluster Control Center — while the datalake and warehouse components stay unhealthy so the MetaDefender Cluster Control Center's own readiness check never passes.

Two consequences worth knowing before you install:

  • These credentials are applied only when PostgreSQL initialises an empty data directory. With postgres.persistence.enabled: true, changing CONTROL_CENTER_DB_PASSWORD on a later helm upgrade does not change the password inside the database, and every service then fails to authenticate. Change it with ALTER ROLE in PostgreSQL, or delete the postgres PVC to start fresh.

  • An external PostgreSQL has no such coupling. The four pairs may name four different roles, as long as each can reach its database and one can create databases.

Environment

Rendered into the mdcluster-config ConfigMap. Defaults point at the bundled infrastructure.

Some variables are set directly on the pod by the templates, and a container-level value always wins over the ConfigMap. Setting these under env: is silently ignored on the very pod that reads them:

  • FILE_STORAGE_SERVICES on the MetaDefender Cluster Control Center — derived from file-storage.replicas.

  • WORKER_INSTANCE_TYPE, WORKER_INSTANCE_PORT, WORKER_INSTANCE_LOG_LEVEL, WORKER_ISOLATE_INSTANCE and WORKER_ISOLATE_INSTANCE_TIMEOUT on worker pods — set these through the per-worker keys listenPort, logLevel and isolate.*.

MetaDefender Cluster Control Center

Key

Default

Description

CONTROL_CENTER_HOST

control-center

Also becomes the Service name.

CONTROL_CENTER_PORT

8892

Service port other components connect to.

CONTROL_CENTER_LISTEN_PORT

8892

Port inside the container.

CONTROL_CENTER_DB_HOST

postgres


CONTROL_CENTER_DB_PORT

5432


CONTROL_CENTER_LOG_LEVEL

info

MetaDefender Cluster Control Center service log level.

ADD_WORKER_RATE_LIMIT

32

Rate limit.

CONTROL_CENTER_LISTEN_HOST

Not supported. Unlike the MetaDefender Cluster Identity Service and MetaDefender Cluster File Storage equivalents, this is accepted but ignored — the MetaDefender Cluster Control Center always binds all interfaces. Setting it has no effect and produces no warning.

MetaDefender Cluster Identity Service

Key

Default

Description

IDENTITY_HOST

identity-service

Also becomes the Service name.

IDENTITY_PORT

8891


IDENTITY_LISTEN_HOST

*

Bind address.

IDENTITY_LISTEN_PORT

8891


IDENTITY_DB_HOST

postgres


IDENTITY_DB_PORT

5432


IDENTITY_LOG_LEVEL

info

MetaDefender Cluster Identity Service log level.

MetaDefender Cluster File Storage

Key

Default

Description

FILE_STORAGE_SERVICE_NAMESPACE

file-storage

Headless Service name; forms each replica's DNS name as file-storage-<n>.<this>.

FILE_STORAGE_LISTEN_HOST

*

Bind address.

FILE_STORAGE_LISTEN_PORT

8890


FILE_STORAGE_LOG_LEVEL

info

MetaDefender Cluster File Storage log level. Applies to every replica.

FILE_STORAGE_MIN_REPLICA

1

Minimum copies of each file that must be written successfully — and the minimum number of MetaDefender Cluster File Storage instances that must be healthy. See the warning below.

FILE_STORAGE_MAX_REPLICA

1

How many copies of each file to write. Must be ≤ file-storage.replicas.

FILE_STORAGE_REPLICA_COUNT

1

Legacy single-value fallback for the two settings above. Deprecated — set the two explicitly instead.

These are the file copy settings: FILE_STORAGE_MAX_REPLICA: 2 means every file is written to two MetaDefender Cluster File Storage instances, and each write picks up to that many instances. FILE_STORAGE_MIN_REPLICA: 2 means a write that reaches only one instance fails.

FILE_STORAGE_MIN_REPLICA also gates the MetaDefender Cluster Control Center's own readiness. If fewer than this many MetaDefender Cluster File Storage instances are healthy, the MetaDefender Cluster Control Center reports MetaDefender Cluster File Storage unhealthy, /readyz stops returning 200, and it refuses writes and file lookups outright — it does not merely degrade.

Because the MetaDefender Cluster Control Center's own startup waits for its /readyz to return 200, setting this higher than the number of replicas you can keep healthy will crash-loop the MetaDefender Cluster Control Center on its next restart. Raise it only alongside enough replicas to sustain it.

FILE_STORAGE_MAX_REPLICA is validated against the number of MetaDefender Cluster File Storage instances registered with the MetaDefender Cluster Control Center, and only at the moment the setting is applied. Removing instances later does not re-validate it, so the ≤ file-storage.replicas rule can silently stop holding.

The two resolve independently, each in this order: its own value, then FILE_STORAGE_REPLICA_COUNT, then 1. An empty string counts as unset. The chart sets both explicitly, so the fallback only applies if you remove them. See Scaling.

MetaDefender Cluster Workers

Key

Default

Description

WORKER_SERVICE_NAMESPACE

worker

Shared headless Service name for all MetaDefender Cluster Worker instances. It is also the DNS suffix each MetaDefender Cluster Worker registers itself under (<pod>.<this>), which is the identity the MetaDefender Cluster Control Center tracks it by — changing it after install leaves the old MetaDefender Cluster Worker entries stale.

WORKER_LISTEN_PORT

8893

MetaDefender Cluster Worker agent port. Distinct from each instance's listenPort.

WORKER_PLATFORM

(not set by the chart; the MetaDefender Cluster Worker image defaults to Linux)

License platform to match when activating. Add it under env: to override.

WORKER_LISTEN_HOST

*

Bind address of the MetaDefender Cluster Worker agent.

WORKER_LOG_LEVEL

info

The MetaDefender Cluster Worker agent's own log level.

Infrastructure endpoints

Key

Default

Description

DATALAKE_SERVICES

postgres:5432

Comma-separated host:port list.

WAREHOUSE_SERVICES

postgres:5432

Comma-separated host:port list.

REDIS_SERVICES

redis:6379

Comma-separated host:port list. Two constraints: use a dedicated Redis, because the scan engines issue FLUSHDB; and with a clustered Redis point this at a single writable endpoint, because MetaDefender Cluster is not Sentinel-aware. See Redis.

RABBITMQ_SERVICES

rabbitmq:5672

Comma-separated host:port list.

Global

Key

Default

Description

GLOBAL_WAIT_TIMEOUT

150

Seconds any service waits for a dependency before failing. Raise it on slow clusters or when external databases are slow to accept connections.

Log levels

Accepted values, least to most severe: dump, debug, info, warning, error. Each service has its own key — CONTROL_CENTER_LOG_LEVEL, IDENTITY_LOG_LEVEL, FILE_STORAGE_LOG_LEVEL and WORKER_LOG_LEVEL, all defaulting to info. Logs go to the container's stdout, so kubectl logs is the only collection step needed.

Note the distinction on MetaDefender Cluster worker pods: WORKER_LOG_LEVEL sets the agent's level for every MetaDefender Cluster worker.

TLS certificates

MetaDefender Cluster Identity Service, MetaDefender Cluster File Storage and the MetaDefender Cluster Worker agents serve HTTPS. By default each generates a self-signed certificate for its own hostname at startup, so no configuration is needed for internal traffic.

To supply your own certificates, mount the PEM files into the pod and point both keys of a pair at the in-container paths. Setting only one key of a pair fails the container at startup.

Key

Default

Description

IDENTITY_CERTIFICATE_PATH / IDENTITY_PRIVATE_KEY_PATH

(unset)

MetaDefender Cluster Identity Service PEM certificate and private key. Leave both unset to auto-generate.

FILE_STORAGE_CERTIFICATE_PATH / FILE_STORAGE_PRIVATE_KEY_PATH

(unset)

Same, for MetaDefender Cluster File Storage. The same paths apply to every replica.

WORKER_CERTIFICATE_PATH / WORKER_PRIVATE_KEY_PATH

(unset)

Same, for the MetaDefender Cluster Worker agents.

The chart does not create volume mounts for these files. You must add the mount yourself, or leave the keys unset and accept the generated certificates.

FILE_STORAGE_PATH is deliberately not configurable — it must stay at the PVC mount point, /app/storage.

Use external infrastructure

To run against existing PostgreSQL, Redis or RabbitMQ instead of the bundled single-pod deployments, disable the bundled component and repoint the endpoint. Both halves are required — disabling without repointing leaves the services pointed at a hostname that no longer resolves.

# Disable the bundled infrastructure postgres: { enabled: false } redis: { enabled: false } rabbitmq: { enabled: false } secrets: # Credentials for the external instances CONTROL_CENTER_DB_USER: '<db-user>' CONTROL_CENTER_DB_PASSWORD: '<db-password>' IDENTITY_DB_USER: '<db-user>' IDENTITY_DB_PASSWORD: '<db-password>' DATALAKE_USER: '<db-user>' DATALAKE_PASSWORD: '<db-password>' WAREHOUSE_USER: '<db-user>' WAREHOUSE_PASSWORD: '<db-password>' RABBITMQ_USER: '<rabbitmq-user>' RABBITMQ_PASSWORD: '<rabbitmq-password>' # REDIS_USER: '<redis-user>' # only if your Redis requires auth # REDIS_PASSWORD: '<redis-password>' env: CONTROL_CENTER_DB_HOST: 'my-postgres' CONTROL_CENTER_DB_PORT: 5432 IDENTITY_DB_HOST: 'my-postgres' IDENTITY_DB_PORT: 5432 DATALAKE_SERVICES: 'my-postgres:5432' WAREHOUSE_SERVICES: 'my-postgres:5432' REDIS_SERVICES: 'my-redis:6379' RABBITMQ_SERVICES: 'my-rabbitmq:5672'

Two requirements on the external PostgreSQL:

  • The role must be able to create databases. The MetaDefender Cluster Control Center creates and migrates md_cluster_control_center, md_cluster_datalake, md_cluster_datawarehouse and md_cluster_identity_service on first start.

  • Service names in a different namespace must be fully qualified: <service>.<namespace>.svc.cluster.local.

For clustered external infrastructure with worked examples, see High Availability.