pfrederiksen/blast-radius
Local-first AWS dependency graph CLI to understand blast radius before changes
blast-radius
Local-first AWS dependency graph CLI to understand blast radius before changes.
Overview
blast-radius is a command-line tool that, given an AWS resource identifier (ARN, ID, or name), discovers related dependencies and produces a dependency graph. This helps operators answer the critical question: "What will break if I touch this?"
Features
- Local-first: No backend required, uses your existing AWS credentials
- Multi-resource support: ALB/NLB, ECS services, Lambda functions, RDS instances/clusters, and more
- Flexible output formats: Human-friendly tree view (default), Graphviz DOT, or JSON
- Permission-resilient: Missing permissions won't crash the tool; they're annotated and discovery continues
- Depth control: Configure how deep to traverse the dependency graph
- AWS SSO friendly: Uses the default AWS credential chain
Installation
Homebrew (macOS/Linux)
brew install pfrederiksen/tap/blast-radiusGo Install
go install github.com/pfrederiksen/blast-radius@latestBinary Download
Download the latest release from the releases page.
Quick Start
# Analyze an ALB by ARN
blast-radius arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890abcdef
# Analyze an ECS service
blast-radius arn:aws:ecs:us-east-1:123456789012:service/my-cluster/my-service
# Use a specific AWS profile and region
blast-radius my-load-balancer --profile prod --region us-west-2
# Output as Graphviz DOT for visualization
blast-radius arn:aws:lambda:us-east-1:123456789012:function:my-function --format dot
# Control traversal depth
blast-radius my-rds-instance --depth 3
# Enable debug logging
blast-radius my-resource --debugUsage
Usage:
blast-radius [resource-identifier] [flags]
Flags:
--depth int Maximum traversal depth (default: 2)
--format string Output format: tree, dot, json (default: "tree")
--profile string AWS profile to use
--region string AWS region (default: from config/environment)
--max-nodes int Maximum nodes to discover (default: 250)
--debug Enable debug logging
-h, --help help for blast-radius
Supported Resources
Application/Network Load Balancers (ALB/NLB) ✅
Status: Fully implemented
- Listeners and listener rules
- Target groups and registered targets (EC2 instances, IP targets, Lambda functions)
- Security groups and VPC/subnets
- Upstream Route 53 alias records (discovers DNS records pointing to the load balancer)
- Target health status
Resolution methods:
- By ARN:
arn:aws:elasticloadbalancing:region:account:loadbalancer/app/name/id - By name:
my-load-balancer
ECS Services ✅
Status: Fully implemented
- Task definitions with container information
- Load balancers and target groups (bidirectional discovery with ALB)
- IAM roles (task role, execution role)
- Security groups and VPC/subnets (from awsvpc network mode)
- Application Auto Scaling policies (target tracking, step scaling)
- Cluster membership
Resolution methods:
- By ARN:
arn:aws:ecs:region:account:service/cluster-name/service-name - By cluster/service:
cluster-name/service-name
Lambda Functions ✅
Status: Fully implemented
- IAM execution role
- Event source mappings (SQS, DynamoDB streams, Kinesis streams, Kafka)
- Event source mapping destinations (OnFailure)
- Function event invoke config destinations (OnSuccess, OnFailure)
- Dead letter queue configuration
- VPC configuration (security groups, subnets)
- Function metadata (runtime, handler, memory, timeout, layers)
Resolution methods:
- By ARN:
arn:aws:lambda:region:account:function:function-name - By name:
function-name
RDS Instances/Clusters ✅
Status: Fully implemented
- DB instances and Aurora clusters
- Subnet groups and VPC with individual subnets
- Security groups with status
- Parameter groups (instance and cluster-level)
- Cluster membership (instances in clusters, and vice versa)
- Complete instance and cluster metadata (engine, version, storage, multi-AZ, endpoints)
- Heuristic-based upstream discovery (experimental, with
--heuristics rds-endpoint)
Resolution methods:
- Instance by identifier:
my-database-instance - Cluster by identifier:
my-aurora-cluster - By ARN:
arn:aws:rds:region:account:db:instance-name - By ARN:
arn:aws:rds:region:account:cluster:cluster-name
Architecture
blast-radius uses a breadth-first traversal algorithm to discover dependencies:
- Resource Identification: Parses input (ARN or name) and determines resource type
- Graph Building: Uses AWS SDK v2 to query related resources
- BFS Traversal: Expands outward from the starting resource up to specified depth
- Output Formatting: Renders the dependency graph in the requested format
Each node in the graph contains:
- ID, type, ARN, name
- Region and account
- Tags and metadata
Each edge contains:
- Source and target nodes
- Relationship type
- Evidence (API call and key fields)
Discovery Implementation
ALB/NLB Discovery:
- Resolves load balancers by name or ARN
- Discovers listeners via
DescribeListeners(with pagination) - Discovers listener rules via
DescribeRules(with pagination) - Discovers target groups via
DescribeTargetGroups - Discovers target health and registered targets via
DescribeTargetHealth - Maps targets to EC2 instances, IP addresses, or Lambda functions based on target type
- Discovers security groups and subnets from load balancer configuration
- Discovers upstream Route 53 alias records by:
- Listing all hosted zones via
ListHostedZones - Searching each zone for alias records via
ListResourceRecordSets - Matching alias target DNS names to load balancer DNS names
- Listing all hosted zones via
Permission Requirements:
elasticloadbalancing:DescribeLoadBalancerselasticloadbalancing:DescribeListenerselasticloadbalancing:DescribeRuleselasticloadbalancing:DescribeTargetGroupselasticloadbalancing:DescribeTargetHealthroute53:ListHostedZonesroute53:ListResourceRecordSets
ECS Service Discovery:
- Resolves services by ARN or cluster/service name via
DescribeServices - Discovers task definitions via
DescribeTaskDefinition - Extracts container definitions with CPU/memory allocation
- Discovers IAM roles (task role and execution role) from task definition
- Discovers security groups and subnets from awsvpc network configuration
- Links to target groups (bidirectional discovery with ALB)
- Discovers Application Auto Scaling policies via:
DescribeScalableTargetsto find auto-scaling configurationDescribeScalingPoliciesto get scaling policies (target tracking, step scaling)
- Discovers cluster membership
Permission Requirements:
ecs:DescribeServicesecs:DescribeTaskDefinitionapplication-autoscaling:DescribeScalableTargetsapplication-autoscaling:DescribeScalingPolicies
Lambda Function Discovery:
- Resolves functions by name or ARN via
GetFunction - Discovers IAM execution role from function configuration
- Discovers VPC configuration (security groups and subnets) if configured
- Discovers dead letter queue (DLQ) from function configuration
- Discovers event source mappings via
ListEventSourceMappings(with pagination):- Identifies source type from ARN (SQS, DynamoDB, Kinesis, Kafka)
- Tracks mapping state and batch size
- Discovers OnFailure destinations for event source mappings
- Discovers function event invoke config destinations via
GetFunctionEventInvokeConfig:- OnSuccess destinations (SNS, SQS, Lambda, EventBridge)
- OnFailure destinations (SNS, SQS, Lambda, EventBridge)
- Extracts function metadata: runtime, handler, memory, timeout, code size, layers
Permission Requirements:
lambda:GetFunctionlambda:ListEventSourceMappingslambda:GetFunctionEventInvokeConfig
RDS Instance/Cluster Discovery:
- Resolves instances by identifier or ARN via
DescribeDBInstances - Resolves clusters by identifier or ARN via
DescribeDBClusters - Discovers subnet groups and individual subnets from DB configuration
- Discovers security groups with status from VPC configuration
- Discovers parameter groups (instance and cluster-level) with apply status
- Discovers cluster membership:
- For instances: identifies parent cluster if instance is part of Aurora cluster
- For clusters: lists all member instances with writer/reader role
- Extracts complete metadata: engine, version, storage, multi-AZ, endpoints (including reader endpoint for clusters)
- Heuristic-based upstream discovery (experimental):
- When
--heuristics rds-endpointflag is enabled - Attempts to find Lambda functions and ECS services that connect to RDS endpoint
- Marks connections with
Heuristic: truein evidence
- When
Permission Requirements:
rds:DescribeDBInstancesrds:DescribeDBClusters
Missing permissions will be logged as warnings and discovery will continue with available data.
Examples
Real-World Scenarios
1. Understanding Load Balancer Impact
Before making changes to a load balancer, understand its full dependency graph:
# Analyze by ALB name
blast-radius my-production-alb
# Analyze by ARN with increased depth
blast-radius arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/abc123 --depth 3
# Output as visualization
blast-radius my-production-alb --format dot | dot -Tpng -o alb-dependencies.pngExample output:
[Level 0] Root
└─ LoadBalancer: my-production-alb (arn:aws:elasticloadbalancing:...)
Tags: Environment=production, Team=platform
[Level 1] Direct Dependencies
├─ Listener: HTTPS:443 (arn:aws:elasticloadbalancing:...)
│ DefaultAction: forward
├─ Listener: HTTP:80 (arn:aws:elasticloadbalancing:...)
│ DefaultAction: redirect to HTTPS
├─ SecurityGroup: alb-sg (sg-abc123)
└─ Route53Record: api.example.com (A ALIAS)
[Level 2] Transitive Dependencies
├─ TargetGroup: api-tg-blue
│ ├─ ECSService: prod-cluster/api-service
│ ├─ Instance: i-0a1b2c3d (healthy, t3.large)
│ └─ Instance: i-4e5f6g7h (healthy, t3.large)
└─ TargetGroup: api-tg-green
└─ ECSService: prod-cluster/api-service-canary
2. ECS Service Dependency Analysis
Understanding what an ECS service depends on before scaling or updating:
# Analyze ECS service
blast-radius prod-cluster/api-service
# Use specific region and profile
blast-radius prod-cluster/api-service --region us-west-2 --profile productionExample output:
[Level 0] Root
└─ ECSService: prod-cluster/api-service
DesiredCount: 4, RunningCount: 4
[Level 1] Direct Dependencies
├─ ECSTaskDefinition: api-service:42
│ CPU: 512, Memory: 1024
│ Containers: api-app, datadog-agent
├─ IAMRole: ecs-task-execution-role
├─ IAMRole: api-service-task-role
├─ TargetGroup: api-tg-blue (arn:aws:elasticloadbalancing:...)
├─ SecurityGroup: ecs-service-sg (sg-xyz789)
├─ Subnet: subnet-1a2b3c4d (us-east-1a)
├─ Subnet: subnet-5e6f7g8h (us-east-1b)
└─ ScalingPolicy: target-tracking-cpu
[Level 2] Transitive Dependencies
└─ LoadBalancer: my-production-alb
└─ Route53Record: api.example.com
3. Lambda Function Analysis
Discover what triggers a Lambda function and what it connects to:
# Analyze Lambda function
blast-radius my-data-processor
# Find all dependencies including event sources
blast-radius arn:aws:lambda:us-east-1:123456789012:function:my-data-processor --depth 2Example output:
[Level 0] Root
└─ Lambda: my-data-processor
Runtime: python3.11, Memory: 512MB, Timeout: 30s
[Level 1] Direct Dependencies
├─ IAMRole: lambda-execution-role
├─ SQSQueue: data-ingestion-queue
│ Trigger: EventSourceMapping (BatchSize: 10)
├─ EventDestination: dead-letter-queue (OnFailure)
├─ SecurityGroup: lambda-sg (sg-def456)
└─ Subnet: subnet-9i0j1k2l (us-east-1a)
[Level 2] Transitive Dependencies
└─ VPC: vpc-main
4. RDS Database Impact Assessment
Before migrating or modifying a database, see what depends on it:
# Analyze RDS instance
blast-radius my-production-db
# Analyze Aurora cluster
blast-radius my-aurora-cluster --heuristics rds-endpointExample output:
[Level 0] Root
└─ RDSInstance: my-production-db
Engine: postgres 14.7, Class: db.r5.xlarge
MultiAZ: true, Endpoint: my-production-db.abc.us-east-1.rds.amazonaws.com
[Level 1] Direct Dependencies
├─ DBSubnetGroup: prod-db-subnet-group
│ ├─ Subnet: subnet-db-1a (us-east-1a)
│ ├─ Subnet: subnet-db-1b (us-east-1b)
│ └─ Subnet: subnet-db-1c (us-east-1c)
├─ SecurityGroup: rds-sg (sg-rds123)
│ Status: active
├─ DBParameterGroup: postgres14-custom
│ Status: in-sync
└─ RDSCluster: my-aurora-cluster
(if instance is part of a cluster)
5. Analyzing Aurora Clusters
# Discover all instances in a cluster
blast-radius my-aurora-cluster --depth 2Example output:
[Level 0] Root
└─ RDSCluster: my-aurora-cluster
Engine: aurora-postgresql 14.7
Endpoint: cluster-endpoint.us-east-1.rds.amazonaws.com
ReaderEndpoint: cluster-ro-endpoint.us-east-1.rds.amazonaws.com
[Level 1] Direct Dependencies
├─ RDSInstance: my-aurora-cluster-instance-1
│ IsClusterWriter: true, Class: db.r5.large
├─ RDSInstance: my-aurora-cluster-instance-2
│ IsClusterWriter: false, Class: db.r5.large
├─ RDSInstance: my-aurora-cluster-instance-3
│ IsClusterWriter: false, Class: db.r5.large
├─ DBSubnetGroup: aurora-subnet-group
├─ SecurityGroup: aurora-sg (sg-aurora123)
└─ DBClusterParameterGroup: aurora-pg14-custom
Output Formats
Tree (Default) - Human-Friendly
blast-radius my-resourceBest for: Quick analysis, terminal output, understanding dependency hierarchy
DOT - Graphviz Visualization
# Generate PNG
blast-radius my-alb --format dot | dot -Tpng -o graph.png
# Generate SVG (better for large graphs)
blast-radius my-alb --format dot | dot -Tsvg -o graph.svg
# Generate PDF
blast-radius my-alb --format dot | dot -Tpdf -o graph.pdfBest for: Documentation, presentations, visual analysis
JSON - Machine-Readable
# Full graph as JSON
blast-radius my-resource --format json
# Filter specific resource types
blast-radius my-alb --format json | jq '.nodes[] | select(.type == "ECSService")'
# Extract all security groups
blast-radius my-resource --format json | jq '.nodes[] | select(.type == "SecurityGroup") | .name'
# Find all resources in a specific region
blast-radius my-resource --format json | jq '.nodes[] | select(.region == "us-east-1")'
# Count dependencies by type
blast-radius my-resource --format json | jq '.nodes | group_by(.type) | map({type: .[0].type, count: length})'Best for: Automation, CI/CD integration, custom processing
Common Workflows
Pre-Deployment Safety Check
#!/bin/bash
# Check if critical resources will be affected by changes
RESOURCE=$1
MAX_NODES=100
echo "Analyzing blast radius for: $RESOURCE"
blast-radius "$RESOURCE" --max-nodes $MAX_NODES --format json > blast-radius.json
# Check if any production resources are affected
PROD_COUNT=$(jq '.nodes[] | select(.tags.Environment == "production") | .id' blast-radius.json | wc -l)
if [ "$PROD_COUNT" -gt 0 ]; then
echo "WARNING: $PROD_COUNT production resources will be affected!"
echo "Manual approval required."
exit 1
fiDocument Infrastructure Dependencies
#!/bin/bash
# Generate documentation for all critical services
SERVICES=("my-alb" "api-service" "data-processor" "production-db")
for service in "${SERVICES[@]}"; do
echo "Documenting: $service"
blast-radius "$service" --format dot | dot -Tpng -o "docs/${service}-dependencies.png"
blast-radius "$service" > "docs/${service}-dependencies.txt"
doneMulti-Region Analysis
#!/bin/bash
# Analyze the same resource across multiple regions
RESOURCE="my-service"
REGIONS=("us-east-1" "us-west-2" "eu-west-1")
for region in "${REGIONS[@]}"; do
echo "=== $region ==="
blast-radius "$RESOURCE" --region "$region" --profile prod
echo ""
doneDevelopment
Prerequisites
- Go 1.22+
- AWS credentials configured
Build
go build -o blast-radiusTest
go test ./...Lint
golangci-lint runTest Coverage
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.outCI/CD
The project uses GitHub Actions for:
- PR Checks: Automated testing, linting, and build verification on every pull request
- Releases: Automated binary builds for multiple platforms and Homebrew tap updates on version tags
To create a release:
git tag -a v0.1.0 -m "Release v0.1.0"
git push origin v0.1.0Contributing
Contributions welcome! Please open an issue or submit a pull request.
License
Apache-2.0. See LICENSE for details.
Acknowledgments
Built with: