Skip to content

EC2 instances should not use multiple ENIs

Multiple ENIs on a single instance can cause asymmetric routing, misconfigured security groups, and unintended network paths between subnets or VPCs. Each ENI carries its own security group assignments, meaning a secondary ENI could inadvertently expose the instance to traffic the primary ENI's security groups were designed to block.

There are legitimate reasons to use multiple ENIs (management plane separation, container networking, appliance workloads), but most general-purpose instances should not have them. When instances silently accumulate extra ENIs through automation drift or ad-hoc troubleshooting, the attack surface grows without visibility. Flagging multi-ENI instances forces an explicit review of whether each additional interface is justified.

Retrofit consideration

Removing an ENI from a running instance can disrupt active connections and dependent services. Before remediating, check whether the instance is a NAT appliance, part of a dual-homed architecture, or hosting workloads that rely on multiple ENIs for routing isolation. Deleting an aws_network_interface_attachment in Terraform will attempt detachment at apply time, which may require stopping the instance depending on the interface type.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "ec2_instance" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/ec2-instance/aws"
  version = ">=6.0.0"

  ami_ssm_parameter = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
  instance_type     = "t4g.nano"
  subnet_id         = "subnet-abc123"
}

If you use terraform-aws-modules/ec2-instance/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "ec2_instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = ">=6.0.0"

  ami_ssm_parameter = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
  instance_type     = "t4g.nano"
  subnet_id         = "subnet-abc123"
}

Use AWS provider resources directly. See docs for the resources involved: aws_instance.

resource "aws_instance" "this" {
  ami                    = "ami-abc12345"
  instance_type          = "t4g.nano"
  subnet_id              = element(["subnet-abc123", "subnet-def456"], 0)
  vpc_security_group_ids = ["sg-abc12345"]
}

What this control checks

The control checks whether an aws_instance has more than one network interface attached. In Terraform, additional ENIs attach via separate aws_network_interface and aws_network_interface_attachment resources, or via multiple network_interface blocks inside the aws_instance resource.

A configuration passes when each aws_instance has either no explicit network_interface blocks (using the default ENI from subnet_id) or exactly one. It fails when aws_network_interface_attachment resources target the same instance, adding a second interface. If the primary ENI is defined explicitly via aws_network_interface, attach it as the sole interface with device_index = 0. An aws_network_interface_attachment pointing at an instance that already has its primary ENI creates a second attachment and fails the control. Exceptions are configurable via an allow-list parameter for instances with documented multi-ENI requirements.

Common pitfalls

  • ECS awsvpc networking creates hidden ENIs

    ECS tasks using awsvpc network mode create task ENIs in your VPC, but they attach to the task, not to the underlying EC2 container instance. This control won't fire on those. Manually attached secondary ENIs on the EC2 host are a different matter and will still trigger failure. If specific instances legitimately need multiple interfaces, add them to the allow-list with documented justification.

  • Lambda VPC ENIs attached to instances by mistake

    Orphaned aws_network_interface resources from past debugging sessions are a common source of unexpected failures. Lambda Hyperplane ENIs in a VPC won't trigger this control since they aren't attached to EC2 instances, but those leftover manual interfaces will, especially if someone wired them up via aws_network_interface_attachment and never cleaned up. Audit your attachment resources and remove any that weren't intentionally created.

  • Inline network_interface blocks vs. subnet_id are mutually exclusive

    Specifying subnet_id on aws_instance alongside a network_interface block produces an error at plan time. Migrating to an explicitly managed ENI means removing subnet_id, vpc_security_group_ids, and associate_public_ip_address from the instance block and setting them on the aws_network_interface resource instead.

  • Out-of-band ENI attachments during runtime

    Out-of-band ENI attachments, whether from manual console work or automation running outside Terraform, won't appear in Terraform state but will cause control failures when evaluated against the actual instance. Monitor AttachNetworkInterface events in CloudTrail to catch these before your next compliance evaluation.

Audit evidence

An auditor expects Config rule evaluation results showing compliant status for all in-scope EC2 instances, or a CSPM report listing each instance with its ENI count. The aws ec2 describe-instances output filtered to show the NetworkInterfaces array length per instance is direct evidence. Any instance with more than one entry in that array needs a documented exception with an approved architectural justification.

For ongoing assurance, Config conformance pack results or Security Hub findings exported over the audit period demonstrate continuous compliance rather than point-in-time status.

Framework-specific interpretation

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: ec2_instance_not_use_multiple_enis

  • AWS Config Managed Rule: EC2_INSTANCE_MULTIPLE_ENI_CHECK

  • Powerpipe Control: aws_compliance.control.ec2_instance_not_use_multiple_enis

  • Prowler Check: ec2_instance_uses_single_eni

  • AWS Security Hub Control: EC2.17

Last reviewed: 2026-03-09