Static public IPs for EC2 instances

2 minute read Published:

A solution for convenient and automatic static public IPs for CentOS EC2 instances using EIPs and ENIs.

Problem

Stopping and starting your EC2 instances will lose the first public IP that was assigned on its creation. If you had a DNS entry pointing to this IP, it needs to be updated.

Solution

Use an Elastic IP, which is a fixed public IP you can attach to an EC2 instance.

Problem

The Elastic IP has no tag support. You’ll have hundreds of EIPs attached to hundreds of EC2 instances. Messy?

Solution

The Elastic Network Interface has tag support, and is a little beefier than an EIP. More functionality: consistent, additional private IPs as well.

You can add an EIP to an ENI, and then tag the ENI so that the “duo” is defined by the ENI’s tags and you don’t have any floating EIPs.

Problem

How will you attach ENIs to EC2 instances conveniently?

Solution

Using my tag-based EBS & ENI attach tool, goat.

How do you use goat? It’s dead simple. Add these tags to your EC2 instance and ENI:

* GOAT-IN:Prefix = "my-magical-ec2-cluster"
* GOAT-IN:NodeID = "0"

Then, install and enable goat during the instance boot phase (ec2-userdata, for example):

$ yum install -y https://github.com/sevagh/goat/releases/download/0.4.0/goat-0.4.0-1.fc25.x86_64.rpm
$ systemctl enable goat@eni
$ systemctl start goat@eni

Problem

It’s attached - now what?

Solution

ec2-net-utils is a package available on the Amazon Linux AMI. Fortunately, somebody ported it to systemd and it largely works.

I forked it, did some cleanup, and made a release. The full working solution of having your ENI configured automatically after being attached is:

$ yum install -y https://github.com/sevagh/goat/releases/download/ec2-utils-v0.5.3/ec2-net-utils-0.5-2.fc25.noarch.rpm
$ systemctl enable elastic-network-interfaces
$ systemctl start elastic-network-interfaces

Conclusion

What does this look like in production? In my Terraform repository, it’s something like this:

├── enis 
│   ├── eip.tf
│   └── eni.tf
├── ec2
│   ├── ec2.tf
│   └── bootstrap.tpl 

bootstrap.tpl represents the ec2-userdata script, and should contain something like this:

yum install -y https://github.com/sevagh/goat/releases/download/0.4.0/goat-0.4.0-1.fc25.x86_64.rpm
yum install -y https://github.com/sevagh/goat/releases/download/ec2-utils-v0.5.3/ec2-net-utils-0.5-2.fc25.noarch.rpm
systemctl enable elastic-network-interfaces
systemctl start elastic-network-interfaces
systemctl enable goat@eni
systemctl start goat@eni

Full example here.