Skip to content

External data stores

Configure self-hosted Dreadnode to use external PostgreSQL, ClickHouse, or S3 services.

Data stores are chart configuration, applied by a redeploy. Configure each store in a Helm overlay, under Data Stores in the Admin Console, or with the matching KOTS ConfigValues items.

Dreadnode installs PostgreSQL, ClickHouse, and MinIO in the cluster by default. You can replace any of them with a managed service. Configure network access, credentials, backups, and availability at the external service before you redeploy Dreadnode.

Commands on this page use $NAMESPACE. For Helm, set it to your release namespace. For Embedded Cluster, enter sudo ./dreadnode shell, then set it to kotsadm. See Access Kubernetes.

Set the external host and credentials, then disable the bundled PostgreSQL StatefulSet:

dreadnode-api:
endpoints:
database:
external: my-rds-instance.region.rds.amazonaws.com
credentials:
database:
source: externalSecret
secretName: dreadnode-external-pg
config:
database:
port: 5432
name: platform
user: admin
useSsl: true
useIamAuth: false
dreadnode-base:
postgresql:
enabled: false

Create the referenced Secret before upgrading:

Terminal window
kubectl -n "$NAMESPACE" create secret generic dreadnode-external-pg \
--from-literal=password='<db-password>'

For Amazon RDS IAM authentication, set useIamAuth: true and annotate the API service account with an IAM role that has rds-db:connect permission:

dreadnode-api:
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/dreadnode-api

In the Admin Console, enable Use AWS IAM authentication; the password field disappears. Put the service-account annotation under Advanced Helm Values. In a ConfigValues file, set postgres_use_iam.value to "1", omit postgres_password, and put the annotation in advanced_helm_values.

The bundled inference proxy shares this database

Section titled “The bundled inference proxy shares this database”

If you also run the bundled LiteLLM proxy, it keeps its model catalog in a litellm schema on the same database. On Embedded Cluster this is wired for you when you select an external database. On Helm, point it at the same host:

dreadnode-litellm:
database:
host: <db-hostname>
port: 5432
name: platform
user: <db-user>
useSsl: true
secretName: dreadnode-external-pg

The configured user needs CREATE SCHEMA on that database — the proxy creates the schema on first start. Without it, the proxy pod retries until the privilege is granted.

IAM authentication is the one combination that does not work. LiteLLM connects with a static password and cannot mint RDS tokens, so an external database in IAM mode cannot host it. Keep the bundled PostgreSQL for the proxy, use password authentication, or run LiteLLM outside the cluster and connect the platform to it. On Embedded Cluster the proxy toggle is hidden when IAM authentication is enabled, and the chart fails the deploy with this message if the combination is reached through Helm.

Set the external host and credentials, then disable the bundled ClickHouse StatefulSet:

dreadnode-api:
endpoints:
clickhouse:
external: my-clickhouse.example.com
credentials:
clickhouse:
source: externalSecret
secretName: dreadnode-external-ch
config:
clickhouse:
protocol: https
port: 8443
database: default
user: admin
dreadnode-base:
clickhouse:
enabled: false

Create the referenced Secret before upgrading:

Terminal window
kubectl -n "$NAMESPACE" create secret generic dreadnode-external-ch \
--from-literal=admin-password='<ch-password>'

Set the external endpoint and buckets, then disable bundled MinIO:

dreadnode-api:
endpoints:
s3:
internal: ''
external: https://s3.us-east-1.amazonaws.com
credentials:
s3:
source: static # static | iam | minio
secretName: dreadnode-external-s3
config:
s3:
region: us-east-1
buckets:
pythonPackages: my-packages-bucket
orgData: my-org-data-bucket
userDataLogs: my-logs-bucket
sdk:
userDataRoleArn: arn:aws:iam::123456789012:role/dreadnode-user-data
stsDurationSeconds: 3600
dreadnode-base:
minio:
enabled: false

Create the referenced Secret before upgrading:

Terminal window
kubectl -n "$NAMESPACE" create secret generic dreadnode-external-s3 \
--from-literal=accessKeyId='<access-key-id>' \
--from-literal=secretAccessKey='<secret-access-key>'

Leave internal empty for AWS S3. For another S3-compatible service, set it to the endpoint that the API can reach. external is the endpoint returned to clients for presigned URLs and must be reachable from their networks.

For Helm installs using IAM credentials, set source: iam, omit the credential Secret, and configure workload identity on the API service account. The dedicated Embedded Cluster surface supports static access keys only; use the Helm install path when the API itself must authenticate to S3 through workload identity.

userDataRoleArn is the role the API assumes when it creates scoped workspace credentials. It must trust the API identity and allow access to the organization data bucket. stsDurationSeconds must be no greater than 3600 — the API rejects larger values at startup — and the role’s MaxSessionDuration must be at least the configured value. Keep Scoped Credential Lifetime at or below 3600 in the Admin Console and ConfigValues file.

The dedicated Embedded Cluster fields cover the endpoint, credentials, user-data role, region, and credential lifetime. Only bucket-name overrides need Advanced Helm Values; that document merges after the dedicated fields during deployment.

Redeploy Dreadnode, then watch the API migration and startup logs:

Terminal window
kubectl -n "$NAMESPACE" logs deploy/dreadnode-api -c migrations
kubectl -n "$NAMESPACE" logs deploy/dreadnode-api

Connection, authentication, and bucket errors appear during startup. When the API is ready, verify the platform health endpoint:

Terminal window
curl https://dreadnode.example.com/api/v1/health

Use the configured scheme and domain. Back up external services with their native tools; Dreadnode does not manage their backup lifecycle.