Install a self-hosted security graph
Core runs as two processes that share one Postgres database: the om CLI (scans,
rules, queries) and the API (console and HTTP). Docker Compose starts Postgres and the API.
You build or download the CLI and point it at the published database port.
Prerequisites
- Docker with Compose
- Go 1.27.1 if you build
omfrom source (or a release archive from GitHub Releases) - Cloud credentials only when you scan a real account. The demo graph needs none.
Start Postgres and the API
git clone https://github.com/OpenSourceOM/core.git
cd core
cp .env.example .env
docker compose up -d
Compose publishes Postgres on localhost:5432 and the API on
http://localhost:8080. The API applies pending
migrations before it listens.
Compose reads .env for the API container. The CLI does not. It defaults to
POSTGRES_HOST=localhost, which matches the published port. Leave
POSTGRES_HOST=postgres inside .env for the container, and do not
export that value into the shell you use for om.
Build the CLI
go build -o om ./cmd/om
The API container runs om serve, which applies the SQL files in
migrations/ before it listens. A later start applies only files that are not
already recorded. When Compose is running Postgres without the API, run
om migrate from the repository root. Set OM_AUTO_MIGRATE=false on
the API when that command should be the only schema change.
Load the sample graph
./om scan demo
./om paths list
./om paths run internet-to-datastore
./om graph stats om scan demo replaces the previous demo account, upserts a small AWS-and-Kubernetes
sample, runs every CSPM rule, and prints one attack path.
What the demo shows
The command replaces account ids 111122223333 and cluster-demo,
then prints an attack path and up to eight findings from those accounts. The path is
Internet → sg-web → web-1 → AdminRole → prod-db. worker-1 has no public IP and
only reaches the private bucket acme-assets through AppRole.
acme-logs-public is a public bucket that is not on the web-1 path. The
Kubernetes sample is a workload named frontend with
k8s_service_type: LoadBalancer and image nginx:1.25.3, reachable
from the internet and not connected to prod-db. web-1 lists
package cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*. worker-1 lists
the same product at 2.17.1. om enrich cve attaches CVE-2021-44228
to web-1 because that package matches.
Open http://localhost:8080. The console opens on
internet-to-datastore, which should draw that path. Stats should be non-zero,
and the findings list should include attack-path rows for web-1 to prod-db, the public datastore,
and the internet-exposed workload. web-1 matches the internet-exposed workload rule, the
public-IP rule, and the IMDSv1 rule, so each of those becomes its own attack-path finding.
The card lists the ids internet:global, aws:sg:sg-web,
aws:ec2:i-web-1, aws:iam:role/AdminRole, and
aws:rds:prod-db.
If the page is empty, the CLI and the API are pointed at different databases. See
Docker Compose.
Scan a cloud account
Collectors use each cloud’s default credential chain. They are read-only toward the account. Export variables in the shell, then scan. Details and IAM scope are on the collector pages.
export AWS_REGION=us-east-1
./om scan aws
export AZURE_SUBSCRIPTION_ID=00000000-0000-0000-0000-000000000000
./om scan azure
export GCP_PROJECT_ID=my-project
./om scan gcp
./om scan k8s After a scan, evaluate rules and attach CVEs that match workload inventory:
./om rules run
./om enrich cve
./om identity blast-radius --name AdminRole Next
- Configuration for every variable the CLI reads
- The graph for how nodes and edges are used
- CLI for the full command list
- Kubernetes when you leave Compose
Questions
How do I install OpenSourceOM?
Clone the OpenSourceOM/core repository and start Postgres and the API with Docker Compose. The API applies database migrations when it starts. Build the om CLI, then om scan demo loads a sample graph at http://localhost:8080.
Can I try OpenSourceOM without cloud credentials?
Yes. om scan demo loads a sample environment and runs the CSPM rules. AWS, Azure, GCP, and Kubernetes scans are separate commands and use each cloud’s default credential chain.
Related reading
Copyright © 2026 OpenSourceOM. Licensed under Apache-2.0.