Cloud May 12, 2021 0

How To Attach Multiple ENIs To EC2 Instances Without Lambda

Creating a Launch Template in AWS of a single EC2 instance with multiple elastic network interfaces (ENIs) is quite straightforward. How about the Autoscaling Group and Multiple Availability Zones.

What if a launch template must be used by the Auto Scaling Group, spinning up EC2 instances in multiple Availability Zones and attaching multiple ENIs in defined subnets? Here is how to do it with user data script a bit of shell scripting, and without Lambda functions.

Auto Scaling Group – Bastion Hosts-Multiple Elastic Network Interfaces

Example scenario:

Deploy Bastion Host cluster consisting of 2 EC2 instances in multiple AZs (1a and 1b) and attach 2 additional elastic network interfaces (ENI) to each EC2 instance in desired subnets. Assuming all required ENIs have been created. The primary network interface (eth0) is created automatically, we are attaching eth1, eth2, ethn.

ENIsAZENI ID
ENI_1_BH_1a (eth1)eu-west-1aeni-01fd164d37e9399b6
ENI_2_BH_1a (eth2)eu-west-1aeni-0e65371003fb3eec7
ENI_1_BH_1b (eth1)eu-west-1beni-01e64d711a9ff7f88
ENI_2_BH_1b (eth2)eu-west-1beni-09329d7d425e30303

IAM role – EC2 instance must be granted minimum privileges to be able to attach network interfaces.

Add to IAM role the following policy with these minimum privileges:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeNetworkInterfaces",
                "ec2:AttachNetworkInterface"
            ],
            "Resource": "*"
        }
    ]
}

First, we have to make our EC2 instances aware of a couple of things during the boot time:

  • Availability Zone in which EC2 instance has been spun up
  • EC2 Instance ID
  • AWS Region

Next we create a bash function, which will be used in IF statements…

User data shell script

Below user data shell script can be used in launch template.

Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0

--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
cloud_final_modules:
- [scripts-user, always]

--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"

#!/bin/bash

## =========  ENI Variables ===========================================

ENI_1_BH_1a="eni-01fd164d37e9399b6"
ENI_2_BH_1a="eni-0e65371003fb3eec7"

ENI_1_BH_1b="eni-01e64d711a9ff7f88"
ENI_2_BH_1b="eni-09329d7d425e30303"

# Ensure latest version of awscli 
/bin/curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
/bin/unzip -o awscliv2.zip > /dev/null 2>&1
./aws/install --update

# Required variables
AWS_REGION=$(/bin/curl -s http://169.254.169.254/latest/meta-data/placement/region)
INSTANCE_ID=$(/bin/curl -s http://169.254.169.254/latest/meta-data/instance-id)
AZ=$(/bin/curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)

## =========  ENIs Attachment =====================================

# Main function
attach_eni () {
    /usr/local/bin/aws ec2 attach-network-interface \
        --device-index $1 \
        --network-interface-id $2 \
        --instance-id $INSTANCE_ID \
        --region $AWS_REGION
}

## AZ1
if [[ $AZ = "eu-west-1a" ]]; then
    attach_eni 1 $ENI_1_BH_1a
    attach_eni 2 $ENI_2_BH_1a
fi

## AZ2
if [[ $AZ = "eu-west-1b" ]]; then
    attach_eni 1 $ENI_1_BH_1b
    attach_eni 2 $ENI_2_BH_1b
fi

This way we can easily control the assignment of ENIs within desired subnets to EC2 instances created by the autoscaling group.

I hope this simple tutorial is helpful. If have any further questions, share with me in the comments section below.