Persisting IPs With AWS ENIs in RHEL 7.4

Persisting IPs With AWS ENIs in RHEL 7.4

I spent some time on this in the week and there was some wrestle involved in setting up an Elastic Network Interface to be used with an autohealing EC2 instance, I thought it would be worth sharing the pattern if someone has to design a service in a similar fashion. If designed correctly, a new instance will reassociate to the address in the event of an instance termination and the consuming entities can keep querying the newly instantiated service on the instance.

Context

This is in the context of ENIs attached to instances hosting RHEL 7.4. Part of the reason I came across this was upgrading from RHEL 7.2 to 7.4 and discovering the known issue of HWADDR being added to the device config (plus another lesser issue where the configuration attributes no longer required quotation marks). Also this is was in a scenario where I worked with private instances without DNS. If you wish for a persistent public IP an Elastic IP can be used in a public subnet with the usual VPC configuration. The instance service will only be available from within its own subnet or from another available routed subnet.

Solution

Provision an ENI specifying the subnet it should belong in and the desired IP address. The IP address must sit in the CIDR range of the specified subnet and not be one of the reserved addresses 1. Also when creating the ENI the source destination check must be set to false; this is easy enough to do, especially when creating through Cloudformation, as ENI resources have the SourceDestCheck attribute.

To configure the autoscaled instance to use the new ENI the userdata script of the launch configuration associated with the autoscaling group can call the AWS CLI command aws ec2 attach-network-interface 2. This makes the ENI available as a device to the instance and can be seen with ip link show eth1 (if this is the only other ENI than the default). The MAC address can be pulled from here to be used in the device configuration with

hwaddr=$(ip link show eth1 | grep ether | xargs | cut -d " " -f2)

Configuration

Note: From here all commands are performed with elevated privileges, this is fine if done in the launch configuration userdata as this is run as root, otherwise elevate the user to root and execute the commands.

To configure the device the /etc/sysconfig/network-scripts/ folder provides the device configurations as specified in this Redhat page. The device configuration can be created by simply copying the ifcfg-eth0 config to ifcfg-eth1 and replacing the pertinent attributes.

cp /etc/sysconfig/network-scripts/ifcfg-eth0 \
   /etc/sysconfig/network-scripts/ifcfg-eth1

Here I add the MAC address of the new device, update the device name to eth1 and activate the device on system boot

sed -i "s/HWADDR=.*/HWADDR=${hwaddr}/g" /etc/sysconfig/network-scripts/ifcfg-eth1
sed -i "s/eth0/eth1/" /etc/sysconfig/network-scripts/ifcfg-eth1
sed -i "s/ONBOOT=no/ONBOOT=yes/" /etc/sysconfig/network-scripts/ifcfg-eth1

Also we need to return to the original eth0 device and switch it off at boot.

sed -i "s/ONBOOT=yes/ONBOOT=no/" /etc/sysconfig/network-scripts/ifcfg-eth0

After this the network manager needs to be restarted. Once this is done the instance can be SSH’ed into from the new ENI IP address and can be set to serve queries.

systemctl restart network

That’s it, I’m hoping to up the frequency of these which means they will generally be shorter which essentially meets my original aims; to provide articles on infrastructure building blocks that are as atomic as possible to lend to being more universal and portable for designs. Thanks folks.

See also:


  1. I was confused when I first read about the 10.0.0.2 of each subnet being reserved, I read this as the DNS server being reachable from the .2 address of the subnet, it is not, it is reachable from the .2 of the first subnet of the CIDR range of the VPC, see AWS reference on DNS. [return]
  2. Be sure the instance has internet connectivity to make the API calls to the EC2 endpoints for the network interface attachment and any other required outbound commands. This would usually be done via a NAT instance, or very soon the API calls could be set up to use AWS PrivateLink. [return]
comments powered by Disqus