This module reads elastic network interfaces (ENIs) within an Amazon VPC and returns their private IP addresses using Python's AWS Rest API.
Point out the VPC (id) and tell this module the owner id for the elastic network interfaces you specifically want and it will output their private IP addresses using a python script executed by Terraform's external data feature.
Read AWS documentation on Network Interfaces.
Check that your machine or docker image has python installed ( see integration test ) and ensure your AWS credentials are setup. Provide the VPC ID and the owner ID in the variables below.
Finally put the below HCL code into a file and run terraform init
followed by terraform apply -auto-approve
.
data aws_caller_identity this {}
module eni-addresses
{
source = "github.com/devops4me/terraform-network-interface-addresses"
in_vpc_id = "<enter-vpc-id-here>"
in_owner_id = "${ data.aws_caller_identity.this.account_id }"
}
output out_addresses
{
value = "${ module.eni-ip-addresses.out_eni_addresses }"
}
The list of IP addresses will be returned in the out_addresses
variable.
Owner ID | AWS Cloud Service | Return Description |
---|---|---|
<12 digit account id> | EC2 Instances | IP addresses of EC2 instances by account owner. |
amazon-rds | Relational Db Service | IP addresses of the database cluster nodes. |
amazon-elasticsearch | Elasticsearch Service | IP addresses of the elasticsearch cluster nodes. |
The owner id is the 12 digit account id when you are interested in the EC2 instances you (and/or your agents) have created.
If using a cloud service like a RDS database cluster or AWS ElasticSearch the owner id will translate as amazon-rds
and amazon-elasticsearch
respectively.
This snippet from eni-addresses.py demonstrates the loop which reads every subnet in a VPC followed by every network interface inside the subnet.
for this_subnet in boto3.resource('ec2').Vpc( sys.argv[1] ).subnets.all():
for eni in this_subnet.network_interfaces.all():
if ( (eni.status == ENI_STATUS ) and ( eni.requester_id == sys.argv[2] ) ):
ip_addresses_list.append( eni.private_ip_address )
The script will push debugging information into a log file called eni-addresses.log.
This snippet from the eni-addresses.log
illustrates the XML traffic generated by calls to the AWS Rest API.
<?xml version="1.0" encoding="UTF-8"?>
<DescribeNetworkInterfacesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>21f2e3d3-fc6a-4429-9e1b-6e045981a362</requestId>
<networkInterfaceSet>
<item>
<networkInterfaceId>eni-0f609f1ae695e96bc</networkInterfaceId>
<subnetId>subnet-0cd5a7e8a251fba04</subnetId>
<vpcId>vpc-0958415a8f36ccd2c</vpcId>
<availabilityZone>eu-west-2b</availabilityZone>
<description/>
<ownerId>987654321098</ownerId>
<requesterManaged>false</requesterManaged>
<status>in-use</status>
<macAddress>0a:2c:7c:66:35:aa</macAddress>
<privateIpAddress>10.197.16.162</privateIpAddress>
<privateDnsName>ip-10-197-16-162.eu-west-2.compute.internal</privateDnsName>
</item>
</networkInterfaceSet>
</DescribeNetworkInterfacesResponse>
When troubleshooting it pays to be able to run this script manually. Let's pretend our VPC ID
is vpc-54bab24bc1cb8789c and the AWS elasticsearch service is responsible for creating the nodes - hence an owner ID of amazon-elasticsearch
.
u@devops4me$ export AWS_ACCESS_KEY_ID=<access-key-characters>
u@devops4me$ export AWS_SECRET_ACCESS_KEY=<secret-key-characters>
u@devops4me$ export AWS_REGION=<eg eu-west-1>
u@devops4me$ export AWS_DEFAULT_REGION=<eg eu-west-1>
u@devops4me$ chmod u+x eni-addresses.py
u@devops4me$ ./eni-addresses.py "vpc-54bab24bc1cb8789c" "amazon-elasticsearch"
Terraform expects JSON to be returned with a key labelled ip_addresses
like this assuming 4 nodes.
{
"ip_addresses": "10.99.20.240,10.99.20.247,10.99.11.11,10.99.3.167"
}
Python's botocore will insist that you set the AWS_DEFAULT_REGION environment variable by throwing a NoRegionError
.
botocore.exceptions.NoRegionError: You must specify a region.