This page is generated from skills/ecs-recon/references/networking.md. Edit the source, not this page.
Module: Networking
Part of: ecs-recon Purpose: Discover networking configuration, load balancing, and service-to-service connectivity for ECS services
Table of Contents
Prerequisites
- Service name(s) required: Yes (one or more services to inspect)
- AWS APIs used:
ecs:DescribeServices— service network configuration, load balancers, service registries, Service Connect configecs:DescribeTaskDefinition— network mode from task definitionelbv2:DescribeTargetGroups— target group details including load balancer ARNselbv2:DescribeLoadBalancers— load balancer type (ALB vs NLB)
- CLI commands:
aws ecs describe-services,aws ecs describe-task-definition,aws elbv2 describe-target-groups,aws elbv2 describe-load-balancers - IAM permissions: Read-only (
ecs:DescribeServices,ecs:DescribeTaskDefinition,elasticloadbalancing:DescribeTargetGroups,elasticloadbalancing:DescribeLoadBalancers)
Detection Strategy
Run detections in this order to build the networking picture from task definition up to external connectivity:
1. Network Mode -> Get from task definition (awsvpc | bridge | host | none)
2. awsvpc Configuration -> Get subnets, security groups, public IP from service (awsvpc only)
3. Load Balancers -> Enumerate associated LBs, follow target group ARN to determine type
4. Service Connectivity -> Detect Service Connect, Service Discovery, App Mesh
Why this order matters:
- Network mode determines whether awsvpc config exists — bridge/host/none have no awsvpc configuration
- awsvpc config contains subnet and security group assignments critical for connectivity
- Load balancer discovery requires following target group ARNs through to the load balancer itself to determine type (ALB vs NLB)
- Service-to-service connectivity mechanisms (Service Connect, Service Discovery, App Mesh) are independent of load balancers and represent internal mesh configuration
Key decision logic:
- If
networkModein task definition isawsvpc→ extractnetworkConfiguration.awsvpcConfigurationfrom service - If
networkModeisbridge,host, ornone→ no awsvpc config exists, skip step 2 - If
loadBalancersarray on service is non-empty → follow each target group ARN to determine LB type - If
serviceConnectConfigurationon the PRIMARY deployment is present and enabled → Service Connect is active - If
serviceRegistriesarray is non-empty → Service Discovery is active - If task definition has a proxy configuration with App Mesh → App Mesh is active
Detection Commands
1. Network Mode from Task Definition
Retrieve the network mode declared in the active task definition. This determines whether awsvpc networking applies to this service.
CLI (get task definition ARN from service, then describe it):
aws ecs describe-services \
--cluster <cluster-name> \
--services <service-name> \
--query 'services[0].taskDefinition'
aws ecs describe-task-definition \
--task-definition <task-definition-arn> \
--query 'taskDefinition.networkMode'
Example output:
"awsvpc"
Interpret the result:
Facts verified 2026-07-14 against https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html
"awsvpc"— tasks get their own ENI, subnets, and security groups; step 2 applies"bridge"— tasks share the host's network via Docker bridge; no awsvpc config"host"— tasks share the host's network namespace directly; no awsvpc config"none"— tasks have no external connectivity; no awsvpc config- If not specified, defaults to
"bridge"on Linux EC2 launch type (Fargate requiresawsvpc). Windows EC2 tasks default to<default>(NAT), andbridgeis not valid on Windows.
2. awsvpc Configuration from Service
When the network mode is awsvpc, the service's networkConfiguration contains subnet, security group, and public IP assignment details.
CLI:
aws ecs describe-services \
--cluster <cluster-name> \
--services <service-name> \
--query 'services[0].networkConfiguration.awsvpcConfiguration'
Example output:
{
"subnets": [
"subnet-0a1b2c3d4e5f00001",
"subnet-0a1b2c3d4e5f00002"
],
"securityGroups": [
"sg-0a1b2c3d4e5f00001",
"sg-0a1b2c3d4e5f00002"
],
"assignPublicIp": "DISABLED"
}
Interpret the result:
subnets— VPC subnets where task ENIs are placedsecurityGroups— security groups attached to the task ENIassignPublicIp—ENABLEDorDISABLED; controls whether tasks get a public IP (relevant for Fargate in public subnets)- If
subnetsis an empty list → report as"none_configured" - If
securityGroupsis an empty list → report as"none_configured"
3. Load Balancer Enumeration
Services can be fronted by one or more load balancers. The service describes its load balancer associations by target group ARN, container name, and port. To determine the load balancer type (ALB vs NLB), follow the target group ARN through to the load balancer.
Step 3a: Get load balancer associations from service
CLI:
aws ecs describe-services \
--cluster <cluster-name> \
--services <service-name> \
--query 'services[0].loadBalancers'
Example output:
[
{
"targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-tg/1234567890abcdef",
"containerName": "web",
"containerPort": 8080
}
]
Note on ECS-native blue/green services: When the service uses ECS-native blue/green deployment (deploymentConfiguration.strategy: BLUE_GREEN), the loadBalancers entry may also include advancedConfiguration with productionListenerRule, testListenerRule, alternateTargetGroupArn, and roleArn. If DescribeTargetGroups returns empty LoadBalancerArns for such a service, extract the load balancer ARN from the listener-rule ARN (arn:...:listener-rule/<lb-arn-segment>/...) or fall back to type: "unknown". See Target group with empty LoadBalancerArns.
Step 3b: Describe target group to get load balancer ARNs
CLI:
aws elbv2 describe-target-groups \
--target-group-arns <target-group-arn> \
--query 'TargetGroups[0].LoadBalancerArns'
Example output:
[
"arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890abcdef"
]
Step 3c: Describe load balancer to determine type
CLI:
aws elbv2 describe-load-balancers \
--load-balancer-arns <load-balancer-arn> \
--query 'LoadBalancers[0].Type'
Example output:
"application"
Interpret the result:
"application"→ report type as"ALB""network"→ report type as"NLB"- The load balancer ARN format also hints at the type (
/app/for ALB,/net/for NLB) but always confirm with the describe call
4. Service Connectivity Mechanisms
Detect whether the service uses Service Connect, Service Discovery, or App Mesh for service-to-service communication.
Step 4a: Detect Service Connect
Service Connect is configured per deployment — the configuration lives on the Deployment object, not the top-level Service. To read the active configuration, extract it from the PRIMARY deployment.
CLI:
aws ecs describe-services \
--cluster <cluster-name> \
--services <service-name> \
--query "services[0].deployments[?status=='PRIMARY'] | [0].serviceConnectConfiguration"
Example output (enabled):
{
"enabled": true,
"namespace": "production",
"services": [
{
"portName": "http",
"clientAliases": [
{
"port": 80,
"dnsName": "web-api"
}
]
}
]
}
Example output (not configured):
null
Interpret the result:
- If
serviceConnectConfigurationfrom the PRIMARY deployment is present andenabledistrue→ Service Connect is active - If
nullorenabledisfalse→ Service Connect is not configured
Step 4b: Detect Service Discovery
Service Discovery is indicated by the serviceRegistries array on the service.
CLI:
aws ecs describe-services \
--cluster <cluster-name> \
--services <service-name> \
--query 'services[0].serviceRegistries'
Example output (configured):
[
{
"registryArn": "arn:aws:servicediscovery:us-east-1:123456789012:service/srv-abc123def456",
"containerName": "web",
"containerPort": 8080
}
]
Example output (not configured):
[]
Interpret the result:
- If
serviceRegistriesis a non-empty array → Service Discovery is active - If empty array or
null→ Service Discovery is not configured
Step 4c: Detect App Mesh
App Mesh integration is detected via a proxy configuration in the task definition. The Envoy sidecar is injected as a proxy.
Facts verified 2026-07-14 against https://docs.aws.amazon.com/app-mesh/latest/userguide/what-is-app-mesh.html
Lifecycle note: AWS App Mesh reaches end of support on September 30, 2026 (new-customer onboarding closed September 24, 2024; existing customers remain functional until the end-of-support date). The detection mechanics below stay valid, but when app_mesh: true is detected, the report should surface the end-of-support date so the customer knows a migration is required.
CLI:
aws ecs describe-task-definition \
--task-definition <task-definition-arn> \
--query 'taskDefinition.proxyConfiguration'
Example output (App Mesh configured):
{
"type": "APPMESH",
"containerName": "envoy",
"properties": [
{
"name": "AppPorts",
"value": "8080"
},
{
"name": "ProxyEgressPort",
"value": "15001"
},
{
"name": "ProxyIngressPort",
"value": "15000"
},
{
"name": "IgnoredUID",
"value": "1337"
},
{
"name": "EgressIgnoredIPs",
"value": "169.254.170.2,169.254.169.254"
}
]
}
Example output (no App Mesh):
null
Interpret the result:
- If
proxyConfigurationis present andtypeis"APPMESH"→ App Mesh is active - If
nullor absent → App Mesh is not configured
Output Schema
networking:
services:
- service_name: string
network_mode: string # awsvpc | bridge | host | none
awsvpc_config: # Present only when network_mode is awsvpc
subnets: list[string] | "none_configured"
security_groups: list[string] | "none_configured"
assign_public_ip: string # ENABLED | DISABLED
load_balancers:
- type: string # "ALB" | "NLB" | "unknown"
target_group_arn: string
container_name: string
container_port: int
service_connectivity:
service_connect: bool
service_discovery: bool
app_mesh: bool
error: string | null # Set when a networking API call failed for this service; other fields may be absent
Field details:
network_mode— always present; one ofawsvpc,bridge,host,noneawsvpc_config— present only whennetwork_modeisawsvpc; omitted for bridge/host/nonesubnets/security_groups— report actual IDs as a list; report"none_configured"if the list is emptyassign_public_ip—"ENABLED"or"DISABLED"load_balancers— empty list[]when no load balancer is associatedtype—"ALB"(Application Load Balancer),"NLB"(Network Load Balancer), or"unknown"(LB type could not be resolved — see Target group with empty LoadBalancerArns)service_connectivity— all three flags always reported astrueorfalse; whenapp_meshistrue, surface the App Mesh end-of-support date (2026-09-30) in the reporterror—nullon success; when a networking API call fails for this service, records the failing API call and error code
Edge Cases
Handle these scenarios to ensure accurate networking reporting.
Bridge mode (no awsvpc_config)
Services using bridge, host, or none network modes do not have networkConfiguration.awsvpcConfiguration in the service description.
How to handle:
- Report
network_modeas the actual value (bridge,host, ornone) - Omit the
awsvpc_configfield entirely from the output (do not report it as null or empty) - Load balancers and service connectivity are still reported normally — they operate independently of the network mode
Detection:
aws ecs describe-task-definition \
--task-definition <task-definition-arn> \
--query 'taskDefinition.networkMode'
If the result is not "awsvpc", skip the awsvpc configuration step entirely.
No load balancers associated
A service may have no load balancer associations. This is common for background workers, batch processors, or services that receive traffic only via Service Connect or Service Discovery.
How to handle:
- Report
load_balancers: [](empty list) - Do not report this as an error — it is a valid configuration
- Check service connectivity mechanisms, which may provide internal routing without a load balancer
Detection:
aws ecs describe-services \
--cluster <cluster-name> \
--services <service-name> \
--query 'services[0].loadBalancers'
If the result is [] or null, report an empty load balancer list.
No connectivity mechanism configured
A service may have no load balancer, no Service Connect, no Service Discovery, and no App Mesh. This means the service has no external routing or internal mesh.
How to handle:
- Report
load_balancers: [] - Report
service_connectivity: { service_connect: false, service_discovery: false, app_mesh: false } - This is valid for internal services that are accessed directly by IP or via other custom mechanisms
Empty subnets or security groups reported as "none_configured"
When awsvpc mode is used but the subnets or security groups list is empty, report explicitly.
How to handle:
- If
awsvpcConfiguration.subnetsis[]→ reportsubnets: "none_configured" - If
awsvpcConfiguration.securityGroupsis[]→ reportsecurity_groups: "none_configured" - This is an unusual configuration that may indicate a misconfiguration — report it factually without judgment
Example output for empty security groups:
networking:
services:
- service_name: worker-svc
network_mode: awsvpc
awsvpc_config:
subnets:
- subnet-0a1b2c3d4e5f00001
security_groups: "none_configured"
assign_public_ip: DISABLED
load_balancers: []
service_connectivity:
service_connect: false
service_discovery: false
app_mesh: false
Multiple load balancers on a single service
A service can route to multiple target groups (and therefore multiple load balancers). Each load balancer association targets a specific container and port combination.
How to handle:
- Follow each target group ARN independently through describe-target-groups and describe-load-balancers
- Report each load balancer association as a separate entry in the
load_balancerslist - Different entries may point to different LB types (one ALB, one NLB)
Example output:
load_balancers:
- type: "ALB"
target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/web-tg/abc123"
container_name: web
container_port: 8080
- type: "NLB"
target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/grpc-tg/def456"
container_name: grpc
container_port: 9090
Networking configuration retrieval failure
If any networking API call fails (access denied, throttling, resource not found):
How to handle:
- Record the error on the affected service's entry (set
errorto the failing API call and error code) and continue with the remaining services — do NOT terminate the remaining reconnaissance - Keep any fields already retrieved for the affected service; omit the ones the failed call would have populated
- Use module-level
unavailable: trueONLY when the module cannot produce any data at all (every service failed, or a prerequisite call failed before any per-service data was gathered)
Example — one service failed, others succeeded:
networking:
services:
- service_name: web-api
network_mode: awsvpc
error: "elbv2:DescribeTargetGroups failed for service 'web-api': AccessDeniedException"
- service_name: worker-svc
network_mode: awsvpc
awsvpc_config:
subnets:
- subnet-0a1b2c3d4e5f00001
security_groups:
- sg-0a1b2c3d4e5f00001
assign_public_ip: DISABLED
load_balancers: []
service_connectivity:
service_connect: false
service_discovery: false
app_mesh: false
error: null
Example — total failure only:
networking:
unavailable: true
reason: "ecs:DescribeServices failed for all requested services: AccessDeniedException"
Target group with empty LoadBalancerArns
DescribeTargetGroups returns an empty LoadBalancerArns list in two common scenarios:
- ECS-native blue/green deployments — the target groups attach to the load balancer via listener rules managed by the ECS deployment controller (returned in
loadBalancers[].advancedConfiguration), not via direct association. - Orphaned target groups — the target group was detached from its load balancer or never attached.
In both cases the DescribeTargetGroups → DescribeLoadBalancers path cannot determine the LB type.
How to handle:
- If
LoadBalancerArnsis empty, check whether the service usesadvancedConfiguration(present on ECS-native blue/green services). IfadvancedConfiguration.productionListenerRuleexists, derive the load balancer ARN from the listener-rule ARN and resolve the type withDescribeLoadBalancers. - ARN derivation: a listener-rule ARN has the form
arn:aws:elasticloadbalancing:<region>:<account>:listener-rule/<lb-type>/<lb-name>/<lb-id>/<listener-id>/<rule-id>. Replace thelistener-ruleresource token withloadbalancerand keep only the first three path segments:arn:aws:elasticloadbalancing:<region>:<account>:loadbalancer/<lb-type>/<lb-name>/<lb-id>. - If
DescribeLoadBalancerson the derived ARN returnsLoadBalancerNotFound, the reference is stale (the load balancer was deleted after the service's last deployment) — settypeto"unknown"and note the stale reference in the service'serrorfield. - If
advancedConfigurationis absent or the derivation is impractical, settypeto"unknown". - Always report the entry with the target group ARN, container name, and port regardless.
Example — resolved via advancedConfiguration:
load_balancers:
- type: "ALB"
target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/blue-tg/1234567890abcdef"
container_name: web
container_port: 8080
Example — unresolvable:
load_balancers:
- type: "unknown"
target_group_arn: "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/orphan-tg/xyz789"
container_name: web
container_port: 8080
Sources
- Task definition network parameters (network mode defaults per OS and launch type): https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html
- Service Connect (configuration lives on the deployment): https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect.html
- Service discovery (
serviceRegistries): https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-discovery.html - AWS App Mesh overview and end-of-support announcement (2026-09-30): https://docs.aws.amazon.com/app-mesh/latest/userguide/what-is-app-mesh.html