×
Fork me on GitHub

How to dynamically bind Elastic IP addresses to an auto scaling group

What if you want to associate a pool of Elastic IP addresses to an auto scaling group, without using a load balancer? Nor grant permissions to bind the elastic IP in a startup script? Enter the elastic IP manager, which manages the assignment of a pool of Elastic IP addresses to instances!

How does it work?

The elastic IP manager is a Lambda function, which is triggered on EC2 state change events and uses tags to relate a pool of addresses to EC2 instances. When the instance is stopped or terminated, the elastic IP address is removed. When a new instance is started, an elastic IP is assigned to it. The elastic IP manager also syncs the state every 5 minutes, to ensure that we are eventually consistent in the face of errors.

The elastic IP manager only operates on ec2 instances with the tag elastic-ip-manager-pool. When an instance with this tag reaches the state running, it will assign a free elastic IP addresses with the same tag and tag value. When an instance with this tag is stopped or terminated, the association with the elastic IP address is removed.

How do I use it?

You can start using the elastic IP manager, in three simple steps:

  1. deploy the elastic-ip-manager
  2. create a pool of tagged elastic IP addresses
  3. create an auto scaling group of tagged instances

deploy the elastic-ip-manager

To deploy the provider, type:

git clone https://github.com/binxio/ec2-elastic-ip-manager.git
cd ec2-elastic-ip-manager
aws cloudformation create-stack \
        --capabilities CAPABILITY_IAM \
        --stack-name elastic-ip-manager \
        --template-body file://./cloudformation/elastic-ip-manager.yaml

aws cloudformation wait stack-create-complete  --stack-name elastic-ip-manager

Create a pool of Elastic IP addresses

Create a pool of elastic IP addresses, and tag them with an elastic-ip-manager-pool value:

  EIPBastionPoolTags:
    Type: Custom::Tag
    Properties:
      ResourceARN:
        - !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:eip/${EIP1.AllocationId}'
        - !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:eip/${EIP2.AllocationId}'
      Tags:
        elastic-ip-manager-pool: bastion

      ServiceToken: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:cfn-tag-provider'

In this example we are using the custom tag provider, as the AWS::EC2::EIP does not (yet) support tags.

Create an auto scaling group

Create an auto scaling group and apply the tag elastic-ip-manager-pool to all the instances:

  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      ...
      Tags:
        - Key: elastic-ip-manager-pool
          Value: bastion
          PropagateAtLaunch: true

The manager will automatically associate elastic IP addresses to instance tagged with elastic-ip-manager-pool. It will not do anything on instances without the tag elastic-ip-manager-pool.

That is all. If you want to see it all in action, deploy the demo.

Deploy the demo

In order to deploy the demo, type:

read -p "vpc id: " VPC_ID
read -p "subnet ids: " SUBNET_IDS
aws cloudformation create-stack \
        --capabilities CAPABILITY_NAMED_IAM \
        --stack-name elastic-ip-manager-demo \
        --template-body file://./cloudformation/demo-stack.yaml \
        --parameter Name=VPC,Value=$VPC_ID Name=Subnets,Value=$SUBNET_IDS

aws cloudformation wait stack-create-complete  --stack-name elastic-ip-manager-demo

Alternatives

There are two alternative solutions to achieve the same functionality:

In my use case, I did not want to spent money on keeping an NLB running nor give the instance the permission to associate an EIP to itself.

Conclusion

With the elastic IP manager and the CloudFormation tag provider, you can dynamically associate EIP addresses with auto scaling group instances. If you are looking for binding static private IP addresses, you can use the EC2 network interface manager.

Picture of Mark van Holsteijn
Mark van Holsteijn
CTO