Install OpenSourceOM on Kubernetes
The chart in deploy/helm/opensourceom installs the API Deployment and, by
default, a Postgres StatefulSet. Chart version and appVersion are
0.4.0. When bundled Postgres is enabled, an init container named
wait-db runs pg_isready against
{{release}}-opensourceom-postgres. A second init container runs
om migrate. The main container runs om serve, which applies any
migrations still pending. api.autoMigrate (default true) sets
OM_AUTO_MIGRATE. Readiness and liveness probe GET /v1/health.
With an external database,
wait-db is omitted and migrate still runs, so that host must
accept connections before the pod can become Ready.
Install
postgres.password is required. The image repository
defaults to ghcr.io/opensourceom/core. An empty image.tag falls
back to the chart appVersion (0.4.0). Set the tag when you are not
running that release.
docker build -t ghcr.io/opensourceom/core:0.4.0 .
helm install om deploy/helm/opensourceom \
--set postgres.password='change-me' \
--set image.tag=0.4.0
Load that image into the cluster if you are not pushing to GHCR. Published images live at
ghcr.io/opensourceom/core.
The Service is ClusterIP on port 8080. The release name om yields a
Service named om-opensourceom:
kubectl port-forward svc/om-opensourceom 8080:8080 Values
| Value | Default | Role |
|---|---|---|
replicaCount | 1 | API replicas. They share one database. |
image.repository | ghcr.io/opensourceom/core | API image. |
image.tag | empty, then chart appVersion (0.4.0) | Image tag. Set it when the cluster should not run 0.4.0. |
service.type / service.port | ClusterIP / 8080 | How the API is reached inside the cluster. |
api.env | production | Written to OM_ENV. |
api.autoMigrate | true | Written to OM_AUTO_MIGRATE. om serve applies pending migrations. The init container still runs om migrate first. |
api.smtp.host / api.smtp.port / api.smtp.from | empty / 587 / empty | Optional SMTP for temporary admin passwords and password-reset links. Setting the host requires from. A password stays in the chart Secret. |
api.publicURL | empty | OM_PUBLIC_URL. Set this to the browser origin before optional Google or GitHub login works. |
api.adminEmail | empty | OM_ADMIN_EMAIL. When set, only this address can become the first admin. |
api.google.clientId / api.google.clientSecret | empty | Google sign-in. Setting the id requires the secret. The secret stays in the chart Secret. |
api.github.clientId / api.github.clientSecret | empty | GitHub sign-in. Same pattern as Google. |
postgres.enabled | true | When false, set postgres.host to your own server. |
postgres.persistence.size | 10Gi | PVC for the bundled database. storageClass is optional. |
resources | 100m / 128Mi request, 1 CPU / 512Mi limit | API container. Scan CronJobs use the same limits unless scan.resources is set. |
scan.schedule | 0 */6 * * * | Schedule for every enabled collector. Overlapping runs of one collector are skipped. |
Scheduled scans
Collectors stay off until you enable one and supply credentials. The chart then runs
om scan as a CronJob against the same Postgres the API reads. For a release
named om, that Service is om-opensourceom-postgres.
om scan demo is not scheduled. A scan does not run CSPM rules.
helm upgrade om deploy/helm/opensourceom \
--reuse-values \
--set scan.aws.enabled=true \
--set scan.aws.existingSecret=aws-creds aws-creds must contain AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY. Azure needs scan.azure.subscriptionId and a
Secret with AZURE_TENANT_ID, AZURE_CLIENT_ID, and
AZURE_CLIENT_SECRET. GCP needs scan.gcp.projectId and a Secret key
named credentials.json. Inline key fields on scan.aws,
scan.azure, and scan.gcp work the same way and are copied into a
chart Secret. serviceAccountAuth: true skips the static key and uses the chart
ServiceAccount; set scan.serviceAccount.annotations for IRSA or workload identity.
Enabling a cloud collector without one of those credentials does not create a CronJob.
scan.kubernetes.enabled=true schedules om scan k8s. With no
kubeconfig Secret, the chart creates a read-only ServiceAccount for this cluster.
scan.kubernetes.namespace empty is a ClusterRole; a namespace is a Role in that
namespace. scan.kubernetes.cluster is the graph account id. Set
scan.kubernetes.existingSecret to mount a kubeconfig instead (key
kubeconfig, unless kubeconfigKey says otherwise). See
the Kubernetes collector.
Set postgres.enabled=false and postgres.host to use a database you
already run. postgres.host is required in that mode. The chart still creates
the API Secret. It does not create a database user on the external server.
Keep the Service off the public internet, or put your own gateway in front of it. See
Security for personal API tokens and console login. Set
api.publicURL to that gateway’s origin when you enable Google or GitHub.
Copyright © 2026 OpenSourceOM. Licensed under Apache-2.0.