Active findings
5Built-in scenario
sample_aws_ecs_fargate_plan.jsonECS / Fargate Demo
Analyzed sample_aws_ecs_fargate_plan.json with 21 normalized resources and 6 trust boundaries.
Trust boundaries
6Resources
21Observations
1Findings
Severity bands
High
0No high findings.
Medium
5IAM policy grants wildcard privileges
aws-iam-wildcard-permissionsaws_iam_role.task contains allow statements with wildcard actions or resources. That makes the resulting access difficult to reason about and expands blast radius.
- Category
- Elevation of Privilege
- Boundary
- not-applicable
- Resources
- aws_iam_role.task
Evidence
- iam resources: *
- policy statements: Allow actions=[secretsmanager:GetSecretValue] resources=[*]
IAM policy grants wildcard privileges
aws-iam-wildcard-permissionsaws_iam_role.execution contains allow statements with wildcard actions or resources. That makes the resulting access difficult to reason about and expands blast radius.
- Category
- Elevation of Privilege
- Boundary
- not-applicable
- Resources
- aws_iam_role.execution
Evidence
- iam resources: *
- policy statements: Allow actions=[logs:CreateLogStream, logs:PutLogEvents] resources=[*]
Sensitive data tier is transitively reachable from an internet-exposed path
aws-private-data-transitive-exposureaws_db_instance.app is not directly public, but internet traffic can first reach aws_lb.web, move through aws_lb.web can reach aws_ecs_service.app, and then cross into the private data tier through aws_ecs_service.app. That creates a quieter transitive exposure path than a directly public data store.
- Category
- Information Disclosure
- Boundary
- workload-to-data-store:aws_ecs_service.app->aws_db_instance.app
- Resources
- aws_lb.web, aws_ecs_service.app, aws_db_instance.app, aws_security_group.ecs
Evidence
- network path: internet reaches aws_lb.web; aws_lb.web reaches aws_ecs_service.app; aws_ecs_service.app reaches aws_db_instance.app
- security group rules: aws_security_group.ecs ingress tcp 8080 from sg-ecs-alb
- subnet posture: aws_lb.web sits in public subnet aws_subnet.public_a with an internet route; aws_lb.web sits in public subnet aws_subnet.public_b with an internet route; aws_ecs_service.app sits in private subnet aws_subnet.private_app
- data tier posture: aws_db_instance.app is not directly public; database has no direct internet ingress path
- boundary rationale: Application or function workloads cross into a higher-sensitivity data plane when database ingress security groups explicitly trust the workload security group.
Sensitive data tier is transitively reachable from an internet-exposed path
aws-private-data-transitive-exposureaws_secretsmanager_secret.app is not directly public, but internet traffic can first reach aws_lb.web, move through aws_lb.web can reach aws_ecs_service.app, and then cross into the private data tier through aws_ecs_service.app. That creates a quieter transitive exposure path than a directly public data store.
- Category
- Information Disclosure
- Boundary
- workload-to-data-store:aws_ecs_service.app->aws_secretsmanager_secret.app
- Resources
- aws_lb.web, aws_ecs_service.app, aws_secretsmanager_secret.app, aws_security_group.ecs
Evidence
- network path: internet reaches aws_lb.web; aws_lb.web reaches aws_ecs_service.app; aws_ecs_service.app reaches aws_secretsmanager_secret.app
- security group rules: aws_security_group.ecs ingress tcp 8080 from sg-ecs-alb
- subnet posture: aws_lb.web sits in public subnet aws_subnet.public_a with an internet route; aws_lb.web sits in public subnet aws_subnet.public_b with an internet route; aws_ecs_service.app sits in private subnet aws_subnet.private_app
- data tier posture: aws_secretsmanager_secret.app is not directly public
- boundary rationale: Application or function workloads cross into a higher-sensitivity secret plane when their attached role allows Secrets Manager retrieval actions such as secretsmanager:GetSecretValue.
Workload role carries sensitive permissions
aws-workload-role-sensitive-permissionsaws_ecs_service.app inherits sensitive privileges from aws_iam_role.task, including secretsmanager:GetSecretValue. If the workload is compromised, those credentials can be reused for privilege escalation, data access, or role chaining.
- Category
- Elevation of Privilege
- Boundary
- admin-to-workload-plane:aws_iam_role.task->aws_ecs_service.app
- Resources
- aws_ecs_service.app, aws_iam_role.task
Evidence
- iam actions: secretsmanager:GetSecretValue
- policy statements: Allow actions=[secretsmanager:GetSecretValue] resources=[*]
Low
0No low findings.
Observations
Controls and mitigating signals
RDS instance is private and storage encrypted
aws_db_instance.app is kept off direct internet paths and has storage encryption enabled, which reduces straightforward data exposure risk.
Trust boundaries
Crossings that drive the model
admin-to-workload-plane
aws_iam_role.task -> aws_ecs_service.app
IAM configuration acts as a control-plane boundary because the workload inherits whatever privileges the role carries.
internet-to-service
internet -> aws_lb.web
The resource is directly reachable or intentionally exposed to unauthenticated network clients.
public-subnet-to-private-subnet
aws_subnet.public_a -> aws_subnet.private_app
The VPC contains both publicly routable and private network segments that should be treated as separate trust zones.
public-subnet-to-private-subnet
aws_subnet.public_b -> aws_subnet.private_app
The VPC contains both publicly routable and private network segments that should be treated as separate trust zones.
workload-to-data-store
aws_ecs_service.app -> aws_db_instance.app
Application or function workloads cross into a higher-sensitivity data plane when database ingress security groups explicitly trust the workload security group.
workload-to-data-store
aws_ecs_service.app -> aws_secretsmanager_secret.app
Application or function workloads cross into a higher-sensitivity secret plane when their attached role allows Secrets Manager retrieval actions such as secretsmanager:GetSecretValue.
Raw outputs
Stable contract and markdown
JSON report
{
"kind": "cloud-threat-model-report",
"version": "1.0",
"tool": {
"name": "cloud-threat-modeler",
"version": "0.2.0"
},
"title": "ECS / Fargate Demo",
"analyzed_file": "sample_aws_ecs_fargate_plan.json",
"analyzed_path": "/home/fleet/cloud-threat-modeler/fixtures/sample_aws_ecs_fargate_plan.json",
"summary": {
"normalized_resources": 21,
"unsupported_resources": 0,
"trust_boundaries": 6,
"active_findings": 5,
"total_findings": 5,
"suppressed_findings": 0,
"baselined_findings": 0,
"severity_counts": {
"high": 0,
"medium": 5,
"low": 0
}
},
"filtering": {
"total_findings": 5,
"active_findings": 5,
"suppressed_findings": 0,
"baselined_findings": 0,
"suppressions_path": null,
"baseline_path": null
},
"inventory": {
"provider": "aws",
"unsupported_resources": [],
"metadata": {
"primary_account_id": "111122223333",
"supported_resource_types": [
"aws_db_instance",
"aws_ecs_cluster",
"aws_ecs_service",
"aws_ecs_task_definition",
"aws_iam_instance_profile",
"aws_iam_policy",
"aws_iam_role",
"aws_iam_role_policy",
"aws_iam_role_policy_attachment",
"aws_instance",
"aws_internet_gateway",
"aws_kms_key",
"aws_lambda_function",
"aws_lambda_permission",
"aws_lb",
"aws_nat_gateway",
"aws_route_table",
"aws_route_table_association",
"aws_s3_bucket",
"aws_s3_bucket_policy",
"aws_s3_bucket_public_access_block",
"aws_secretsmanager_secret",
"aws_secretsmanager_secret_policy",
"aws_security_group",
"aws_security_group_rule",
"aws_sns_topic",
"aws_sqs_queue",
"aws_subnet",
"aws_vpc"
]
},
"resources": [
{
"address": "aws_db_instance.app",
"provider": "aws",
"resource_type": "aws_db_instance",
"name": "app",
"category": "data",
"identifier": "ecs-app-db",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [
"sg-ecs-db"
],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "sensitive",
"metadata": {
"engine": "postgres",
"publicly_accessible": false,
"public_access_reasons": [],
"public_exposure_reasons": [],
"storage_encrypted": true,
"db_subnet_group_name": null,
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_ecs_cluster.main",
"provider": "aws",
"resource_type": "aws_ecs_cluster",
"name": "main",
"category": "compute",
"identifier": "main",
"arn": "arn:aws:ecs:us-east-1:111122223333:cluster/main",
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"name": "main",
"capacity_providers": [],
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_ecs_service.app",
"provider": "aws",
"resource_type": "aws_ecs_service",
"name": "app",
"category": "compute",
"identifier": "app",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [
"subnet-ecs-private-app"
],
"security_group_ids": [
"sg-ecs-service"
],
"attached_role_arns": [
"arn:aws:iam::111122223333:role/app-task-role"
],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"cluster": "arn:aws:ecs:us-east-1:111122223333:cluster/main",
"task_definition": "arn:aws:ecs:us-east-1:111122223333:task-definition/app:1",
"desired_count": 2,
"launch_type": "FARGATE",
"platform_version": "1.4.0",
"assign_public_ip": false,
"load_balancers": [
{
"container_name": "app",
"container_port": 8080,
"target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/app/abcd"
}
],
"public_access_reasons": [],
"public_exposure_reasons": [],
"resolved_cluster_addresses": [
"aws_ecs_cluster.main"
],
"resolved_task_definition_addresses": [
"aws_ecs_task_definition.app"
],
"network_mode": "awsvpc",
"requires_compatibilities": [
"FARGATE"
],
"task_role_arn": "arn:aws:iam::111122223333:role/app-task-role",
"resolved_task_role_addresses": [
"aws_iam_role.task"
],
"execution_role_arn": "arn:aws:iam::111122223333:role/app-execution-role",
"resolved_execution_role_addresses": [
"aws_iam_role.execution"
],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false,
"fronted_by_internet_facing_load_balancer": true,
"internet_facing_load_balancer_addresses": [
"aws_lb.web"
]
}
},
{
"address": "aws_ecs_task_definition.app",
"provider": "aws",
"resource_type": "aws_ecs_task_definition",
"name": "app",
"category": "compute",
"identifier": "app:1",
"arn": "arn:aws:ecs:us-east-1:111122223333:task-definition/app:1",
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"family": "app",
"revision": 1,
"network_mode": "awsvpc",
"requires_compatibilities": [
"FARGATE"
],
"task_role_arn": "arn:aws:iam::111122223333:role/app-task-role",
"execution_role_arn": "arn:aws:iam::111122223333:role/app-execution-role",
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_iam_role.execution",
"provider": "aws",
"resource_type": "aws_iam_role",
"name": "execution",
"category": "iam",
"identifier": "app-execution-role",
"arn": "arn:aws:iam::111122223333:role/app-execution-role",
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [
{
"effect": "Allow",
"actions": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"resources": [
"*"
],
"principals": [],
"conditions": []
}
],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"assume_role_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
}
}
]
},
"trust_principals": [
"ecs-tasks.amazonaws.com"
],
"trust_statements": [
{
"principals": [
"ecs-tasks.amazonaws.com"
],
"narrowing_condition_keys": [],
"narrowing_conditions": [],
"has_narrowing_conditions": false
}
],
"inline_policy_names": [
"execution-logs"
],
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_iam_role.task",
"provider": "aws",
"resource_type": "aws_iam_role",
"name": "task",
"category": "iam",
"identifier": "app-task-role",
"arn": "arn:aws:iam::111122223333:role/app-task-role",
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [
{
"effect": "Allow",
"actions": [
"secretsmanager:GetSecretValue"
],
"resources": [
"*"
],
"principals": [],
"conditions": []
}
],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"assume_role_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
}
}
]
},
"trust_principals": [
"ecs-tasks.amazonaws.com"
],
"trust_statements": [
{
"principals": [
"ecs-tasks.amazonaws.com"
],
"narrowing_condition_keys": [],
"narrowing_conditions": [],
"has_narrowing_conditions": false
}
],
"inline_policy_names": [
"task-data-access"
],
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_internet_gateway.main",
"provider": "aws",
"resource_type": "aws_internet_gateway",
"name": "main",
"category": "network",
"identifier": "igw-ecs-001",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_lb.web",
"provider": "aws",
"resource_type": "aws_lb",
"name": "web",
"category": "edge",
"identifier": "alb-ecs-web",
"arn": "arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234",
"vpc_id": "vpc-ecs-001",
"subnet_ids": [
"subnet-ecs-public-a",
"subnet-ecs-public-b"
],
"security_group_ids": [
"sg-ecs-alb"
],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": true,
"public_exposure": true,
"data_sensitivity": "standard",
"metadata": {
"internal": false,
"load_balancer_type": "application",
"public_access_reasons": [
"load balancer is configured as internet-facing"
],
"public_exposure_reasons": [
"load balancer is internet-facing and attached security groups allow internet ingress"
],
"public_access_configured": true,
"internet_ingress": true,
"internet_ingress_capable": true,
"internet_ingress_reasons": [
"aws_security_group.alb ingress tcp 443 from 0.0.0.0/0"
],
"in_public_subnet": true,
"has_nat_gateway_egress": false,
"direct_internet_reachable": true
}
},
{
"address": "aws_route_table.private",
"provider": "aws",
"resource_type": "aws_route_table",
"name": "private",
"category": "network",
"identifier": "rtb-ecs-private",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"routes": [],
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_route_table.public",
"provider": "aws",
"resource_type": "aws_route_table",
"name": "public",
"category": "network",
"identifier": "rtb-ecs-public",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"routes": [
{
"cidr_block": "0.0.0.0/0",
"gateway_id": "igw-ecs-001"
}
],
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_route_table_association.private_app",
"provider": "aws",
"resource_type": "aws_route_table_association",
"name": "private_app",
"category": "network",
"identifier": "rtassoc-ecs-private-app",
"arn": null,
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"route_table_id": "rtb-ecs-private",
"subnet_id": "subnet-ecs-private-app",
"gateway_id": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_route_table_association.public_a",
"provider": "aws",
"resource_type": "aws_route_table_association",
"name": "public_a",
"category": "network",
"identifier": "rtassoc-ecs-public-a",
"arn": null,
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"route_table_id": "rtb-ecs-public",
"subnet_id": "subnet-ecs-public-a",
"gateway_id": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_route_table_association.public_b",
"provider": "aws",
"resource_type": "aws_route_table_association",
"name": "public_b",
"category": "network",
"identifier": "rtassoc-ecs-public-b",
"arn": null,
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"route_table_id": "rtb-ecs-public",
"subnet_id": "subnet-ecs-public-b",
"gateway_id": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_secretsmanager_secret.app",
"provider": "aws",
"resource_type": "aws_secretsmanager_secret",
"name": "app",
"category": "data",
"identifier": "ecs-app-secret",
"arn": "arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret",
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "sensitive",
"metadata": {
"name": "ecs-app-secret",
"kms_key_id": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_security_group.alb",
"provider": "aws",
"resource_type": "aws_security_group",
"name": "alb",
"category": "network",
"identifier": "sg-ecs-alb",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [
{
"direction": "ingress",
"protocol": "tcp",
"from_port": 443,
"to_port": 443,
"cidr_blocks": [
"0.0.0.0/0"
],
"ipv6_cidr_blocks": [],
"referenced_security_group_ids": [],
"description": null
},
{
"direction": "egress",
"protocol": "-1",
"from_port": 0,
"to_port": 0,
"cidr_blocks": [
"0.0.0.0/0"
],
"ipv6_cidr_blocks": [],
"referenced_security_group_ids": [],
"description": null
}
],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"description": null,
"group_name": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_security_group.db",
"provider": "aws",
"resource_type": "aws_security_group",
"name": "db",
"category": "network",
"identifier": "sg-ecs-db",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [
{
"direction": "ingress",
"protocol": "tcp",
"from_port": 5432,
"to_port": 5432,
"cidr_blocks": [],
"ipv6_cidr_blocks": [],
"referenced_security_group_ids": [
"sg-ecs-service"
],
"description": null
}
],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"description": null,
"group_name": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_security_group.ecs",
"provider": "aws",
"resource_type": "aws_security_group",
"name": "ecs",
"category": "network",
"identifier": "sg-ecs-service",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [
{
"direction": "ingress",
"protocol": "tcp",
"from_port": 8080,
"to_port": 8080,
"cidr_blocks": [],
"ipv6_cidr_blocks": [],
"referenced_security_group_ids": [
"sg-ecs-alb"
],
"description": null
},
{
"direction": "egress",
"protocol": "-1",
"from_port": 0,
"to_port": 0,
"cidr_blocks": [
"0.0.0.0/0"
],
"ipv6_cidr_blocks": [],
"referenced_security_group_ids": [],
"description": null
}
],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"description": null,
"group_name": null,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
},
{
"address": "aws_subnet.private_app",
"provider": "aws",
"resource_type": "aws_subnet",
"name": "private_app",
"category": "network",
"identifier": "subnet-ecs-private-app",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"cidr_block": "10.60.10.0/24",
"availability_zone": "us-east-1a",
"map_public_ip_on_launch": false,
"tags": {},
"is_public_subnet": false,
"route_table_ids": [
"rtb-ecs-private"
],
"has_public_route": false,
"has_nat_gateway_egress": false,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"direct_internet_reachable": false
}
},
{
"address": "aws_subnet.public_a",
"provider": "aws",
"resource_type": "aws_subnet",
"name": "public_a",
"category": "network",
"identifier": "subnet-ecs-public-a",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"cidr_block": "10.60.1.0/24",
"availability_zone": "us-east-1a",
"map_public_ip_on_launch": true,
"tags": {},
"is_public_subnet": true,
"route_table_ids": [
"rtb-ecs-public"
],
"has_public_route": true,
"has_nat_gateway_egress": false,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"direct_internet_reachable": false
}
},
{
"address": "aws_subnet.public_b",
"provider": "aws",
"resource_type": "aws_subnet",
"name": "public_b",
"category": "network",
"identifier": "subnet-ecs-public-b",
"arn": null,
"vpc_id": "vpc-ecs-001",
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"cidr_block": "10.60.2.0/24",
"availability_zone": "us-east-1b",
"map_public_ip_on_launch": true,
"tags": {},
"is_public_subnet": true,
"route_table_ids": [
"rtb-ecs-public"
],
"has_public_route": true,
"has_nat_gateway_egress": false,
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"direct_internet_reachable": false
}
},
{
"address": "aws_vpc.main",
"provider": "aws",
"resource_type": "aws_vpc",
"name": "main",
"category": "network",
"identifier": "vpc-ecs-001",
"arn": null,
"vpc_id": null,
"subnet_ids": [],
"security_group_ids": [],
"attached_role_arns": [],
"network_rules": [],
"policy_statements": [],
"public_access_configured": false,
"public_exposure": false,
"data_sensitivity": "standard",
"metadata": {
"cidr_block": "10.60.0.0/16",
"tags": {},
"public_access_reasons": [],
"public_exposure_reasons": [],
"public_access_configured": false,
"internet_ingress": false,
"internet_ingress_capable": false,
"internet_ingress_reasons": [],
"in_public_subnet": false,
"has_nat_gateway_egress": false,
"direct_internet_reachable": false
}
}
]
},
"trust_boundaries": [
{
"identifier": "admin-to-workload-plane:aws_iam_role.task->aws_ecs_service.app",
"boundary_type": "admin-to-workload-plane",
"source": "aws_iam_role.task",
"target": "aws_ecs_service.app",
"description": "aws_iam_role.task governs actions performed by aws_ecs_service.app.",
"rationale": "IAM configuration acts as a control-plane boundary because the workload inherits whatever privileges the role carries."
},
{
"identifier": "internet-to-service:internet->aws_lb.web",
"boundary_type": "internet-to-service",
"source": "internet",
"target": "aws_lb.web",
"description": "Traffic can cross from the public internet to aws_lb.web.",
"rationale": "The resource is directly reachable or intentionally exposed to unauthenticated network clients."
},
{
"identifier": "public-subnet-to-private-subnet:aws_subnet.public_a->aws_subnet.private_app",
"boundary_type": "public-subnet-to-private-subnet",
"source": "aws_subnet.public_a",
"target": "aws_subnet.private_app",
"description": "Traffic can move from aws_subnet.public_a toward aws_subnet.private_app.",
"rationale": "The VPC contains both publicly routable and private network segments that should be treated as separate trust zones."
},
{
"identifier": "public-subnet-to-private-subnet:aws_subnet.public_b->aws_subnet.private_app",
"boundary_type": "public-subnet-to-private-subnet",
"source": "aws_subnet.public_b",
"target": "aws_subnet.private_app",
"description": "Traffic can move from aws_subnet.public_b toward aws_subnet.private_app.",
"rationale": "The VPC contains both publicly routable and private network segments that should be treated as separate trust zones."
},
{
"identifier": "workload-to-data-store:aws_ecs_service.app->aws_db_instance.app",
"boundary_type": "workload-to-data-store",
"source": "aws_ecs_service.app",
"target": "aws_db_instance.app",
"description": "aws_ecs_service.app can interact with aws_db_instance.app.",
"rationale": "Application or function workloads cross into a higher-sensitivity data plane when database ingress security groups explicitly trust the workload security group."
},
{
"identifier": "workload-to-data-store:aws_ecs_service.app->aws_secretsmanager_secret.app",
"boundary_type": "workload-to-data-store",
"source": "aws_ecs_service.app",
"target": "aws_secretsmanager_secret.app",
"description": "aws_ecs_service.app can interact with aws_secretsmanager_secret.app.",
"rationale": "Application or function workloads cross into a higher-sensitivity secret plane when their attached role allows Secrets Manager retrieval actions such as secretsmanager:GetSecretValue."
}
],
"findings": [
{
"fingerprint": "sha256:5ec3fb62a663e1454a2ce20663078ed81272c11ab55dec52a1ab143de38df967",
"title": "IAM policy grants wildcard privileges",
"rule_id": "aws-iam-wildcard-permissions",
"category": "Elevation of Privilege",
"severity": "medium",
"affected_resources": [
"aws_iam_role.task"
],
"trust_boundary_id": null,
"rationale": "aws_iam_role.task contains allow statements with wildcard actions or resources. That makes the resulting access difficult to reason about and expands blast radius.",
"recommended_mitigation": "Replace wildcard actions and resources with narrowly scoped permissions tied to the exact services, APIs, and ARNs required by the workload.",
"evidence": [
{
"key": "iam_resources",
"values": [
"*"
]
},
{
"key": "policy_statements",
"values": [
"Allow actions=[secretsmanager:GetSecretValue] resources=[*]"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 1,
"data_sensitivity": 0,
"lateral_movement": 1,
"blast_radius": 2,
"final_score": 4,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:d95bd2a4e3fd2829972048abcecf45fe90662e812ce2eb3b37f6435011b44034",
"title": "IAM policy grants wildcard privileges",
"rule_id": "aws-iam-wildcard-permissions",
"category": "Elevation of Privilege",
"severity": "medium",
"affected_resources": [
"aws_iam_role.execution"
],
"trust_boundary_id": null,
"rationale": "aws_iam_role.execution contains allow statements with wildcard actions or resources. That makes the resulting access difficult to reason about and expands blast radius.",
"recommended_mitigation": "Replace wildcard actions and resources with narrowly scoped permissions tied to the exact services, APIs, and ARNs required by the workload.",
"evidence": [
{
"key": "iam_resources",
"values": [
"*"
]
},
{
"key": "policy_statements",
"values": [
"Allow actions=[logs:CreateLogStream, logs:PutLogEvents] resources=[*]"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 1,
"data_sensitivity": 0,
"lateral_movement": 1,
"blast_radius": 2,
"final_score": 4,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:65323e63a70a2e0d38e94cde539c6426ef31fc7ef547e3be179f7a5f6ab48d4b",
"title": "Sensitive data tier is transitively reachable from an internet-exposed path",
"rule_id": "aws-private-data-transitive-exposure",
"category": "Information Disclosure",
"severity": "medium",
"affected_resources": [
"aws_lb.web",
"aws_ecs_service.app",
"aws_db_instance.app",
"aws_security_group.ecs"
],
"trust_boundary_id": "workload-to-data-store:aws_ecs_service.app->aws_db_instance.app",
"rationale": "aws_db_instance.app is not directly public, but internet traffic can first reach aws_lb.web, move through aws_lb.web can reach aws_ecs_service.app, and then cross into the private data tier through aws_ecs_service.app. That creates a quieter transitive exposure path than a directly public data store.",
"recommended_mitigation": "Keep internet-adjacent entry points from chaining into workloads that retain database or secret access, narrow edge-to-workload and workload-to-workload trust, and isolate sensitive data access behind more deliberate service boundaries.",
"evidence": [
{
"key": "network_path",
"values": [
"internet reaches aws_lb.web",
"aws_lb.web reaches aws_ecs_service.app",
"aws_ecs_service.app reaches aws_db_instance.app"
]
},
{
"key": "security_group_rules",
"values": [
"aws_security_group.ecs ingress tcp 8080 from sg-ecs-alb"
]
},
{
"key": "subnet_posture",
"values": [
"aws_lb.web sits in public subnet aws_subnet.public_a with an internet route",
"aws_lb.web sits in public subnet aws_subnet.public_b with an internet route",
"aws_ecs_service.app sits in private subnet aws_subnet.private_app"
]
},
{
"key": "data_tier_posture",
"values": [
"aws_db_instance.app is not directly public",
"database has no direct internet ingress path"
]
},
{
"key": "boundary_rationale",
"values": [
"Application or function workloads cross into a higher-sensitivity data plane when database ingress security groups explicitly trust the workload security group."
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 0,
"data_sensitivity": 2,
"lateral_movement": 2,
"blast_radius": 1,
"final_score": 5,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:9ed7390fcb1824a244102c4602ae7f35c896338b19c28a30145057cc9c7cbfe4",
"title": "Sensitive data tier is transitively reachable from an internet-exposed path",
"rule_id": "aws-private-data-transitive-exposure",
"category": "Information Disclosure",
"severity": "medium",
"affected_resources": [
"aws_lb.web",
"aws_ecs_service.app",
"aws_secretsmanager_secret.app",
"aws_security_group.ecs"
],
"trust_boundary_id": "workload-to-data-store:aws_ecs_service.app->aws_secretsmanager_secret.app",
"rationale": "aws_secretsmanager_secret.app is not directly public, but internet traffic can first reach aws_lb.web, move through aws_lb.web can reach aws_ecs_service.app, and then cross into the private data tier through aws_ecs_service.app. That creates a quieter transitive exposure path than a directly public data store.",
"recommended_mitigation": "Keep internet-adjacent entry points from chaining into workloads that retain database or secret access, narrow edge-to-workload and workload-to-workload trust, and isolate sensitive data access behind more deliberate service boundaries.",
"evidence": [
{
"key": "network_path",
"values": [
"internet reaches aws_lb.web",
"aws_lb.web reaches aws_ecs_service.app",
"aws_ecs_service.app reaches aws_secretsmanager_secret.app"
]
},
{
"key": "security_group_rules",
"values": [
"aws_security_group.ecs ingress tcp 8080 from sg-ecs-alb"
]
},
{
"key": "subnet_posture",
"values": [
"aws_lb.web sits in public subnet aws_subnet.public_a with an internet route",
"aws_lb.web sits in public subnet aws_subnet.public_b with an internet route",
"aws_ecs_service.app sits in private subnet aws_subnet.private_app"
]
},
{
"key": "data_tier_posture",
"values": [
"aws_secretsmanager_secret.app is not directly public"
]
},
{
"key": "boundary_rationale",
"values": [
"Application or function workloads cross into a higher-sensitivity secret plane when their attached role allows Secrets Manager retrieval actions such as secretsmanager:GetSecretValue."
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 0,
"data_sensitivity": 2,
"lateral_movement": 2,
"blast_radius": 1,
"final_score": 5,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:8385f532d643a9bf640d963169a2e2c0575c59324bf7c0447e38b6070c34996f",
"title": "Workload role carries sensitive permissions",
"rule_id": "aws-workload-role-sensitive-permissions",
"category": "Elevation of Privilege",
"severity": "medium",
"affected_resources": [
"aws_ecs_service.app",
"aws_iam_role.task"
],
"trust_boundary_id": "admin-to-workload-plane:aws_iam_role.task->aws_ecs_service.app",
"rationale": "aws_ecs_service.app inherits sensitive privileges from aws_iam_role.task, including secretsmanager:GetSecretValue. If the workload is compromised, those credentials can be reused for privilege escalation, data access, or role chaining.",
"recommended_mitigation": "Split high-privilege actions into separate roles, scope permissions to named resources, and remove role-passing or cross-role permissions from general application identities.",
"evidence": [
{
"key": "iam_actions",
"values": [
"secretsmanager:GetSecretValue"
]
},
{
"key": "policy_statements",
"values": [
"Allow actions=[secretsmanager:GetSecretValue] resources=[*]"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 1,
"data_sensitivity": 1,
"lateral_movement": 1,
"blast_radius": 2,
"final_score": 5,
"severity": "medium",
"computed_severity": null
}
}
],
"suppressed_findings": [],
"baselined_findings": [],
"observations": [
{
"title": "RDS instance is private and storage encrypted",
"observation_id": "aws-rds-private-encrypted",
"affected_resources": [
"aws_db_instance.app"
],
"rationale": "aws_db_instance.app is kept off direct internet paths and has storage encryption enabled, which reduces straightforward data exposure risk.",
"category": "data-protection",
"evidence": [
{
"key": "database_posture",
"values": [
"publicly_accessible is false",
"storage_encrypted is true",
"no attached security group allows internet ingress",
"engine is postgres"
]
}
]
}
],
"limitations": [
"AWS support is intentionally limited to a curated v1 resource set rather than the full Terraform AWS provider.",
"Subnet public/private classification prefers explicit route table associations and NAT or internet routes when present, but it does not model main-route-table inheritance or every routing edge case.",
"IAM analysis resolves inline role policies, customer-managed role-policy attachments, and EC2 instance profiles present in the plan, but it does not expand AWS-managed policy documents that are not materialized in Terraform state.",
"Resource-policy analysis focuses on explicit policy documents and Lambda permission resources present in the plan; it does not model every service-specific condition key or every downstream runtime authorization path.",
"The engine reasons over Terraform planned values only and does not validate runtime drift, CloudTrail evidence, or post-deploy control-plane activity."
]
}
Markdown report
# ECS / Fargate Demo
- Analyzed file: `sample_aws_ecs_fargate_plan.json`
- Provider: `aws`
- Normalized resources: `21`
- Unsupported resources: `0`
## Summary
This run identified **6 trust boundaries** and **5 findings** across **21 normalized resources**.
- High severity findings: `0`
- Medium severity findings: `5`
- Low severity findings: `0`
## Discovered Trust Boundaries
### `internet-to-service`
- Source: `internet`
- Target: `aws_lb.web`
- Description: Traffic can cross from the public internet to aws_lb.web.
- Rationale: The resource is directly reachable or intentionally exposed to unauthenticated network clients.
### `public-subnet-to-private-subnet`
- Source: `aws_subnet.public_a`
- Target: `aws_subnet.private_app`
- Description: Traffic can move from aws_subnet.public_a toward aws_subnet.private_app.
- Rationale: The VPC contains both publicly routable and private network segments that should be treated as separate trust zones.
### `public-subnet-to-private-subnet`
- Source: `aws_subnet.public_b`
- Target: `aws_subnet.private_app`
- Description: Traffic can move from aws_subnet.public_b toward aws_subnet.private_app.
- Rationale: The VPC contains both publicly routable and private network segments that should be treated as separate trust zones.
### `workload-to-data-store`
- Source: `aws_ecs_service.app`
- Target: `aws_db_instance.app`
- Description: aws_ecs_service.app can interact with aws_db_instance.app.
- Rationale: Application or function workloads cross into a higher-sensitivity data plane when database ingress security groups explicitly trust the workload security group.
### `workload-to-data-store`
- Source: `aws_ecs_service.app`
- Target: `aws_secretsmanager_secret.app`
- Description: aws_ecs_service.app can interact with aws_secretsmanager_secret.app.
- Rationale: Application or function workloads cross into a higher-sensitivity secret plane when their attached role allows Secrets Manager retrieval actions such as secretsmanager:GetSecretValue.
### `admin-to-workload-plane`
- Source: `aws_iam_role.task`
- Target: `aws_ecs_service.app`
- Description: aws_iam_role.task governs actions performed by aws_ecs_service.app.
- Rationale: IAM configuration acts as a control-plane boundary because the workload inherits whatever privileges the role carries.
## Findings
### High
No findings in this severity band.
### Medium
#### IAM policy grants wildcard privileges
- STRIDE category: Elevation of Privilege
- Affected resources: `aws_iam_role.task`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +1, data_sensitivity +0, lateral_movement +1, blast_radius +2, final_score 4 => medium
- Rationale: aws_iam_role.task contains allow statements with wildcard actions or resources. That makes the resulting access difficult to reason about and expands blast radius.
- Recommended mitigation: Replace wildcard actions and resources with narrowly scoped permissions tied to the exact services, APIs, and ARNs required by the workload.
- Evidence:
- iam resources: *
- policy statements: Allow actions=[secretsmanager:GetSecretValue] resources=[*]
#### IAM policy grants wildcard privileges
- STRIDE category: Elevation of Privilege
- Affected resources: `aws_iam_role.execution`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +1, data_sensitivity +0, lateral_movement +1, blast_radius +2, final_score 4 => medium
- Rationale: aws_iam_role.execution contains allow statements with wildcard actions or resources. That makes the resulting access difficult to reason about and expands blast radius.
- Recommended mitigation: Replace wildcard actions and resources with narrowly scoped permissions tied to the exact services, APIs, and ARNs required by the workload.
- Evidence:
- iam resources: *
- policy statements: Allow actions=[logs:CreateLogStream, logs:PutLogEvents] resources=[*]
#### Sensitive data tier is transitively reachable from an internet-exposed path
- STRIDE category: Information Disclosure
- Affected resources: `aws_lb.web`, `aws_ecs_service.app`, `aws_db_instance.app`, `aws_security_group.ecs`
- Trust boundary: `workload-to-data-store:aws_ecs_service.app->aws_db_instance.app`
- Severity reasoning: internet_exposure +0, privilege_breadth +0, data_sensitivity +2, lateral_movement +2, blast_radius +1, final_score 5 => medium
- Rationale: aws_db_instance.app is not directly public, but internet traffic can first reach aws_lb.web, move through aws_lb.web can reach aws_ecs_service.app, and then cross into the private data tier through aws_ecs_service.app. That creates a quieter transitive exposure path than a directly public data store.
- Recommended mitigation: Keep internet-adjacent entry points from chaining into workloads that retain database or secret access, narrow edge-to-workload and workload-to-workload trust, and isolate sensitive data access behind more deliberate service boundaries.
- Evidence:
- network path: internet reaches aws_lb.web; aws_lb.web reaches aws_ecs_service.app; aws_ecs_service.app reaches aws_db_instance.app
- security group rules: aws_security_group.ecs ingress tcp 8080 from sg-ecs-alb
- subnet posture: aws_lb.web sits in public subnet aws_subnet.public_a with an internet route; aws_lb.web sits in public subnet aws_subnet.public_b with an internet route; aws_ecs_service.app sits in private subnet aws_subnet.private_app
- data tier posture: aws_db_instance.app is not directly public; database has no direct internet ingress path
- boundary rationale: Application or function workloads cross into a higher-sensitivity data plane when database ingress security groups explicitly trust the workload security group.
#### Sensitive data tier is transitively reachable from an internet-exposed path
- STRIDE category: Information Disclosure
- Affected resources: `aws_lb.web`, `aws_ecs_service.app`, `aws_secretsmanager_secret.app`, `aws_security_group.ecs`
- Trust boundary: `workload-to-data-store:aws_ecs_service.app->aws_secretsmanager_secret.app`
- Severity reasoning: internet_exposure +0, privilege_breadth +0, data_sensitivity +2, lateral_movement +2, blast_radius +1, final_score 5 => medium
- Rationale: aws_secretsmanager_secret.app is not directly public, but internet traffic can first reach aws_lb.web, move through aws_lb.web can reach aws_ecs_service.app, and then cross into the private data tier through aws_ecs_service.app. That creates a quieter transitive exposure path than a directly public data store.
- Recommended mitigation: Keep internet-adjacent entry points from chaining into workloads that retain database or secret access, narrow edge-to-workload and workload-to-workload trust, and isolate sensitive data access behind more deliberate service boundaries.
- Evidence:
- network path: internet reaches aws_lb.web; aws_lb.web reaches aws_ecs_service.app; aws_ecs_service.app reaches aws_secretsmanager_secret.app
- security group rules: aws_security_group.ecs ingress tcp 8080 from sg-ecs-alb
- subnet posture: aws_lb.web sits in public subnet aws_subnet.public_a with an internet route; aws_lb.web sits in public subnet aws_subnet.public_b with an internet route; aws_ecs_service.app sits in private subnet aws_subnet.private_app
- data tier posture: aws_secretsmanager_secret.app is not directly public
- boundary rationale: Application or function workloads cross into a higher-sensitivity secret plane when their attached role allows Secrets Manager retrieval actions such as secretsmanager:GetSecretValue.
#### Workload role carries sensitive permissions
- STRIDE category: Elevation of Privilege
- Affected resources: `aws_ecs_service.app`, `aws_iam_role.task`
- Trust boundary: `admin-to-workload-plane:aws_iam_role.task->aws_ecs_service.app`
- Severity reasoning: internet_exposure +0, privilege_breadth +1, data_sensitivity +1, lateral_movement +1, blast_radius +2, final_score 5 => medium
- Rationale: aws_ecs_service.app inherits sensitive privileges from aws_iam_role.task, including secretsmanager:GetSecretValue. If the workload is compromised, those credentials can be reused for privilege escalation, data access, or role chaining.
- Recommended mitigation: Split high-privilege actions into separate roles, scope permissions to named resources, and remove role-passing or cross-role permissions from general application identities.
- Evidence:
- iam actions: secretsmanager:GetSecretValue
- policy statements: Allow actions=[secretsmanager:GetSecretValue] resources=[*]
### Low
No findings in this severity band.
## Controls Observed
### RDS instance is private and storage encrypted
- Category: `data-protection`
- Affected resources: `aws_db_instance.app`
- Rationale: aws_db_instance.app is kept off direct internet paths and has storage encryption enabled, which reduces straightforward data exposure risk.
- Evidence:
- database posture: publicly_accessible is false; storage_encrypted is true; no attached security group allows internet ingress; engine is postgres
## Limitations / Unsupported Resources
- AWS support is intentionally limited to a curated v1 resource set rather than the full Terraform AWS provider.
- Subnet public/private classification prefers explicit route table associations and NAT or internet routes when present, but it does not model main-route-table inheritance or every routing edge case.
- IAM analysis resolves inline role policies, customer-managed role-policy attachments, and EC2 instance profiles present in the plan, but it does not expand AWS-managed policy documents that are not materialized in Terraform state.
- Resource-policy analysis focuses on explicit policy documents and Lambda permission resources present in the plan; it does not model every service-specific condition key or every downstream runtime authorization path.
- The engine reasons over Terraform planned values only and does not validate runtime drift, CloudTrail evidence, or post-deploy control-plane activity.
Limits
Unsupported or intentionally scoped areas
- AWS support is intentionally limited to a curated v1 resource set rather than the full Terraform AWS provider.
- Subnet public/private classification prefers explicit route table associations and NAT or internet routes when present, but it does not model main-route-table inheritance or every routing edge case.
- IAM analysis resolves inline role policies, customer-managed role-policy attachments, and EC2 instance profiles present in the plan, but it does not expand AWS-managed policy documents that are not materialized in Terraform state.
- Resource-policy analysis focuses on explicit policy documents and Lambda permission resources present in the plan; it does not model every service-specific condition key or every downstream runtime authorization path.
- The engine reasons over Terraform planned values only and does not validate runtime drift, CloudTrail evidence, or post-deploy control-plane activity.