How do I set instances launched through EC2 Auto Scaling to have multiple elastic network interfaces with each interface in different subnets?

Last updated: 2022-06-27

When Amazon Elastic Compute Cloud (Amazon EC2) Auto Scaling launches a new instance, I want a second elastic network interface in a different subnet to automatically attach to it. I also want EC2 Auto Scaling to delete the elastic network interface upon instance termination. How can I do this?

Short description

EC2 Auto Scaling supports attaching a second elastic network interface automatically when Auto Scaling spins up a new instance. However, both elastic network interfaces attached to the instance are in the same subnet.

Using this solution, you can place instances launched by EC2 Auto Scaling in two different subnets of your choice. For example, you can have one elastic network interface in a public subnet and the other in a private subnet.

Note: This solution also supports warm pools and scale-in to warm pool.

To avoid exhausting private IP addresses in the subnet, elastic network interfaces attached to the instance are deleted on termination of the instances. This helps prevent reaching the elastic network interface limit in your account.

To do this:

  1. Create an AWS Lambda function that attaches the second elastic network interface to the instance when the instance is in the Pending:wait state. Make sure that the second elastic network interface is in a different subnet from the subnet of the first elastic network interface.
  2. Create a lifecycle hook for instance launch.
  3. Configure an Amazon EventBridge rule or Amazon Simple Notification Service (Amazon SNS) topic to trigger the Lambda function. The rule or SNS topic will be invoked by EC2 Instance-launch Lifecycle Action when Auto Scaling launches a new instance

Note: The following resolution is for an Auto Scaling group enabled in a single or multiple Availability Zones with two subnets in each Availability Zone.

Resolution

Create a Lambda function

Create a Lambda function that does the following:

  • Checks the subnet of the first network interface that's attached to the launched instance.
  • Attaches a second elastic network interface to the instance in the other subnet configured in that Availability Zone on the Auto Scaling group.

To create the Lambda function, do the following:

1.    Open the Lambda console.

2.    Choose Create function.

3.    Choose Author from scratch.

4.    Enter a name for the Lambda function in the Function name field, and then choose Python 3.8 for Runtime.

5.    Expand Permissions by selecting the dropdown arrow to change the default execution role for Lambda function. You can choose to use an existing AWS Identity and Access Management (IAM) role or create a custom role on IAM console. The function role must have the following permissions:

{
    "Statement": [{
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Action": [
                "ec2:CreateNetworkInterface",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DetachNetworkInterface",
                "ec2:DeleteNetworkInterface",
                "ec2:DescribeSubnets",
                "ec2:AttachNetworkInterface",
                "ec2:DescribeInstances",
                "ec2:ModifyNetworkInterfaceAttribute",
                "autoscaling:CompleteLifecycleAction",
                "autoscaling:DescribeAutoScalingGroups"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}

6.    Choose Create function.

7.    Download the Multiple ENI Auto Scaling group Python script. Then copy the code into the Function code field.

8.    Select the Deploy tab to make sure that the changes saved.

Create a lifecycle hook

Create a lifecycle hook to trigger your event from the AWS Management console. For instructions, see Add lifecycle hooks (console). Or, use the following AWS Command Line Interface (AWS CLI) command:

Note: For this use case, set the Heartbeat timeout parameter to 300 secs and the Default result parameter as ABANDON.

aws autoscaling put-lifecycle-hook --lifecycle-hook-name my-lifecycle-launch-hook --auto-scaling-group-name my-asg --lifecycle-transition autoscaling:EC2_INSTANCE_LAUNCHING --heartbeat-timeout 300 --default-result ABANDON

Note: If you receive errors when running AWS CLI commands, make sure that you're using the most recent version of the AWS CLI.

Trigger the Lambda function

You can trigger the Lambda function using Amazon EventBridge or the Amazon Simple Notification Service (Amazon SNS)

Create an EventBridge rule to trigger the Lambda function

1.    Open the EventBridge console.

2.    From the left navigation pane, choose Rules.

Note: For Event bus, select AWS default event bus. When an AWS service in your account emits an event, it always goes to your account’s default event bus.

3.    Choose Create rule.

4.    Enter a Name and Description for the rule.

5.    Under Rule type, select Rule with an event pattern, and then choose Next.

6.    Choose Other under Event Source, add the following into the Event pattern section, and then choose Next.

Note: In the following example, change AutoScalingGroupName to the name of your Auto Scaling group and LifecycleHookName to the name of your lifecycle hook.

{
  "source": ["aws.autoscaling"],
  "detail-type": ["EC2 Instance-launch Lifecycle Action"],
  "detail": {
    "AutoScalingGroupName": ["my-asg"],
    "LifecycleHookName": ["my-lifecycle-launch-hook"]
  }
}

7.    For Target types, choose AWS service.

8.    For Select a target, choose Lambda function from the dropdown menu, and then select the Lambda function that you previously created.

9.    Choose Next.

10.    (Optional) Enter one or more tags for the rule.

11.    Choose Next.

12.    Review the details of the rule and choose Create rule.

Create an Amazon SNS topic to trigger the Lambda function

To use an SNS topic, do the following:

1.    Run the following command to create a lifecycle hook that sends a notification to your SNS topic using the AWS CLI command:

aws autoscaling put-lifecycle-hook --lifecycle-hook-name my-lifecycle-launch-hook --auto-scaling-group-name my-asg --lifecycle-transition autoscaling:EC2_INSTANCE_LAUNCHING --heartbeat-timeout 300 --default-result ABANDON --notification-target-arn <SNStopicARN>

2.    Configure this SNS topic to trigger the Lambda function.

Now, when Auto Scaling launches a new instance, a second elastic network interface is created in a different subnet and attached to the instance.

Note: Launch templates that aren't using the Amazon Linux AMI might need additional options configured on the OS-level to create the additional interface.