Skip to content

Repository files navigation

Supported Versions License

TrustSource OBOM Scanner

The ts-obom scanner extracts an Operations Bill of Materials (OBOM) from infrastructure-as-code: the resources a module is deployed as -- functions, tables, buckets, queues, task definitions -- together with the IAM grants that say which of them may do what to which other. It reads CloudFormation, AWS SAM, Terraform and OpenTofu sources and writes a CycloneDX document that the TrustSource platform stores. It is the infrastructure counterpart to ts-scan, which produces the Software Bill of Materials (SBOM) of the code.

Where an SBOM answers what is in the software, an OBOM answers what the software is operated as, and what it is allowed to touch once it runs. That is the evidence trust-boundary and threat-modelling work needs and which SBOM signals alone cannot provide.

Description

ts-obom scans a directory for IaC sources and emits, per scanned directory, a document with

  • resources - every resource declared in the sources, with its type and the file it comes from. In the CycloneDX output these are the components
  • edges - access grants {principal, resource, actions[], effect, grantedVia}, for example the role of a Lambda function that may s3:GetObject on a bucket ARN, with the policy or SAM policy template that granted it. In the CycloneDX output these are component properties and dependencies edges
  • unresolved - grants the scanner saw but could not expand, for example managed policy ARNs that would need AWS API access to resolve

Supported IaC front-ends:

Front-end Sources What is extracted
cloudformation CloudFormation and AWS SAM templates (.yaml, .yml, .json) AWS::IAM::Role inline policies, AWS::Serverless::Function policies including the common SAM policy templates (DynamoDBCrudPolicy, S3ReadPolicy, ...)
terraform Terraform and OpenTofu (.tf, .tf.json, .tofu, .tofu.json; a .tofu file shadows a .tf file of the same name, as in OpenTofu) aws_iam_role_policy / aws_iam_user_policy / aws_iam_group_policy inline documents, *_policy_attachment resources, resolved to the compute resource assuming the role where possible

The graph is built with a trimmed, vendored subset of Checkov's resource graph builder; see src/ts_obom/_vendor/NOTICE.md for provenance and changes. No Checkov installation and no cloud credentials are required; the scan is fully offline.

Installation

Installation from the PyPI repository

pip install ts-obom

Installation from a local folder

git clone https://github.com/trustsource/ts-obom.git
cd ts-obom
pip install .

Installation as a Docker image

docker pull trustsource/ts-obom

Scan a local checkout by mounting it into the container:

docker run --rm -v "$(pwd)":/workspace trustsource/ts-obom scan -o /workspace/obom.json /workspace/infrastructure

Usage

The command set follows the conventions of ts-scan: verbs as sub-commands, -o/--output and -f/--format for results, --<front-end>:<option> for front-end specific switches, a profile-based config file and an optional tsproject.toml in the scanned directory.

ts-obom scan -o <path to the output file> [-f <output format>] <path to one or more directories>

The -f <output format> option controls the output format and can be:

  • ts - the scanner's own JSON format (default), one document per scanned directory
  • cyclonedx - a CycloneDX 1.6 Operations BOM, the format the TrustSource platform stores
  • dot - a Graphviz digraph of the access graph, for example ts-obom scan -f dot infra | dot -Tsvg -o obom.svg

Options

Which sources are read:

  • --cloudformation:ignore - Skip CloudFormation and SAM templates
  • --terraform:ignore - Skip Terraform and OpenTofu sources

Which deployment the result describes — see Deployments below:

  • --deployment <NAME> - Names the deployment: an environment (DEV, PRD) or a customer setup (kunde1)
  • --cloudformation:parameters <FILE> - Applies a CloudFormation parameter file on top of the templates' declared defaults. Reads [{"ParameterKey": ..., "ParameterValue": ...}] — the format sam deploy --parameter-overrides is fed from — or a flat name/value mapping
  • --terraform:var-file <FILE> - Applies a .tfvars file on top of the variable defaults, as terraform -var-file would

Recorded alongside the result:

  • --tag <TAG> - Stores the SCM tag <TAG> in the result
  • --branch <BRANCH> - Stores the SCM branch <BRANCH> in the result
  • --verbose - Enables verbose mode

The full list of options can be printed using:

ts-obom scan --help

Deployments

One project is usually deployed several times, and the interesting questions are comparative: what does production have that development does not, what does one customer setup grant that another does not.

