Built-in scenario

sample_aws_ecs_fargate_plan.json

ECS / Fargate Demo

Analyzed sample_aws_ecs_fargate_plan.json with 21 normalized resources and 6 trust boundaries.

Analyze another plan

Active findings

5

Trust boundaries

6

Resources

21

Observations

1
High 0
Medium 5
Low 0

Findings

Severity bands

High

0

No high findings.

Medium

5

IAM policy grants wildcard privileges

aws-iam-wildcard-permissions

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.

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-permissions

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.

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-exposure

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.

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-exposure

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.

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-permissions

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.

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

0

No 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.

aws_db_instance.app

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.