setup

BBOT

Purpose

Ingests completed BBOT JSON scans into SubImage. BBOT discovers internet-facing assets and security findings; SubImage reads the report and correlates those observations with the rest of the graph.

SubImage does not run BBOT or hold its scan credentials. Run the open-source scanner in infrastructure you control, against targets you are authorized to assess, and publish its output.json to Amazon S3, Google Cloud Storage, or Azure Blob Storage.

Required Fields

Field Description
bbot_source Cloud prefix containing reports: s3://bucket/bbot/, gs://bucket/bbot/, or azblob://account/container/bbot/.
bbot_aws_account_id 12-digit AWS account ID that owns the report bucket. Required only when bbot_source uses S3; GCS and Azure reuse their corresponding SubImage integrations.

Setup Steps

1. Grant read access

Choose the provider that owns the report bucket.

Amazon S3

Create the BBOT report-reader role in the bucket's AWS account. The default role name is SubImageBbotRole; your SubImage deployment can configure a different name. The role must trust your tenant's SubImage role with the tenant-specific external ID subimage-bbot-<TENANT_ID> and have only s3:ListBucket and s3:GetObject access to the configured prefix.

This CloudFormation example expects the report at bbot/output.json:

AWSTemplateFormatVersion: "2010-09-09"
Description: Read-only BBOT report access for SubImage

Resources:
  SubImageBbotRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: SubImageBbotRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: arn:aws:iam::<ACCOUNT_ID>:role/<TENANT_ID>-subimage-readonly
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                sts:ExternalId: subimage-bbot-<TENANT_ID>
      Policies:
        - PolicyName: ReadBbotReports
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Sid: ListBbotReports
                Effect: Allow
                Action: s3:ListBucket
                Resource: arn:aws:s3:::{{BUCKET_NAME}}
                Condition:
                  StringLike:
                    s3:prefix: bbot/*
              - Sid: ReadBbotReports
                Effect: Allow
                Action: s3:GetObject
                Resource: arn:aws:s3:::{{BUCKET_NAME}}/bbot/*

If the bucket uses a customer-managed KMS key, also grant this role kms:Decrypt on that key.

Google Cloud Storage

Configure the GCP integration in Modules first. BBOT reuses its service account or Workload Identity Federation credentials. Grant that principal roles/storage.objectViewer on the report bucket.

Azure Blob Storage

Configure the Azure integration in Modules first. BBOT reuses its service principal. Grant that principal Storage Blob Data Reader on the report container.

2. Run BBOT and publish the completed report

BBOT supports pipx and Docker. The smallest scheduled runner is a shell script invoked by cron, systemd, or your existing job platform:

#!/bin/sh
set -eu

output_dir=$(mktemp -d)
trap 'rm -rf "$output_dir"' EXIT

bbot -t example.com -p subdomain-enum -n subimage -o "$output_dir" -y
aws s3 cp \
  "$output_dir/subimage/output.json" \
  s3://{{BUCKET_NAME}}/bbot/output.json \
  --only-show-errors

Replace the final upload command with gcloud storage cp or az storage blob upload when using GCS or Azure Blob Storage. Keep scan API keys in BBOT's own secrets file or your job platform's secret store, not in the script.

Upload only after BBOT exits successfully. Replacing output.json keeps each SubImage sync constant-cost. If you need report history, copy reports to a separate archive prefix; do not place an unbounded archive under the configured ingestion prefix.

3. Enable BBOT in SubImage

  1. In ModulesBBOT, set bbot_source to the provider URI for your report prefix.
  2. For S3 only, set bbot_aws_account_id to the bucket owner's AWS account ID.
  3. Save the module and run a sync.

Cartography validates the scan's own completion event and selects the newest completed scan under the prefix. No date-based filename is required. Incomplete scans are ignored, and a report read or parse failure preserves the previously ingested graph snapshot.

Troubleshooting

  • S3 AssumeRole failed — verify the configured role name, tenant principal ARN, external ID, and AWS account ID.
  • GCS access failed — verify the GCP module is enabled and its principal has roles/storage.objectViewer on the bucket.
  • Azure Blob access failed — verify the Azure module is enabled and its service principal has Storage Blob Data Reader on the container.
  • No completed BBOT report — confirm the object is named .json or .jsonl and contains a final SCAN event with status FINISHED.