Active findings
12Built-in scenario
aws/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
1Analysis coverage
Audit trail for this run
Resource coverage
- Provider resources considered
- 21
- Normalized resources
- 21
No unsupported AWS resource types were encountered.
Rule coverage
- Registered rules
- 83
- Disabled rules
- 0
- aws-public-alb-waf-missing1
- aws-rds-cloudwatch-log-exports-missing1
- aws-secretsmanager-customer-managed-kms-key-missing1
- aws-secretsmanager-rotation-not-configured-or-too-long1
- aws-workload-secretsmanager-vpc-endpoint-missing1
- aws-vpc-flow-logs-not-configured1
- aws-iam-wildcard-permissions2
- aws-iam-privileged-role-assignment1
- aws-workload-role-sensitive-permissions1
- aws-private-data-transitive-exposure2
Findings
Severity bands
High
1IAM role has privileged assignment posture
aws-iam-privileged-role-assignmentaws_iam_role.task has deterministic privileged IAM assignment posture: secrets-admin. If this role is attached to a workload or assumable by a control-plane principal, those privileges increase blast radius.
- Category
- Elevation of Privilege
- Boundary
- not-applicable
- Resources
- aws_iam_role.task
Evidence
- iam role: address=aws_iam_role.task; type=aws_iam_role; arn=arn:aws:iam::111122223333:role/app-task-role; identifier=app-task-role
- privileged access: grant_1=categories=[secrets-admin]; scope=account; confidence=high
- privilege categories: secrets-admin
- grant scopes: scope_kind=account; scope_value=*
- grant confidence: high
- inline policy sources: inline_policy_name=task-data-access
Medium
10IAM 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=[*]
Public Application Load Balancer is not associated with a WAF Web ACL
aws-public-alb-waf-missingaws_lb.web is an internet-facing Application Load Balancer, but the Terraform plan does not show a deterministic AWS WAFv2 Web ACL association targeting it. Public edge traffic can reach the ALB without a modeled WAF or edge protection policy.
- Category
- Tampering
- Boundary
- not-applicable
- Resources
- aws_lb.web
Evidence
- target load balancer: address=aws_lb.web; type=aws_lb; arn=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234; load_balancer_type=application; public_exposure=true; load balancer is internet-facing and attached security groups allow internet ingress
- waf association coverage: target_resource_arn=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234; resolved_web_acl_association_count=0; modeled_web_acl_association_count=0
Secrets Manager rotation is not configured or too infrequent
aws-secretsmanager-rotation-not-configured-or-too-longaws_secretsmanager_secret.app does not show a deterministic Secrets Manager rotation resource in the Terraform plan. Static or manually rotated secrets can remain valid longer after disclosure, service compromise, or operator error.
- Category
- Information Disclosure
- Boundary
- not-applicable
- Resources
- aws_secretsmanager_secret.app
Evidence
- target resource: address=aws_secretsmanager_secret.app; type=aws_secretsmanager_secret; identifier=ecs-app-secret; arn=arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret
- rotation posture: rotation_state=not_configured; maximum_rotation_interval_days=90; aws_secretsmanager_secret_rotation resource was not resolved for this secret
Secrets Manager secret does not use a customer-managed KMS key
aws-secretsmanager-customer-managed-kms-key-missingaws_secretsmanager_secret.app does not show a deterministic customer-managed KMS key in the Terraform plan. Secrets Manager AWS-managed encryption may still apply; this finding concerns customer key ownership, rotation, audit separation, and compliance posture.
- Category
- Information Disclosure
- Boundary
- not-applicable
- Resources
- aws_secretsmanager_secret.app
Evidence
- target resource: address=aws_secretsmanager_secret.app; type=aws_secretsmanager_secret; identifier=ecs-app-secret; arn=arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret
- encryption ownership: customer_managed_kms_state=not_configured; kms_key_id is unset; AWS-managed encryption may still apply; this finding concerns customer key control
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.
VPC Flow Logs are not configured for a modeled VPC
aws-vpc-flow-logs-not-configuredaws_vpc.main does not have a resolved aws_flow_log targeting the VPC in this Terraform plan. Network traffic metadata for incident response, threat hunting, and segmentation review may be unavailable unless Flow Logs are configured elsewhere.
- Category
- Repudiation
- Boundary
- not-applicable
- Resources
- aws_vpc.main
Evidence
- target vpc: address=aws_vpc.main; type=aws_vpc; identifier=vpc-ecs-001; cidr_block=10.60.0.0/16
- flow log coverage: target_vpc_id=vpc-ecs-001; resolved_vpc_flow_log_count=0; aws_flow_log resources are not modeled
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=[*]
Workload uses Secrets Manager without a VPC endpoint
aws-workload-secretsmanager-vpc-endpoint-missingaws_ecs_service.app runs in VPC `vpc-ecs-001` and inherits Secrets Manager secret retrieval from aws_iam_role.task, but the Terraform plan does not show a Secrets Manager interface VPC endpoint for that VPC. Calls to the sensitive service may therefore depend on public AWS service endpoints, NAT, or another egress path.
- Category
- Information Disclosure
- Boundary
- not-applicable
- Resources
- aws_ecs_service.app, aws_iam_role.task
Evidence
- target workload: address=aws_ecs_service.app; type=aws_ecs_service; vpc_id=vpc-ecs-001; subnet_ids=[subnet-ecs-private-app]; security_group_ids=[sg-ecs-service]
- sensitive service dependency: service=secretsmanager; role=aws_iam_role.task; actions=[secretsmanager:GetSecretValue]; resources=[*]
- vpc endpoint coverage: vpc_id=vpc-ecs-001; service=secretsmanager; expected_endpoint_type=interface; vpc_endpoint_coverage=missing
- policy statements: Allow actions=[secretsmanager:GetSecretValue] resources=[*]
Low
1RDS database does not export engine CloudWatch logs
aws-rds-cloudwatch-log-exports-missingaws_db_instance.app (engine `postgres`) does not export any of the baseline CloudWatch Logs expected for its engine family (postgresql). Without these log exports the database lacks the basic observability posture needed to investigate errors, slow queries, and audit activity from CloudWatch.
- Category
- Repudiation
- Boundary
- not-applicable
- Resources
- aws_db_instance.app
Evidence
- target resource: address=aws_db_instance.app; type=aws_db_instance; identifier=ecs-app-db; engine=postgres
- log export posture: enabled_cloudwatch_logs_exports=[]; expected_log_exports=['postgresql']; engine-family baseline log exports are absent
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": "tfstride-report",
"version": "1.1",
"tool": {
"name": "tfstride",
"version": "0.4.23"
},
"title": "ECS / Fargate Demo",
"analyzed_file": "sample_aws_ecs_fargate_plan.json",
"analyzed_path": "sample_aws_ecs_fargate_plan.json",
"summary": {
"normalized_resources": 21,
"unsupported_resources": 0,
"trust_boundaries": 6,
"active_findings": 12,
"total_findings": 12,
"suppressed_findings": 0,
"baselined_findings": 0,
"severity_counts": {
"high": 1,
"medium": 10,
"low": 1
}
},
"filtering": {
"total_findings": 12,
"active_findings": 12,
"suppressed_findings": 0,
"baselined_findings": 0,
"suppressions_path": null,
"baseline_path": null
},
"analysis_coverage": {
"resources": {
"total_resources": 21,
"provider_resources": 21,
"normalized_resources": 21,
"unsupported_resources": 0,
"unsupported_resource_types": {}
},
"rules": {
"registered_rule_count": 83,
"enabled_rules": [
"aws-public-compute-broad-ingress",
"aws-lambda-public-invocation",
"aws-load-balancer-http-public-listener",
"aws-load-balancer-listener-tls-certificate-missing",
"aws-load-balancer-listener-ssl-policy-weak-or-unknown",
"aws-public-alb-waf-missing",
"aws-cloudfront-viewer-http-allowed",
"aws-cloudfront-viewer-tls-policy-weak-or-unknown",
"aws-cloudfront-access-logging-not-configured",
"aws-public-cloudfront-waf-missing",
"aws-api-gateway-cors-permissive",
"aws-public-api-gateway-waf-missing",
"aws-api-gateway-public-route-authorization-none",
"aws-api-gateway-stage-access-logs-missing",
"aws-cloudtrail-multi-region-disabled",
"aws-cloudtrail-log-file-validation-disabled",
"aws-cloudtrail-management-events-disabled",
"aws-cloudtrail-data-events-not-modeled",
"aws-cloudtrail-insight-selectors-missing",
"aws-guardduty-detector-disabled-or-missing",
"aws-securityhub-account-missing",
"aws-config-recorder-disabled-or-missing",
"aws-config-delivery-channel-missing",
"aws-access-analyzer-not-configured",
"aws-macie-not-enabled-for-sensitive-storage",
"aws-rds-storage-encryption-disabled",
"aws-rds-public-endpoint-enabled",
"aws-rds-backup-retention-insufficient",
"aws-rds-deletion-protection-disabled",
"aws-rds-customer-managed-kms-key-missing",
"aws-rds-multi-az-disabled",
"aws-rds-performance-insights-disabled",
"aws-rds-cloudwatch-log-exports-missing",
"aws-rds-iam-auth-disabled",
"aws-s3-public-access",
"aws-s3-customer-managed-encryption-missing",
"aws-s3-versioning-disabled",
"aws-s3-object-lock-retention-missing",
"aws-s3-lifecycle-noncurrent-retention-insufficient",
"aws-ecr-image-tag-mutability-enabled",
"aws-ecr-customer-managed-encryption-missing",
"aws-ecr-repository-scanning-disabled",
"aws-workload-image-not-digest-pinned",
"aws-workload-ecr-mutable-tag",
"aws-workload-can-modify-image-repository",
"aws-ecs-sensitive-environment-value-inline",
"aws-ecs-secret-access-blast-radius",
"aws-public-ecs-secret-access",
"aws-public-ecs-s3-mutation-access",
"aws-public-ecs-messaging-mutation-access",
"aws-sns-customer-managed-encryption-missing",
"aws-sqs-customer-managed-encryption-missing",
"aws-sqs-message-retention-insufficient",
"aws-sqs-dead-letter-queue-not-configured",
"aws-secretsmanager-customer-managed-kms-key-missing",
"aws-secretsmanager-recovery-window-too-short",
"aws-secretsmanager-rotation-not-configured-or-too-long",
"aws-kms-key-rotation-disabled-or-unknown",
"aws-kms-key-deletion-window-too-short",
"aws-workload-secretsmanager-vpc-endpoint-missing",
"aws-workload-kms-vpc-endpoint-missing",
"aws-workload-s3-vpc-endpoint-missing",
"aws-vpc-endpoint-policy-broad-access",
"aws-vpc-flow-logs-not-configured",
"aws-vpc-flow-log-traffic-type-incomplete",
"aws-vpc-flow-log-destination-missing",
"aws-eks-api-endpoint-public-unrestricted",
"aws-eks-private-endpoint-not-enabled",
"aws-eks-secrets-encryption-not-configured",
"aws-eks-control-plane-logging-incomplete",
"aws-eks-authentication-mode-weak-or-unknown",
"aws-eks-vpc-cni-network-policy-not-enabled",
"aws-database-permissive-ingress",
"aws-missing-tier-segmentation",
"aws-sensitive-resource-policy-external-access",
"aws-service-resource-policy-external-access",
"aws-iam-wildcard-permissions",
"aws-iam-privileged-role-assignment",
"aws-workload-role-sensitive-permissions",
"aws-private-data-transitive-exposure",
"aws-control-plane-sensitive-workload-chain",
"aws-role-trust-expansion",
"aws-role-trust-missing-narrowing"
],
"disabled_rules": [],
"severity_overrides": {},
"finding_counts_by_rule": {
"aws-public-compute-broad-ingress": 0,
"aws-lambda-public-invocation": 0,
"aws-load-balancer-http-public-listener": 0,
"aws-load-balancer-listener-tls-certificate-missing": 0,
"aws-load-balancer-listener-ssl-policy-weak-or-unknown": 0,
"aws-public-alb-waf-missing": 1,
"aws-cloudfront-viewer-http-allowed": 0,
"aws-cloudfront-viewer-tls-policy-weak-or-unknown": 0,
"aws-cloudfront-access-logging-not-configured": 0,
"aws-public-cloudfront-waf-missing": 0,
"aws-api-gateway-cors-permissive": 0,
"aws-public-api-gateway-waf-missing": 0,
"aws-api-gateway-public-route-authorization-none": 0,
"aws-api-gateway-stage-access-logs-missing": 0,
"aws-cloudtrail-multi-region-disabled": 0,
"aws-cloudtrail-log-file-validation-disabled": 0,
"aws-cloudtrail-management-events-disabled": 0,
"aws-cloudtrail-data-events-not-modeled": 0,
"aws-cloudtrail-insight-selectors-missing": 0,
"aws-guardduty-detector-disabled-or-missing": 0,
"aws-securityhub-account-missing": 0,
"aws-config-recorder-disabled-or-missing": 0,
"aws-config-delivery-channel-missing": 0,
"aws-access-analyzer-not-configured": 0,
"aws-macie-not-enabled-for-sensitive-storage": 0,
"aws-rds-storage-encryption-disabled": 0,
"aws-rds-public-endpoint-enabled": 0,
"aws-rds-backup-retention-insufficient": 0,
"aws-rds-deletion-protection-disabled": 0,
"aws-rds-customer-managed-kms-key-missing": 0,
"aws-rds-multi-az-disabled": 0,
"aws-rds-performance-insights-disabled": 0,
"aws-rds-cloudwatch-log-exports-missing": 1,
"aws-rds-iam-auth-disabled": 0,
"aws-s3-public-access": 0,
"aws-s3-customer-managed-encryption-missing": 0,
"aws-s3-versioning-disabled": 0,
"aws-s3-object-lock-retention-missing": 0,
"aws-s3-lifecycle-noncurrent-retention-insufficient": 0,
"aws-ecr-image-tag-mutability-enabled": 0,
"aws-ecr-customer-managed-encryption-missing": 0,
"aws-ecr-repository-scanning-disabled": 0,
"aws-workload-image-not-digest-pinned": 0,
"aws-workload-ecr-mutable-tag": 0,
"aws-workload-can-modify-image-repository": 0,
"aws-ecs-sensitive-environment-value-inline": 0,
"aws-ecs-secret-access-blast-radius": 0,
"aws-public-ecs-secret-access": 0,
"aws-public-ecs-s3-mutation-access": 0,
"aws-public-ecs-messaging-mutation-access": 0,
"aws-sns-customer-managed-encryption-missing": 0,
"aws-sqs-customer-managed-encryption-missing": 0,
"aws-sqs-message-retention-insufficient": 0,
"aws-sqs-dead-letter-queue-not-configured": 0,
"aws-secretsmanager-customer-managed-kms-key-missing": 1,
"aws-secretsmanager-recovery-window-too-short": 0,
"aws-secretsmanager-rotation-not-configured-or-too-long": 1,
"aws-kms-key-rotation-disabled-or-unknown": 0,
"aws-kms-key-deletion-window-too-short": 0,
"aws-workload-secretsmanager-vpc-endpoint-missing": 1,
"aws-workload-kms-vpc-endpoint-missing": 0,
"aws-workload-s3-vpc-endpoint-missing": 0,
"aws-vpc-endpoint-policy-broad-access": 0,
"aws-vpc-flow-logs-not-configured": 1,
"aws-vpc-flow-log-traffic-type-incomplete": 0,
"aws-vpc-flow-log-destination-missing": 0,
"aws-eks-api-endpoint-public-unrestricted": 0,
"aws-eks-private-endpoint-not-enabled": 0,
"aws-eks-secrets-encryption-not-configured": 0,
"aws-eks-control-plane-logging-incomplete": 0,
"aws-eks-authentication-mode-weak-or-unknown": 0,
"aws-eks-vpc-cni-network-policy-not-enabled": 0,
"aws-database-permissive-ingress": 0,
"aws-missing-tier-segmentation": 0,
"aws-sensitive-resource-policy-external-access": 0,
"aws-service-resource-policy-external-access": 0,
"aws-iam-wildcard-permissions": 2,
"aws-iam-privileged-role-assignment": 1,
"aws-workload-role-sensitive-permissions": 1,
"aws-private-data-transitive-exposure": 2,
"aws-control-plane-sensitive-workload-chain": 0,
"aws-role-trust-expansion": 0,
"aws-role-trust-missing-narrowing": 0
}
},
"references": {
"unresolved_reference_count": 0,
"unresolved_references": []
}
},
"inventory": {
"provider": "aws",
"unsupported_resources": [],
"metadata": {
"primary_account_id": "111122223333",
"supported_resource_types": [
"aws_accessanalyzer_analyzer",
"aws_api_gateway_authorizer",
"aws_api_gateway_method",
"aws_api_gateway_rest_api",
"aws_api_gateway_stage",
"aws_apigatewayv2_api",
"aws_apigatewayv2_route",
"aws_apigatewayv2_stage",
"aws_cloudfront_distribution",
"aws_cloudtrail",
"aws_config_configuration_recorder",
"aws_config_configuration_recorder_status",
"aws_config_delivery_channel",
"aws_db_instance",
"aws_ecr_registry_scanning_configuration",
"aws_ecr_repository",
"aws_ecs_cluster",
"aws_ecs_service",
"aws_ecs_task_definition",
"aws_eks_addon",
"aws_eks_cluster",
"aws_flow_log",
"aws_guardduty_detector",
"aws_iam_instance_profile",
"aws_iam_openid_connect_provider",
"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_function_url",
"aws_lambda_permission",
"aws_lb",
"aws_lb_listener",
"aws_lb_listener_rule",
"aws_lb_target_group",
"aws_macie2_account",
"aws_nat_gateway",
"aws_route_table",
"aws_route_table_association",
"aws_s3_bucket",
"aws_s3_bucket_lifecycle_configuration",
"aws_s3_bucket_object_lock_configuration",
"aws_s3_bucket_policy",
"aws_s3_bucket_public_access_block",
"aws_s3_bucket_server_side_encryption_configuration",
"aws_s3_bucket_versioning",
"aws_secretsmanager_secret",
"aws_secretsmanager_secret_policy",
"aws_secretsmanager_secret_rotation",
"aws_security_group",
"aws_security_group_rule",
"aws_securityhub_account",
"aws_sns_topic",
"aws_sqs_queue",
"aws_sqs_queue_redrive_policy",
"aws_subnet",
"aws_vpc",
"aws_vpc_endpoint",
"aws_wafv2_web_acl",
"aws_wafv2_web_acl_association"
],
"total_input_resources": 21,
"provider_resource_count": 21,
"normalized_resource_count": 21,
"unsupported_resource_types": {}
},
"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",
"rds_publicly_accessible_state": "disabled",
"rds_backup_retention_period": 14,
"rds_deletion_protection_state": "enabled",
"rds_multi_az_state": "unknown",
"rds_kms_key_id": "arn:aws:kms:us-east-1:222233334444:key/rds",
"rds_performance_insights_enabled_state": "unknown",
"rds_enabled_cloudwatch_logs_exports": [],
"rds_iam_database_authentication_enabled_state": "unknown",
"rds_posture_uncertainties": [],
"db_subnet_group_name": null,
"publicly_accessible": false,
"public_access_reasons": [],
"public_exposure_reasons": [],
"storage_encrypted": true,
"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"
],
"ecs_secret_access_paths": [],
"ecs_s3_access_paths": [],
"ecs_messaging_access_paths": []
}
},
{
"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",
"container_image_references": [],
"container_image_posture_uncertainties": [
"container_definitions is not represented in planned values"
],
"ecs_secret_references": [],
"ecs_secret_posture_uncertainties": [
"container_definitions is not represented in planned values"
],
"ecs_secret_access_paths": [],
"ecs_s3_access_paths": [],
"ecs_messaging_access_paths": [],
"ecr_write_paths": [],
"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": [],
"principal_entries": [],
"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"
],
"principal_entries": [
{
"kind": "Service",
"value": "ecs-tasks.amazonaws.com"
}
],
"narrowing_condition_keys": [],
"narrowing_conditions": [],
"has_narrowing_conditions": false
}
],
"inline_policy_names": [
"execution-logs"
],
"privileged_access_grants": [],
"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": [],
"principal_entries": [],
"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"
],
"principal_entries": [
{
"kind": "Service",
"value": "ecs-tasks.amazonaws.com"
}
],
"narrowing_condition_keys": [],
"narrowing_conditions": [],
"has_narrowing_conditions": false
}
],
"inline_policy_names": [
"task-data-access"
],
"privileged_access_grants": [
{
"provider": "aws",
"principal_type": "role",
"principal_identifier": "arn:aws:iam::111122223333:role/app-task-role",
"principal_display_name": "aws_iam_role.task",
"principal_source_address": "aws_iam_role.task",
"scope_kind": "account",
"scope_value": "*",
"scope_source_address": null,
"privilege_categories": [
"secrets-admin"
],
"confidence": "high",
"assignment_source_address": "aws_iam_role.task",
"role_name": "app-task-role",
"role_id": "arn:aws:iam::111122223333:role/app-task-role",
"permission_patterns": [],
"evidence": [
"action=secretsmanager:GetSecretValue",
"resource=*"
],
"uncertainties": []
}
],
"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",
"secrets_manager_replication": [],
"secrets_manager_posture_uncertainties": [],
"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:447d2bb6368d1811cc4957b86b10397cb0e0e1b5ebf3063d04b7879edab9aee9",
"title": "IAM role has privileged assignment posture",
"rule_id": "aws-iam-privileged-role-assignment",
"category": "Elevation of Privilege",
"severity": "high",
"affected_resources": [
"aws_iam_role.task"
],
"trust_boundary_id": null,
"rationale": "aws_iam_role.task has deterministic privileged IAM assignment posture: secrets-admin. If this role is attached to a workload or assumable by a control-plane principal, those privileges increase blast radius.",
"recommended_mitigation": "Review high-impact IAM role permissions, split administrative and runtime duties, scope resources to named ARNs, and avoid attaching broad IAM, role-passing, secrets, KMS, data, network, or audit administration permissions to general workload roles.",
"evidence": [
{
"key": "iam_role",
"values": [
"address=aws_iam_role.task",
"type=aws_iam_role",
"arn=arn:aws:iam::111122223333:role/app-task-role",
"identifier=app-task-role"
]
},
{
"key": "privileged_access",
"values": [
"grant_1=categories=[secrets-admin]; scope=account; confidence=high"
]
},
{
"key": "privilege_categories",
"values": [
"secrets-admin"
]
},
{
"key": "grant_scopes",
"values": [
"scope_kind=account; scope_value=*"
]
},
{
"key": "grant_confidence",
"values": [
"high"
]
},
{
"key": "inline_policy_sources",
"values": [
"inline_policy_name=task-data-access"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 2,
"data_sensitivity": 2,
"lateral_movement": 0,
"blast_radius": 3,
"final_score": 7,
"severity": "high",
"computed_severity": null
}
},
{
"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:7764e4c5514d2c0f6130714b1c5bb65fd64fb857cf3124a77d42b7d718d0ac33",
"title": "Public Application Load Balancer is not associated with a WAF Web ACL",
"rule_id": "aws-public-alb-waf-missing",
"category": "Tampering",
"severity": "medium",
"affected_resources": [
"aws_lb.web"
],
"trust_boundary_id": null,
"rationale": "aws_lb.web is an internet-facing Application Load Balancer, but the Terraform plan does not show a deterministic AWS WAFv2 Web ACL association targeting it. Public edge traffic can reach the ALB without a modeled WAF or edge protection policy.",
"recommended_mitigation": "Associate an AWS WAFv2 Web ACL with internet-facing Application Load Balancers and keep the association modeled in Terraform so public edge protection is reviewable before deployment.",
"evidence": [
{
"key": "target_load_balancer",
"values": [
"address=aws_lb.web",
"type=aws_lb",
"arn=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234",
"load_balancer_type=application",
"public_exposure=true",
"load balancer is internet-facing and attached security groups allow internet ingress"
]
},
{
"key": "waf_association_coverage",
"values": [
"target_resource_arn=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234",
"resolved_web_acl_association_count=0",
"modeled_web_acl_association_count=0"
]
}
],
"severity_reasoning": {
"internet_exposure": 2,
"privilege_breadth": 0,
"data_sensitivity": 0,
"lateral_movement": 1,
"blast_radius": 1,
"final_score": 4,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:8e18128dffd9efcf1f4871c9e0113f2ed2c30fa7f50d065a57cf010adb6a0066",
"title": "Secrets Manager rotation is not configured or too infrequent",
"rule_id": "aws-secretsmanager-rotation-not-configured-or-too-long",
"category": "Information Disclosure",
"severity": "medium",
"affected_resources": [
"aws_secretsmanager_secret.app"
],
"trust_boundary_id": null,
"rationale": "aws_secretsmanager_secret.app does not show a deterministic Secrets Manager rotation resource in the Terraform plan. Static or manually rotated secrets can remain valid longer after disclosure, service compromise, or operator error.",
"recommended_mitigation": "Configure `aws_secretsmanager_secret_rotation` with a rotation Lambda and a rotation interval aligned to the organization secret lifecycle policy, such as 90 days or less for sensitive application secrets.",
"evidence": [
{
"key": "target_resource",
"values": [
"address=aws_secretsmanager_secret.app",
"type=aws_secretsmanager_secret",
"identifier=ecs-app-secret",
"arn=arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret"
]
},
{
"key": "rotation_posture",
"values": [
"rotation_state=not_configured",
"maximum_rotation_interval_days=90",
"aws_secretsmanager_secret_rotation resource was not resolved for this secret"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 0,
"data_sensitivity": 2,
"lateral_movement": 0,
"blast_radius": 1,
"final_score": 3,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:f1186d2682b29d92fb968a4c955389806eca87eca95222515fc37d0257656765",
"title": "Secrets Manager secret does not use a customer-managed KMS key",
"rule_id": "aws-secretsmanager-customer-managed-kms-key-missing",
"category": "Information Disclosure",
"severity": "medium",
"affected_resources": [
"aws_secretsmanager_secret.app"
],
"trust_boundary_id": null,
"rationale": "aws_secretsmanager_secret.app does not show a deterministic customer-managed KMS key in the Terraform plan. Secrets Manager AWS-managed encryption may still apply; this finding concerns customer key ownership, rotation, audit separation, and compliance posture.",
"recommended_mitigation": "Configure `kms_key_id` with a customer-managed KMS key for secrets where key ownership, rotation, audit separation, or compliance controls are required.",
"evidence": [
{
"key": "target_resource",
"values": [
"address=aws_secretsmanager_secret.app",
"type=aws_secretsmanager_secret",
"identifier=ecs-app-secret",
"arn=arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret"
]
},
{
"key": "encryption_ownership",
"values": [
"customer_managed_kms_state=not_configured",
"kms_key_id is unset",
"AWS-managed encryption may still apply; this finding concerns customer key control"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 0,
"data_sensitivity": 2,
"lateral_movement": 0,
"blast_radius": 1,
"final_score": 3,
"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:c2dad77f15c57ff9b288847015b64eb1504039f1eeae0aa0312b748ec4410f40",
"title": "VPC Flow Logs are not configured for a modeled VPC",
"rule_id": "aws-vpc-flow-logs-not-configured",
"category": "Repudiation",
"severity": "medium",
"affected_resources": [
"aws_vpc.main"
],
"trust_boundary_id": null,
"rationale": "aws_vpc.main does not have a resolved aws_flow_log targeting the VPC in this Terraform plan. Network traffic metadata for incident response, threat hunting, and segmentation review may be unavailable unless Flow Logs are configured elsewhere.",
"recommended_mitigation": "Enable VPC Flow Logs for production VPCs, route them to a retained CloudWatch Logs, S3, or Firehose destination, and manage Flow Log resources in Terraform so network telemetry posture is reviewable.",
"evidence": [
{
"key": "target_vpc",
"values": [
"address=aws_vpc.main",
"type=aws_vpc",
"identifier=vpc-ecs-001",
"cidr_block=10.60.0.0/16"
]
},
{
"key": "flow_log_coverage",
"values": [
"target_vpc_id=vpc-ecs-001",
"resolved_vpc_flow_log_count=0",
"aws_flow_log resources are not modeled"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 0,
"data_sensitivity": 0,
"lateral_movement": 1,
"blast_radius": 2,
"final_score": 3,
"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
}
},
{
"fingerprint": "sha256:f68606c5ff9ce2f88855a750561bb9e881ae0f934e9f9a36a515251835952ccf",
"title": "Workload uses Secrets Manager without a VPC endpoint",
"rule_id": "aws-workload-secretsmanager-vpc-endpoint-missing",
"category": "Information Disclosure",
"severity": "medium",
"affected_resources": [
"aws_ecs_service.app",
"aws_iam_role.task"
],
"trust_boundary_id": null,
"rationale": "aws_ecs_service.app runs in VPC `vpc-ecs-001` and inherits Secrets Manager secret retrieval from aws_iam_role.task, but the Terraform plan does not show a Secrets Manager interface VPC endpoint for that VPC. Calls to the sensitive service may therefore depend on public AWS service endpoints, NAT, or another egress path.",
"recommended_mitigation": "Add a Secrets Manager interface VPC endpoint with private DNS enabled for VPC workloads that retrieve secrets, and narrow endpoint policies where possible.",
"evidence": [
{
"key": "target_workload",
"values": [
"address=aws_ecs_service.app",
"type=aws_ecs_service",
"vpc_id=vpc-ecs-001",
"subnet_ids=[subnet-ecs-private-app]",
"security_group_ids=[sg-ecs-service]"
]
},
{
"key": "sensitive_service_dependency",
"values": [
"service=secretsmanager",
"role=aws_iam_role.task",
"actions=[secretsmanager:GetSecretValue]",
"resources=[*]"
]
},
{
"key": "vpc_endpoint_coverage",
"values": [
"vpc_id=vpc-ecs-001",
"service=secretsmanager",
"expected_endpoint_type=interface",
"vpc_endpoint_coverage=missing"
]
},
{
"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": 1,
"final_score": 4,
"severity": "medium",
"computed_severity": null
}
},
{
"fingerprint": "sha256:ff9a1b4b0b11630f912c75371010b2df22e43179e7a2112f290cdf09014ab55e",
"title": "RDS database does not export engine CloudWatch logs",
"rule_id": "aws-rds-cloudwatch-log-exports-missing",
"category": "Repudiation",
"severity": "low",
"affected_resources": [
"aws_db_instance.app"
],
"trust_boundary_id": null,
"rationale": "aws_db_instance.app (engine `postgres`) does not export any of the baseline CloudWatch Logs expected for its engine family (postgresql). Without these log exports the database lacks the basic observability posture needed to investigate errors, slow queries, and audit activity from CloudWatch.",
"recommended_mitigation": "Enable the CloudWatch Logs exports expected for the RDS engine family (for example `postgresql` for PostgreSQL, `error` and `slowquery` for MySQL/MariaDB) so errors, slow queries, and audit activity are captured for investigation.",
"evidence": [
{
"key": "target_resource",
"values": [
"address=aws_db_instance.app",
"type=aws_db_instance",
"identifier=ecs-app-db",
"engine=postgres"
]
},
{
"key": "log_export_posture",
"values": [
"enabled_cloudwatch_logs_exports=[]",
"expected_log_exports=['postgresql']",
"engine-family baseline log exports are absent"
]
}
],
"severity_reasoning": {
"internet_exposure": 0,
"privilege_breadth": 0,
"data_sensitivity": 1,
"lateral_movement": 0,
"blast_radius": 1,
"final_score": 2,
"severity": "low",
"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 **12 findings** across **21 normalized resources**.
- High severity findings: `1`
- Medium severity findings: `10`
- Low severity findings: `1`
## Analysis Coverage
- Terraform resources seen: `21`
- Provider resources considered: `21`
- Normalized resources: `21`
- Unsupported resources: `0`
- Registered provider rules (AWS): `83`
- Enabled provider rules (AWS): `83`
- Disabled rules: `0`
- Severity overrides: `0`
- Unresolved in-plan references: `0`
- Findings by rule:
- `aws-public-alb-waf-missing`: `1`
- `aws-rds-cloudwatch-log-exports-missing`: `1`
- `aws-secretsmanager-customer-managed-kms-key-missing`: `1`
- `aws-secretsmanager-rotation-not-configured-or-too-long`: `1`
- `aws-workload-secretsmanager-vpc-endpoint-missing`: `1`
- `aws-vpc-flow-logs-not-configured`: `1`
- `aws-iam-wildcard-permissions`: `2`
- `aws-iam-privileged-role-assignment`: `1`
- `aws-workload-role-sensitive-permissions`: `1`
- `aws-private-data-transitive-exposure`: `2`
## 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
#### IAM role has privileged assignment posture
- STRIDE category: Elevation of Privilege
- Affected resources: `aws_iam_role.task`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +2, data_sensitivity +2, lateral_movement +0, blast_radius +3, final_score 7 => high
- Rationale: aws_iam_role.task has deterministic privileged IAM assignment posture: secrets-admin. If this role is attached to a workload or assumable by a control-plane principal, those privileges increase blast radius.
- Recommended mitigation: Review high-impact IAM role permissions, split administrative and runtime duties, scope resources to named ARNs, and avoid attaching broad IAM, role-passing, secrets, KMS, data, network, or audit administration permissions to general workload roles.
- Evidence:
- iam role: address=aws_iam_role.task; type=aws_iam_role; arn=arn:aws:iam::111122223333:role/app-task-role; identifier=app-task-role
- privileged access: grant_1=categories=[secrets-admin]; scope=account; confidence=high
- privilege categories: secrets-admin
- grant scopes: scope_kind=account; scope_value=*
- grant confidence: high
- inline policy sources: inline_policy_name=task-data-access
### 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=[*]
#### Public Application Load Balancer is not associated with a WAF Web ACL
- STRIDE category: Tampering
- Affected resources: `aws_lb.web`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +2, privilege_breadth +0, data_sensitivity +0, lateral_movement +1, blast_radius +1, final_score 4 => medium
- Rationale: aws_lb.web is an internet-facing Application Load Balancer, but the Terraform plan does not show a deterministic AWS WAFv2 Web ACL association targeting it. Public edge traffic can reach the ALB without a modeled WAF or edge protection policy.
- Recommended mitigation: Associate an AWS WAFv2 Web ACL with internet-facing Application Load Balancers and keep the association modeled in Terraform so public edge protection is reviewable before deployment.
- Evidence:
- target load balancer: address=aws_lb.web; type=aws_lb; arn=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234; load_balancer_type=application; public_exposure=true; load balancer is internet-facing and attached security groups allow internet ingress
- waf association coverage: target_resource_arn=arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/web/1234; resolved_web_acl_association_count=0; modeled_web_acl_association_count=0
#### Secrets Manager rotation is not configured or too infrequent
- STRIDE category: Information Disclosure
- Affected resources: `aws_secretsmanager_secret.app`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +0, data_sensitivity +2, lateral_movement +0, blast_radius +1, final_score 3 => medium
- Rationale: aws_secretsmanager_secret.app does not show a deterministic Secrets Manager rotation resource in the Terraform plan. Static or manually rotated secrets can remain valid longer after disclosure, service compromise, or operator error.
- Recommended mitigation: Configure `aws_secretsmanager_secret_rotation` with a rotation Lambda and a rotation interval aligned to the organization secret lifecycle policy, such as 90 days or less for sensitive application secrets.
- Evidence:
- target resource: address=aws_secretsmanager_secret.app; type=aws_secretsmanager_secret; identifier=ecs-app-secret; arn=arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret
- rotation posture: rotation_state=not_configured; maximum_rotation_interval_days=90; aws_secretsmanager_secret_rotation resource was not resolved for this secret
#### Secrets Manager secret does not use a customer-managed KMS key
- STRIDE category: Information Disclosure
- Affected resources: `aws_secretsmanager_secret.app`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +0, data_sensitivity +2, lateral_movement +0, blast_radius +1, final_score 3 => medium
- Rationale: aws_secretsmanager_secret.app does not show a deterministic customer-managed KMS key in the Terraform plan. Secrets Manager AWS-managed encryption may still apply; this finding concerns customer key ownership, rotation, audit separation, and compliance posture.
- Recommended mitigation: Configure `kms_key_id` with a customer-managed KMS key for secrets where key ownership, rotation, audit separation, or compliance controls are required.
- Evidence:
- target resource: address=aws_secretsmanager_secret.app; type=aws_secretsmanager_secret; identifier=ecs-app-secret; arn=arn:aws:secretsmanager:us-east-1:111122223333:secret:ecs-app-secret
- encryption ownership: customer_managed_kms_state=not_configured; kms_key_id is unset; AWS-managed encryption may still apply; this finding concerns customer key control
#### 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.
#### VPC Flow Logs are not configured for a modeled VPC
- STRIDE category: Repudiation
- Affected resources: `aws_vpc.main`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +0, data_sensitivity +0, lateral_movement +1, blast_radius +2, final_score 3 => medium
- Rationale: aws_vpc.main does not have a resolved aws_flow_log targeting the VPC in this Terraform plan. Network traffic metadata for incident response, threat hunting, and segmentation review may be unavailable unless Flow Logs are configured elsewhere.
- Recommended mitigation: Enable VPC Flow Logs for production VPCs, route them to a retained CloudWatch Logs, S3, or Firehose destination, and manage Flow Log resources in Terraform so network telemetry posture is reviewable.
- Evidence:
- target vpc: address=aws_vpc.main; type=aws_vpc; identifier=vpc-ecs-001; cidr_block=10.60.0.0/16
- flow log coverage: target_vpc_id=vpc-ecs-001; resolved_vpc_flow_log_count=0; aws_flow_log resources are not modeled
#### 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=[*]
#### Workload uses Secrets Manager without a VPC endpoint
- STRIDE category: Information Disclosure
- Affected resources: `aws_ecs_service.app`, `aws_iam_role.task`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +1, data_sensitivity +1, lateral_movement +1, blast_radius +1, final_score 4 => medium
- Rationale: aws_ecs_service.app runs in VPC `vpc-ecs-001` and inherits Secrets Manager secret retrieval from aws_iam_role.task, but the Terraform plan does not show a Secrets Manager interface VPC endpoint for that VPC. Calls to the sensitive service may therefore depend on public AWS service endpoints, NAT, or another egress path.
- Recommended mitigation: Add a Secrets Manager interface VPC endpoint with private DNS enabled for VPC workloads that retrieve secrets, and narrow endpoint policies where possible.
- Evidence:
- target workload: address=aws_ecs_service.app; type=aws_ecs_service; vpc_id=vpc-ecs-001; subnet_ids=[subnet-ecs-private-app]; security_group_ids=[sg-ecs-service]
- sensitive service dependency: service=secretsmanager; role=aws_iam_role.task; actions=[secretsmanager:GetSecretValue]; resources=[*]
- vpc endpoint coverage: vpc_id=vpc-ecs-001; service=secretsmanager; expected_endpoint_type=interface; vpc_endpoint_coverage=missing
- policy statements: Allow actions=[secretsmanager:GetSecretValue] resources=[*]
### Low
#### RDS database does not export engine CloudWatch logs
- STRIDE category: Repudiation
- Affected resources: `aws_db_instance.app`
- Trust boundary: `not-applicable`
- Severity reasoning: internet_exposure +0, privilege_breadth +0, data_sensitivity +1, lateral_movement +0, blast_radius +1, final_score 2 => low
- Rationale: aws_db_instance.app (engine `postgres`) does not export any of the baseline CloudWatch Logs expected for its engine family (postgresql). Without these log exports the database lacks the basic observability posture needed to investigate errors, slow queries, and audit activity from CloudWatch.
- Recommended mitigation: Enable the CloudWatch Logs exports expected for the RDS engine family (for example `postgresql` for PostgreSQL, `error` and `slowquery` for MySQL/MariaDB) so errors, slow queries, and audit activity are captured for investigation.
- Evidence:
- target resource: address=aws_db_instance.app; type=aws_db_instance; identifier=ecs-app-db; engine=postgres
- log export posture: enabled_cloudwatch_logs_exports=[]; expected_log_exports=['postgresql']; engine-family baseline log exports are absent
## 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.