ts-obom scan -f cyclonedx --deployment PRD \
  --cloudformation:parameters params4PRD.json -o obom-prd.cdx.json .

A name on its own is not enough. The scan resolves Ref, !Sub and Terraform variables against the defaults declared in the sources. In the usual pattern — one template, one parameter file per environment — the entire difference between two deployments lives in those parameter files, so without them two scans of the same sources produce identical documents. Naming one DEV and the other PRD would then show no difference, which says nothing about the deployments and everything about how the documents were made.

Every result therefore records where its parameter values came from, and this field is never omitted:

parameterSource Meaning
defaults Nothing was supplied. Two documents that both say this are not comparable, however they are named
cloudformation=params4PRD.json Values came from that file
cloudformation=defaults,terraform=params4PRD.tfvars Half parameterised — Terraform got values, CloudFormation did not

Naming a deployment without supplying values is allowed, and warned about — once when the scan produces such a document, and again before it is uploaded. A value supplied for a parameter that no scanned template declares is reported under unresolved as unused-parameter, rather than silently doing nothing.

Example

Scanning a directory with a SAM template

ts-obom scan -o obom.json ./backend

produces a document like

[
  {
    "module": "backend",
    "moduleId": "obom:backend",
    "source": "/work/orderdesk/backend",
    "deployment": "PRD",
    "parameterSource": "cloudformation=params4PRD.json",
    "tool": { "name": "ts-obom", "version": "0.4.0", "frontends": ["cloudformation", "terraform"], "generatedAt": "2026-09-22T12:00:00+00:00" },
    "edges": [
      {
        "principal": "AWS::Serverless::Function.OrderApiFunction",
        "resource": "Ref:OrdersTable",
        "actions": ["dynamodb:GetItem", "dynamodb:DeleteItem", "dynamodb:PutItem", "dynamodb:Scan", "dynamodb:Query", "dynamodb:UpdateItem", "dynamodb:BatchWriteItem", "dynamodb:BatchGetItem", "dynamodb:DescribeTable", "dynamodb:ConditionCheckItem"],
        "effect": "Allow",
        "grantedVia": "SAM policy template 'DynamoDBCrudPolicy'"
      }
    ],
    "unresolved": []
  }
]

The exact principal, resource and grantedVia strings depend on the front-end; the format documentation describes them.

Upload to TrustSource

The platform stores OBOMs as CycloneDX, so a transfer is a scan in that format followed by an upload:

ts-obom scan -f cyclonedx -o obom.cdx.json .
ts-obom upload --api-key "$TS_API_KEY" --project-name Orderdesk obom.cdx.json

Scan the project root and upload at project scope: the front-ends recurse, so one run covers the whole project, and that is where an OBOM belongs. A module is something that produces a deployment artefact, which infrastructure does not divide into -- a queue or a table belongs to no artefact. --module-name exists for the case where the scanned sources really are one module's own infrastructure. The obom feature has to be enabled for the company; the key travels as the x-api-key header, and --base-url carries the API version (default https://api.trustsource.io/v2).

Uploading a file written with -f ts is refused locally -- the API would only reject it -- with a pointer to -f cyclonedx.

User Settings

Like ts-scan, ts-obom reads defaults from a TOML config file with profiles. The default location is ~/.ts-obom/config; it is created on first run:

[default]
format = "ts"

[ci]
format = "ts"
verbose = true

Select a profile with ts-obom -p ci scan ... and a different file with ts-obom --config <path> scan .... Options can also be set through environment variables prefixed with TS_OBOM_, for example TS_OBOM_SCAN_OUTPUT_PATH. A tsproject.toml in a scanned directory provides per-project defaults.

Relationship to ts-scan

ts-scan and ts-obom are deliberately separate tools. Software composition (SBOM) and operational deployment (OBOM) are different questions with different consumers, and mixing them into one command set would blur what each result means. Both share the same conventions, packaging and release process, and the OBOM document header (module, moduleId, source, tag, branch) mirrors ts-scan's scan header so that results can be correlated per module.

License

ts-obom is licensed under the Apache License 2.0. The vendored Checkov subset under src/ts_obom/_vendor/checkov is licensed under the Apache License 2.0 by its respective copyright holders; see the LICENSE and NOTICE.md files in that directory.

About

TrustSource OBOM scanner: extracts an IAM access graph (Ownership Bill of Materials) from CloudFormation, SAM and Terraform

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages