Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 941
Traiano Welcome Avatar asked Mar 08 '17 08:03

Traiano Welcome


2 Answers

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:

  • https://www.terraform.io/docs/providers/aws/r/instance.html#network-interfaces

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
  }
}
like image 183
catsby Avatar answered Oct 20 '22 05:10

catsby


I don't know if you actually want to do what you're doing. From your description I would expect a single network interface with a "static" IP.

Now what I would do is use the private_ip parameter of aws_instance, which simply sets the fixed IP for an EC2 host. Done.

What you seem to try is to create the host without a static IP in the aws_instance (you didn't show it, so I just assume), which will IMHO always give the host a dynamic IP. Then you create a second network interface, which you give a static IP, and attach it to the host. This will not be the first (or "primary") interface of the instance, but it has a static IP, and according to your description this is what happens.

I am pretty sure you will always end up with a DHCP IP address when you don't specify your static IP in your host definition.

So either you provide more information about your use case, or more code, but the way you do things is just wrong for what you want if I understand you correctly.

like image 39
flypenguin Avatar answered Oct 20 '22 03:10

flypenguin