Thursday, March 17, 2022

[SOLVED] Terraform: Correctly assigning a static private IP to newly created instance

Issue

Objective:

I'm trying to create a number of EC2 instances and assign them each a static private ip address from a map variable. This address must be the primary address, and basically means I'm not using the DHCP assigned address provided by aws.

Issue:

The terraform plan succeeds, and I can create instances which show the static IP address assigned, together with the DHCP assigned address (in the aws console). When I ssh into the instance I see the primary address is the DHCP assigned address. there is a second ENI attached to the instance (eth1) but the static ip address is not there.

The Question:

How to have terraform create the instance, using the statically assigned IP address for the primary interface (eth0), instead of the default assigned DHCP address? Basically, how can I either:

a) Create this interface with statically assigned interface at instance creation time or, b) Replace the existing primary interface IP address with a static one (or the entire ENI itself with a newly created one with the static IP address)

Here are the details:

I am using the module as follows in a separate main.tf file:

a) create the instance

module "ec2-hadoop-manager" {
  source                      = "../modules/ec2"
  ami_id                      = "${var.dw_manager["ami"]}"
  instance_type               = "${var.dw_manager["instance_type"]}"
  aws_region                  = "${var.region}"
  availability_zone           = "eu-west-1a"
  associate_public_ip_address = true
  role                        = "hadoop-manager"
  env                         = "${var.environment}"
  vpc                         = "${var.vpc_id}"
  security_group_ids          = "${var.aws_security_group_id["sg_id"]}"
  key_name                    = "${var.key_name}"
  subnet_id           = "${var.default_subnet}"
  number_of_instances = "${var.dw_manager["count"]}"
}

b) I'm Assigning private IPs to the instance using a resource (outside the module bloc in main.tf):

resource "aws_network_interface" "private_ip" {
    count = "${var.dw_manager["count"]}"
    subnet_id = "${var.default_subnet}"
    private_ips = ["${lookup(var.dw_manager_ips, count.index)}"]
    security_groups = "${var.aws_security_group_id["sg_id"]}"
    attachment {
        instance = "${element(split(",", module.ec2-hadoop-manager.ec2_instance_ip), count.index)}"
        device_index = 1
    }
}

NOTE: I have tried changing device_index to 0, but as expected, aws complains that there is already an eni attached at index 0:

Error applying plan:

3 error(s) occurred:

* aws_network_interface.private_ip.0: Error attaching ENI: InvalidParameterValue: Instance 'i-09f1371f798c2f6b3' already has an interface attached at device index '0'.
        status code: 400, request id: ed1737d9-5342-491a-85a5-e49e70b7503d
* aws_network_interface.private_ip.2: Error attaching ENI: InvalidParameterValue: Instance 'i-012bda6948bbe00c9' already has an interface attached at device index '0'.
        status code: 400, request id: 794c04fb-9089-4ad0-8f5d-ba572777575a
* aws_network_interface.private_ip.1: Error attaching ENI: InvalidParameterValue: Instance 'i-00ac215801de3aba8' already has an interface attached at device index '0'.

status code: 400, request id: cbd9e36d-145f-45d4-934f-0a9c2f6e7768

Some additional information that may be useful: Link to my full module definition files:

main definition file for the ec2 module:

http://pastebin.com/zXrZRrQ5

main outputs.tf definition file for ec2 module:

http://pastebin.com/9t5zjfQS


Solution

Terraform v0.9.4 shipped with a new feature on aws_instance that let's you assign to device index 0, via a new config option network_interface:

There's also the aws_network_interface_attachment, but I believe you want the new network_interface option for aws_instance above.

Example config:

resource "aws_network_interface" "foo" {
  subnet_id = "${aws_subnet.my_subnet.id}"
  private_ips = ["172.16.10.100"]
  tags {
    Name = "primary_network_interface"
  }
}

resource "aws_instance" "foo" {
    ami = "ami-22b9a343" // us-west-2
    instance_type = "t2.micro"
    network_interface {
     network_interface_id = "${aws_network_interface.foo.id}"
     device_index = 0
  }
}


Answered By - catsby
Answer Checked By - Robin (WPSolving Admin)