Bona
The Joern for cloud — builds an Asset Property Graph from AWS Config and exports Joern-compatible nodes.json + edges.json.
Bona discovers your cloud infrastructure via AWS Config's advanced SQL queries and produces a typed property graph that can be loaded into Amazon Neptune, the GraphRAG Toolkit, Neo4j, or any tool that consumes flat JSON node/edge format. The output schema is inspired by Joern's cpg_exporter.py — same flat structure, applied to cloud assets instead of code.
Installation
pip install bona
Requires Python 3.11+ and valid AWS credentials with config:SelectResourceConfig permissions.
Quick Start
Export — full infrastructure graph
# Export all resources in a region
bona export --profile myprofile --region us-east-1
# Filter to specific resource types (supports globs)
bona export --profile myprofile --region us-east-1 --types "AWS::EC2::*,AWS::S3::*"
# Multi-region export
bona export --profile myprofile --region us-east-1,us-west-2,eu-west-1
# Multi-account via aggregator
bona export --profile myprofile --region us-east-1 --aggregator MyOrgAggregator
# Include compliance findings as graph nodes
bona export --profile myprofile --region us-east-1 --include-compliance
# Upload to S3
bona export --profile myprofile --region us-east-1 --s3-uri s3://my-bucket/apg/
History — temporal graph (config changes over time)
# Get configuration history for a specific resource
bona history --profile myprofile --region us-east-1 \
--resource-type AWS::EC2::Instance \
--resource-id i-0abc123def456
# Limit to last 5 snapshots
bona history --profile myprofile --region us-east-1 \
--resource-type AWS::S3::Bucket \
--resource-id my-bucket-name \
--limit 5
Types — list tracked resource types
# Show all resource types tracked by AWS Config in a region
bona types --profile myprofile --region us-east-1
Schema — download type definitions
# Download CloudFormation type schemas to local cache
bona schema --profile myprofile --region us-east-1
# Specific types
bona schema --profile myprofile --region us-east-1 --types "AWS::S3::Bucket,AWS::EC2::Instance"
# All types tracked by Config
bona schema --profile myprofile --region us-east-1 --types all
# Upload schema cache to S3
bona schema --profile myprofile --region us-east-1 --s3-uri s3://my-bucket/schemas/
Enrichment — type-aware graph
# Export with type schema enrichment (soft = uses cache, no extra AWS calls)
bona export --profile myprofile --region us-east-1 --enrich
# Hard enrichment (re-downloads schemas from CloudFormation)
bona export --profile myprofile --region us-east-1 --enrich hard
Enrichment adds TypeDefinition reference nodes and INSTANCE_OF edges to the graph:
[IAM Role "MyRole"] ──INSTANCE_OF──▶ [TypeDefinition "AWS::IAM::Role"]
[IAM Role "OtherRole"] ──INSTANCE_OF──▶ [TypeDefinition "AWS::IAM::Role"]
[S3 Bucket "data"] ──INSTANCE_OF──▶ [TypeDefinition "AWS::S3::Bucket"]
One TypeDefinition node per resource type carries the full schema contract (properties, required fields, read-only, identifiers).
Bedrock Discovery
Bona discovers your Amazon Bedrock environment — foundation models, agents, knowledge bases, prompts, guardrails, and AgentCore components:
bona export --profile myprofile --region us-east-1 --types "AWS::Bedrock::*"
What it discovers: 119+ foundation models, providers (Anthropic, Meta, Amazon, etc.), modalities (TEXT, IMAGE, EMBEDDING), model families, Bedrock Agents, Prompt Flows, and AgentCore resources.
Graph structure — model decomposition:
[Model "claude-3-sonnet"] ──PROVIDED_BY──▶ [Provider "Anthropic"]
[Model "claude-3-sonnet"] ──HAS_MODALITY──▶ [Modality "TEXT"]
[Agent "support-bot"] ──USES_MODEL──▶ [Model "claude-3-sonnet"]
[Agent "support-bot"] ──HAS_KB──▶ [KnowledgeBase "product-docs"]
See docs/bedrock-discovery.md for full details.
Configuration File
Control enrichment, output, and logging via bona.yaml:
logging:
level: INFO # DEBUG | INFO | WARNING | ERROR
path: ./bona.log # local file or s3://bucket/logs/
enrichment:
enabled: true
mode: soft # soft | hard
include:
- "AWS::EC2::*"
- "AWS::S3::*"
exclude:
- "AWS::CloudFormation::Stack"
output:
dir: ./bona-output
s3_uri: s3://my-bucket/apg/
schema_cache:
s3_uri: s3://my-bucket/schemas/
learning:
s3_uri: s3://my-bucket/bona-learning/ # uploads graph-schema, rules, descriptions
Place as ./bona.yaml (project-local), ~/.bona/config.yaml (user-level), or pass --config path/to/bona.yaml.
Learn Mode — evolving graph schema
Learn mode maintains a versioned schema of every node type and edge type Bona has ever observed. Each export run updates the schema with new types, properties, and relationship pairs — so over time you get a complete picture of your graph's shape without manual maintenance.
# Learn from an export (writes/updates ~/.bona/graph-schema.json)
bona export --profile myprofile --region us-east-1 --learn
# Combine with enrichment
bona export --profile myprofile --region us-east-1 --enrich --learn
The schema lives at ~/.bona/graph-schema.json (configurable via schema.path in bona.yaml).
Semver auto-bumping:
- MINOR bump — new node types, edge types, or relationship pairs discovered
- PATCH bump — only observation counts/timestamps updated
Example — what the schema captures:
{
"version": "0.3.0",
"last_updated": "2026-08-06T12:00:00Z",
"node_types": {
"AWS::EC2::Instance": {
"observed_properties": ["imageId", "instanceType", "subnetId", "vpcId"],
"observed_count": 42,
"first_seen": "2026-08-01T10:00:00Z",
"last_seen": "2026-08-06T12:00:00Z"
}
},
"edge_types": {
"IS_CONTAINED_IN": {
"observed_pairs": [
{"source_type": "AWS::EC2::Subnet", "target_type": "AWS::EC2::VPC"}
],
"observed_count": 15
}
}
}
See docs/graph-schema.md for full details.
LLM Enrichment
LLM enrichment uses Amazon Bedrock to analyze resource properties and improve graph quality:
- Relationship classification — identifies properties that reference other resources and converts them into typed edges
- Description generation — produces human-readable summaries of resources for graph exploration and RAG
# Export with LLM enrichment
bona export --profile myprofile --region us-east-1 --llm-enrich
# Combine with schema enrichment and learn mode
bona export --profile myprofile --region us-east-1 --enrich --llm-enrich --learn
Configuration in bona.yaml:
llm_enrichment:
model_id: anthropic.claude-3-haiku-20240307-v1:0
tasks:
- classify_relationships
- generate_descriptions
budget:
max_invocations: 500 # cap per export run
max_input_tokens: 100000 # total input token budget
Example — what LLM enrichment discovers:
# A securityGroupIds property gets classified as a relationship:
[Lambda "api-handler"] ──IS_ASSOCIATED_WITH──▶ [SG "sg-abc123"]
# A resource gets a generated description:
{ "description": "Production API handler Lambda in VPC, triggered by API Gateway, with DynamoDB access" }
See docs/llm-enrichment.md for full details.
Plugins
Bona uses a pluggy-based plugin system that lets you add new providers, supplemental enrichers, and relationship classifiers without modifying core bona code.
Install a plugin:
pip install bona-provider-xxx
Plugins are auto-discovered via Python entry points — no config changes needed.
Create a plugin:
# my_provider/plugin.py
import bona.hookspecs
from pluggy import HookimplMarker
hookimpl = HookimplMarker("bona")
@hookimpl
def bona_reference_providers():
"""Return a list of ReferenceProvider instances."""
return [MyCustomProvider()]
Register via pyproject.toml:
[project.entry-points."bona"]
my_provider = "my_provider.plugin"
Available hooks:
| Hook | Purpose |
|---|---|
bona_reference_providers |
Add reference data providers (type definitions, external metadata) |
bona_supplemental_providers |
Add supplemental enrichment providers (hardware specs, pricing, etc.) |
bona_relationship_classifiers |
Add custom relationship classification logic |
See examples/bona-provider-example/ for a full working plugin example.
CLI Reference
bona [--verbose] [--config <path>] <command> [options]
Global:
--verbose, -v Enable debug logging (overrides config level to DEBUG)
--config <path> Path to bona config file (JSON or YAML)
Commands:
export Export Asset Property Graph (nodes.json + edges.json)
schema Download CloudFormation type schemas to local cache
history Export temporal graph — resource config over time
types List resource types tracked by AWS Config
cache Pre-populate local cache (instance types, etc.)
bona export
| Flag | Default | Description |
|---|---|---|
--profile |
(default) | AWS profile name from ~/.aws/credentials |
--region |
us-east-1 | AWS region (comma-separated for multi-region) |
--output-dir |
./bona-output | Local output directory |
--s3-uri |
S3 URI for upload (e.g. s3://bucket/prefix/) |
|
--types |
(all) | Resource type filter (comma-separated, globs supported) |
--max-resources |
10000 | Safety cap on total resources |
--include-compliance |
false | Include Config rule compliance findings as nodes |
--aggregator |
Config aggregator name for multi-account queries | |
--enrich |
disabled | Enable type schema enrichment (soft or hard). If flag given without value: soft |
--learn |
false | Update graph schema with discovered node/edge types (writes ~/.bona/graph-schema.json) |
--llm-enrich |
false | Enable LLM enrichment via Bedrock (classify relationships, generate descriptions) |
--refresh-cache |
false | Force refresh of all cached data from AWS |
bona schema
| Flag | Default | Description |
|---|---|---|
--profile |
(default) | AWS profile name |
--region |
us-east-1 | AWS region |
--type |
Single resource type (e.g. AWS::S3::Bucket) |
|
--types |
(common) | Comma-separated types, or all for Config-tracked types |
--s3-uri |
Upload schemas to S3 (e.g. s3://bucket/schemas/) |
|
--validate |
Validate a nodes.json file against cached schemas |
bona history
| Flag | Default | Description |
|---|---|---|
--profile |
(default) | AWS profile name |
--region |
us-east-1 | AWS region |
--resource-type |
(required) | Resource type (e.g. AWS::EC2::Instance) |
--resource-id |
(required) | Resource ID |
--limit |
20 | Max history items |
--output-dir |
./bona-output | Local output directory |
bona types
| Flag | Default | Description |
|---|---|---|
--profile |
(default) | AWS profile name |
--region |
us-east-1 | AWS region |
Output Format
Bona produces two files: nodes.json and edges.json (plus a manifest.json summary).
nodes.json
Each node is a flat JSON object representing an AWS resource:
[
{
"id": "arn:aws:ec2:us-east-1:123456789012:instance/i-0abc123def456",
"node_type": "AWS::EC2::Instance",
"name": "web-server-1",
"stable_id": "aws|123456789012|us-east-1|AWS::EC2::Instance|i-0abc123def456",
"semantic_hash": "a1b2c3d4e5f6g7h8",
"provider": "aws",
"account_id": "123456789012",
"region": "us-east-1",
"resource_type": "AWS::EC2::Instance",
"state": "ACTIVE",
"tags": {"Name": "web-server-1", "Environment": "production"},
"configuration_capture_time": "2026-08-05T12:00:00Z",
"instanceType": "t3.medium",
"vpcId": "vpc-abc123",
"subnetId": "subnet-def456",
"imageId": "ami-0123456789abcdef0"
}
]
Key fields:
- id — ARN (globally unique identifier)
- node_type — AWS resource type (e.g.
AWS::EC2::Instance) - stable_id — deterministic identity for delta reconciliation across runs
- semantic_hash — SHA-256 of configuration; detects config drift
- state —
ACTIVE,DELETED, orDISCOVERED - All configuration properties are flattened to top-level keys (Joern style)
edges.json
Each edge represents a relationship between resources:
[
{
"source_id": "arn:aws:ec2:us-east-1:123456789012:instance/i-0abc123",
"target_id": "arn:aws:ec2:us-east-1:123456789012:security-group/sg-xyz789",
"edge_type": "IS_ASSOCIATED_WITH",
"stable_id": "aws|123456789012|EDGE|IS_ASSOCIATED_WITH|i-0abc123→sg-xyz789"
}
]
Edge types include:
IS_CONTAINED_IN,CONTAINS— hierarchy (subnet in VPC)IS_ATTACHED_TO— resource attachments (volume to instance)IS_ASSOCIATED_WITH— associations (security group to instance)IN_VPC,IN_SUBNET— inferred from configuration propertiesUSES_ROLE,ENCRYPTED_BY— inferred from IAM/KMS referencesROUTES_TO,ATTACHED_TO,IN_CLUSTER— inferred from ARN referencesINSTANCE_OF— resource instance to its TypeDefinition (enrichment)RUNS_ON— EC2 instance to its InstanceSpec (supplemental enrichment)CHANGED_TO— temporal edges (history command)
Architecture
graph TD
CLI[bona CLI] --> Config[Config<br/>bona.yaml]
CLI --> Provider[AWSProvider]
Provider --> Enumerate[1. Enumerate types]
Provider --> Query[2. SQL query + backfill]
Provider --> Extract[3. Extract relationships]
Provider --> Enrich[4. Enrich via plugins]
Provider --> Learn[5. Learn mode]
Provider --> LLM[6. LLM enrichment]
Enrich --> Plugins[Plugin Manager<br/>pluggy]
Plugins --> TypeSchemas[Type Schemas<br/>CloudFormation]
Plugins --> RefProviders[Reference Providers<br/>Bedrock, EC2 specs]
Plugins --> External[External Plugins<br/>pip install]
Provider --> Exporter[Exporter]
Exporter --> NodesJSON[nodes.json]
Exporter --> EdgesJSON[edges.json]
Exporter --> S3[S3 Upload]
Learn --> GraphSchema[graph-schema.json<br/>semver]
Learn --> Rules[relationship-rules.json]
LLM --> Descriptions[descriptions.json]
subgraph AWS APIs
ConfigAPI[AWS Config<br/>select_resource_config<br/>batch_get_resource_config]
CFN[CloudFormation<br/>describe_type]
Bedrock[Bedrock<br/>list_foundation_models<br/>bedrock-agent<br/>bedrock-agentcore]
BedrockRT[Bedrock Runtime<br/>Converse API]
end
Query --> ConfigAPI
TypeSchemas --> CFN
RefProviders --> Bedrock
LLM --> BedrockRT
subgraph Consumers
Neptune[Amazon Neptune]
GraphRAG[GraphRAG Toolkit]
Neo4j[Neo4j]
Analytics[jq / pandas]
end
Exporter --> Consumers
Multi-Account via Aggregator
Use the --aggregator flag to query across multiple AWS accounts and regions using an AWS Config Aggregator:
bona export --profile management --region us-east-1 --aggregator MyOrgAggregator
This uses select_aggregate_resource_config instead of select_resource_config, returning resources from all accounts enrolled in the aggregator. Each node retains its original account_id and region.
See docs/multi-account.md for aggregator setup instructions.
Compatibility
| Consumer | How to use |
|---|---|
| Amazon Neptune | Bulk load via neptune-export or convert to CSV with provided scripts |
| GraphRAG Toolkit | Feed nodes.json as document-graph source for graph-augmented RAG |
| Neo4j | Import JSON via apoc.load.json or convert to Cypher |
| document-graph | Native format — flat JSON nodes with typed edges |
| jq / pandas | Standard JSON — pipe through jq or load with pd.read_json() |
Requirements
- Python 3.11+
- AWS credentials with permissions:
config:SelectResourceConfigconfig:SelectAggregateResourceConfig(if using--aggregator)config:GetResourceConfigHistory(forhistorycommand)config:DescribeComplianceByResource(if using--include-compliance)config:DescribeConfigRules(if using--include-compliance)cloudformation:DescribeType(if using--enrichorbona schema)ec2:DescribeInstanceTypes(if using EC2 supplemental enrichment)bedrock-runtime:Converse(if using--llm-enrich)sts:GetCallerIdentitys3:PutObject(if using--s3-uri)
- AWS Config recorder must be enabled in target region(s)
License
MIT
Metadata
Release files for bona 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bona-0.5.0.tar.gz | 897.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bona-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 998.0 kB
Release files / bona-0.5.0.tar.gz
| Download URL | bona-0.5.0.tar.gz |
|---|---|
| Size | 897.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
703b6ca84ebfdf1d1353e8c16e14453b638b573242887fa39e1cb0b066ab2578
|
|
BLAKE2b-256 checksum How to use checksums |
80fd55151737e4f8bc189d16a2daef8a57fe3f4c3f35311409bd3d33cff8775d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / bona-0.5.0-py3-none-any.whl
| Download URL | bona-0.5.0-py3-none-any.whl |
|---|---|
| Size | 100.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3e1d2eed42a64b0c257c889d9af5da5972bb83ef290799b1bcdfc66db1bdb664
|
|
BLAKE2b-256 checksum How to use checksums |
bd0e635e18d02154376b2b54a0e03c31b8719cda2808735895ab307774b3ca72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|