Back to Checks
EC2 instance has no more than one Elastic Network Interface (ENI) attached
ec2_instance_uses_single_eni
Service: ec2Severity: low
OfficialBuilt-inVerified
Categories:trust-boundaries
Resource Type:AwsEc2Instance
EC2 instances are evaluated for attached network adapters. It identifies instances with more than one ENI-including efa, interface, or trunk types-and distinguishes those using a single adapter.
Risk
Multiple ENIs create dual-homed hosts across subnets and security groups, enabling unintended routing and policy bypass. Adversaries can pivot between segments, use alternate egress for data exfiltration, or exploit asymmetric paths, undermining segmentation and confidentiality/integrity while complicating containment.
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks ec2_instance_uses_single_eniRecommendation
Prefer a single ENI per instance.
If multi-homing is unavoidable:
- Place ENIs in least-privilege subnets/SGs
- Keep
source/destination checkenabled and routes explicit - Use gateways/LBs for NAT or ingress, not the host
- Monitor flow logs and formally approve exceptions
Embed defense in depth and zero trust.
Remediation
CLI
aws ec2 detach-network-interface --attachment-id <ATTACHMENT_ID>Terraform
# Terraform: instance with only the primary ENI
resource "aws_instance" "<example_resource_name>" {
ami = "<example_resource_id>"
instance_type = "t3.micro"
subnet_id = "<example_resource_id>" # FIX: only primary ENI; no additional network_interface attachments
}NativeIaC
# CloudFormation: ensure the instance has only one ENI
Resources:
<example_resource_name>:
Type: AWS::EC2::Instance
Properties:
ImageId: <example_resource_id>
InstanceType: t3.micro
SubnetId: <example_resource_id> # FIX: creates a single primary ENI; do not add extra NetworkInterfaces/attachmentsOther
1Open the AWS EC2 console and go to Network Interfaces
2Filter by the affected instance ID
3Select each non-primary network interface (Primary cannot be detached)
4Choose Actions > Detach
5Confirm the detach for each secondary ENI
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
class ec2_instance_uses_single_eni(Check):
def execute(self):
findings = []
for instance in ec2_client.instances:
report = Check_Report_AWS(metadata=self.metadata(), resource=instance)
eni_types = {"efa": [], "interface": [], "trunk": []}
if not instance.network_interfaces:
report.status = "PASS"
report.status_extended = (
f"EC2 Instance {instance.id} has no network interfaces attached."
)
else:
for eni_id in instance.network_interfaces:
if (
eni_id in ec2_client.network_interfaces
and ec2_client.network_interfaces[eni_id].type in eni_types
):
eni_types[ec2_client.network_interfaces[eni_id].type].append(
eni_id
)
message_status_extended = ""
if (
len(eni_types["efa"])
+ len(eni_types["interface"])
+ len(eni_types["trunk"])
> 1
):
report.status = "FAIL"
message_status_extended = (
f"EC2 Instance {instance.id} uses multiple ENIs: ("
)
else:
report.status = "PASS"
message_status_extended = (
f"EC2 Instance {instance.id} uses only one ENI: ("
)
if eni_types["efa"]:
message_status_extended += f" EFAs: {eni_types['efa']}"
if eni_types["interface"]:
message_status_extended += f" Interfaces: {eni_types['interface']}"
if eni_types["trunk"]:
message_status_extended += f" Trunks: {eni_types['trunk']}"
report.status_extended = message_status_extended + " )."
findings.append(report)
return findings