Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Private IP of instance launched by autoscaling group #511

Open
hashibot opened this issue Jun 13, 2017 · 53 comments
Open

Get Private IP of instance launched by autoscaling group #511

hashibot opened this issue Jun 13, 2017 · 53 comments
Labels
enhancement Requests to existing resources that expand the functionality or scope. service/autoscaling Issues and PRs that pertain to the autoscaling service.

Comments

@hashibot
Copy link

This issue was originally opened by @coolgooze as hashicorp/terraform#11713. It was migrated here as part of the provider split. The original body of the issue is below.


ASG
resource "aws_autoscaling_group" "REDIS_ASG" {
name = "${var.environment}-REDIS_ASG"
launch_configuration = "${aws_launch_configuration.redis_launch_conf.name}"
#availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
vpc_zone_identifier = ["${data.aws_subnet.PrivateDBSubnetAZ1.id}","${data.aws_subnet.PrivateDBSubnetAZ2.id}","${data.aws_subnet.PrivateDBSubnetAZ3.id}"]
min_size = 1
max_size = 1
desired_capacity = 1
health_check_grace_period = 600
health_check_type = "EC2"
force_delete = "false"
termination_policies = ["OldestInstance"]
tag {
key = "Name"
value = "${var.environment}-int-redis"
propagate_at_launch = true
}
}

i am trying to create a A Record
resource "aws_route53_record" "redis" {
zone_id = "${data.aws_route53_zone.dns.zone_id}"
name = "redis-${var.environment}.${data.aws_route53_zone.dns.name}"
type = "A"
ttl = "60"
records = ["${aws_autoscaling_group.REDIS_ASG.private_ip}"]
}

Output-

  • Resource 'aws_autoscaling_group.REDIS_ASG' does not have attribute 'private_ip' for variable 'aws_autoscaling_group.REDIS_ASG.private_ip'
@hashibot hashibot added the enhancement Requests to existing resources that expand the functionality or scope. label Jun 13, 2017
@jasonkuehl
Copy link

I just had a need for this today. I would love for this to be a real thing.

@brandonawells
Copy link

I ran into a need for this today. I'd love this to exist. Any updates on the request?

@catsby
Copy link
Member

catsby commented Aug 25, 2017

Hello – Can you describe the use case here? I'm curious why you would want the direct IP of any instance that's in an autoscaling group, as opposed to connecting via a Load Balancer.

If I'm not mistaken a specific advantage of an ASG is ensuring you have a certain number of instances available and running, not that any given one of them exists at a certain IP.

If the ASG resource were to export a private IP, and on AWS side the ASG were to change instances for any reason, that IP could become stale until your next plan and apply, right? In which case there could be a window of time when your A record routes you to a bad IP, correct? Where as if the A record pointed to an IP that's assigned to a load balance, the roll over would happen automatically.

I'm curious how exposing this would be used in a reliable, stable way. Thanks!

@catsby catsby added the waiting-response Maintainers are waiting on response from community or contributor. label Aug 25, 2017
@jasonkuehl
Copy link

jasonkuehl commented Aug 29, 2017

@catsby You are correct in saying that IP would be stale and Terraform would need to run in order to update the A record attached to the Route53 record.

We have use case that we have a set of servers that run different jobs. Everything is controlled in puppet and Terraform. Right now we have a module that builds off a count (normally). What we wanted to do was put them into an ASG in order to have self healing in case a node would fail. However we cant move forward with testing due to there is no output of private ips or a node list.

We started an effect sometime ago to remove IP Address from configs and swap to DNS names. It would be icing on the cake if we can build a way to self heal these servers in case of aws instance failure using ASG.

@jainishshah17
Copy link

+1

@bdirito
Copy link

bdirito commented Sep 11, 2017

Another use case
https://github.com/terraform-community-modules/tf_aws_bastion_s3_keys

This sets up a bastion in an autoscaling group min=max=desired=1. The reasoning behind this is to autorelaunch the bastion if it goes down. W/o this however I have to do a check after to see what ip the bastion actually got.

@bernadinm
Copy link

It would be very useful to have this feature. Users can run types of one off workloads with a list of known IPs for the ASG within a null_resource. +1 for me as well.

@igoratencompass
Copy link

@catsby Look at my comment in the closed issue migrated here: hashicorp/terraform#11713

To repeat:

Very useful, will provide same functionality as CloudFormation does. We can simply wait for ASG to finish creating all instances and report back with private ip's, instance id's etc. so we can have further actions follow in terraform like creating dns records for the instances etc.

Also no one says that ASG has to be related to an ELB, in our case we have the instances behind HAProxy so we need to know their IP's.

This has been opened since February, is it really that difficult to resolve?

@igoratencompass
Copy link

@catsby Another example, I want to create Route53 DNS records and health checks after launching instances:

# Host-specific A records for both load-balancers
resource "aws_route53_record" "service-record" {
   zone_id = "<my-zone-id>"
   count = 2
   name = "service-lb-${format("%03d", count.index + 1)}.mydomain.com"
   type = "A"
   ttl = "60"
   records = ["${element(aws_instance.lb-service.*.public_ip, count.index)}"]
}

# Health checks for each of the load balancers
resource "aws_route53_health_check" "service-healthcheck" {
  ip_address = "${element(aws_instance.lb-service.*.public_ip, count.index)}"
  count = 2
  port = 50000
  type = "HTTP"
  resource_path = "/health"
  failure_threshold = "5"
  request_interval = "30"
  tags = {
    Name = "service-${format("%03d", count.index + 1)}.production"
  }
}

# Group consisting of 2 alias records to the host records, with associated health checks, having weighted routing
resource "aws_route53_record" "service-group" {
   zone_id = "<my-zone-id>"
   count = 2
   name = "service.mydomain.com"
   type = "A"
   weighted_routing_policy = {
      weight = "50"
   }
   health_check_id = "${element(aws_route53_health_check.service-healthcheck.*.id, count.index)}"
   set_identifier = "service${format("%03d", count.index + 1)}"
   alias {
     name = "${element(aws_route53_record.service-record.*.fqdn, count.index)}"
     zone_id = "<my-zone-id>"
     evaluate_target_health = true
   }
}

When instances are launched via ASG there is no way to do this. We are forced to move this code into user-data instead which is big PITA.

@paddycarver paddycarver removed the waiting-response Maintainers are waiting on response from community or contributor. label Nov 21, 2017
@hernan82arg
Copy link

+1

@igoratencompass
Copy link

Any update on this?

@catsby
Copy link
Member

catsby commented Dec 12, 2017

I'm not opposed to this feature in general but I do have opinions on how it should be implemented. I'll also be upfront and say that we (HashiCorp) are unlikely to get to this feature soon, but gladly welcome contributions if someone can pick it up.

As for how to implement:

  • The DescribeAutoScalingGroups endpoint returns a list of ASGs (we query by the specific name, so we get just the one, if it exists)
  • The AutoScalingGroup has a attribute that lists it's Instances
  • That list contains Instance information for each instance, but it is incomplete information. Instance IP Addresses (public or private) are not included here

So the problem here in short is that the IP Addresses are not returned by default and you need to do a handful of additional API calls to get them. For large setups, these extra API calls add up quickly, so by default, we should not include Instance IP Addresses in the state of AutoScaling Groups. I recognize it's a useful feature but also think it will not be an often used one, so by default we shouldn't consume all these API calls.

That said, I believe/propose we can support this functionality with a data source:

  • data.aws_autoscaling_group.group (singular) not to be confused with data.aws_autoscaling_groups (plural)
  • this data source should provide more information about the specific ASG (as opposed to data.aws_autoscaling_groups which just returns names)
  • should provide and optional, though default false, attribute like get_instance_properties to instruct the data source to look up instance attributes:

Alternatively we could expand the data.aws_autoscaling_groups data source, but I think I'd prefer the separation.

To get the IP address(es) for the Instance(s) we need to call DescribeInstances for each one. Fortunately we can use an EC2Filter and filter by requester-id, in this case, the AutoScaling Group Id, so we don't have to group up the instance-ids from the DescribeASG output and then feed that into the DescribeInstances call.

I believe this new data source would keep this instance information in a TypeSet of Instances. Unfortunately you can't directly reference the value in a set with things like element(set, count). So if you want a list of ip addresses, we may want to take the results of the DescribeInstances call and aggregate all the public ips into a calculated field public_ips , and private ips into private_ips.

So in the end the out put of this data source would be like this:

  • asg info
  • set of instances
  • list of public ips
  • list of private ips

How does this sound?

resource "autoscaling_group" "example" {
  [...]
}

data "autoscaling_group" "example_ips" {
  autoscaling_id = "${aws_autoscaling_group.example.id}"
  # Fetch Instance information
  # Retrieves instance information
  # Retrieves public_ip's
  # Retrieves private_ip's
  get_instance_properties = true
}

resource "aws_route53_record" "service-record" {
   zone_id = "<my-zone-id>"
   count = 2
   name = "service-lb-${format("%03d", count.index + 1)}.mydomain.com"
   type = "A"
   ttl = "60"
   records = ["${element(data.aws_autoscaling_group.example_ips.private_ips, count.index)}"]
}

@jasonkuehl
Copy link

@catsby I love this and it would help a lot.

@igoratencompass
Copy link

@catsby beautiful!

@samsixtyone
Copy link

any update on this, in real need of this solution.

@im2kl
Copy link

im2kl commented Jan 17, 2018

Has this been looked at? a complete stopper on what im required to do.

@alona-shevliakova
Copy link

alona-shevliakova commented Jan 19, 2018

any update on this?

@radeksimko radeksimko added the service/autoscaling Issues and PRs that pertain to the autoscaling service. label Jan 25, 2018
@peterloron
Copy link

This would be amazing to have!

@n3ph
Copy link
Contributor

n3ph commented Feb 13, 2018

This would be glorious! Since Lambda triggered by CloudWatchEvent is a mess!

@lebedevdsl
Copy link

Need this one too

@SushantJagdale
Copy link

Anyone find workaround or solution for this issue? This is completely show stopper for what I need to do.

@JeremieBethmont
Copy link

+1

3 similar comments
@xvillanu
Copy link

+1

@uriinf
Copy link

uriinf commented May 19, 2018

+1

@drnorton83
Copy link

+1

@cleanshavenalex
Copy link

+1

3 similar comments
@Alifener
Copy link

+1

@tomaszwostal
Copy link

+1

@sadok-f
Copy link

sadok-f commented Jun 19, 2018

+1

@tlipatov
Copy link

tlipatov commented Jun 20, 2018

Here are some solutions that I implement:

  1. Use the module terraform-aws-modules/autoscaling/aws to launch my ASG's
    Tag the ASG and then use the aws_instance data source to search for the instances based on the tags. Then do what ever I need to do with the data

  2. When using an ASG for a bastion host. I create an iam_instance_profile for the ASG that allows the instance itself to update its own route53 record when it boots up using a launch config script.

Hope this helps

@JoaoManoel
Copy link

+1

1 similar comment
@ricardo-larosa
Copy link

+1

@lexsys27
Copy link

Is there currently any workaround available?

@lexsys27
Copy link

This way allowed me to get ips of worker nodes:

data "aws_instances" "workers" {
  instance_tags {
    Name = "lexsys-eks-asg"
  }
}

output "private-ips" {
  value = "${data.aws_instances.workers.private_ips}"
}

output "public-ips" {
  value = "${data.aws_instances.workers.public_ips}"
}
Outputs:

private-ips = [
    10.0.0.75,
    10.0.1.87
]
public-ips = [
    52.44.215.211,
    54.153.70.110
]

Sure, this workaround has the limitations, but worked for me.

@ghost
Copy link

ghost commented Jul 3, 2018

@catsby One use case is for cluster setup. In such a scenario we want to be able to only provide the SSH keys of the instances to people who want to test a cluster like kafka, zookeeper, elasticsearch etc without having to give them access to the AWS console. If terraform could simply output the private ip address then the troubleshooters would have a list of IP addresses to log into simply with their SSH keys and without requiring access to AWS Console.

@nunofernandes
Copy link

+1

@moosahmed
Copy link

@catsby Yeah another use case is when making a kubernetes cluster through an asg. you need the master's private ip to feed into the workers. Is there someone who knows a work around for this?

@matt9949
Copy link

+1

1 similar comment
@npockrus-bnet
Copy link

+1

@jeandreh
Copy link

+1. My use case involves Hashicorp Vault, which needs to be initialised before being recognised as a healthy node by the load balancer.

@kamusin
Copy link

kamusin commented Sep 27, 2018

+1

@KIVagant
Copy link

Any workarounds for Google Cloud Platform? It has the same problem with google_compute_instance_group_manager.

@igoratencompass
Copy link

@lexsys27 the question is specific for when instances are created via aws_autoscaling_group

@KIVagant I'm afraid you'll need to wait patiently as the rest of us have (since Feb 2017) for this to be included in terraform, my prognoses would be around version 2.27 ... probably :-)

@lexsys27
Copy link

@igoratencompass I do use aws_autoscaling_group to create instances.

I tag the instances in the template and use this tag to retrieve IPs in the data section.

@igoratencompass
Copy link

I see was not aware of that feature of data module.

@RuBiCK
Copy link

RuBiCK commented Dec 12, 2018

#511 (comment) is a workaround but be carefull doc page

Note: It's strongly discouraged to use this data source for querying ephemeral instances (e.g. managed via autoscaling group), as the output may change at any time and you'd need to re-run apply every time an instance comes up or dies.

This note is other reason to implement this new data source

@syncroswitch
Copy link

syncroswitch commented Dec 17, 2018

you can pull all instance data with a round about lookup.

( example assuming some asg named aws_autoscaling_group.one is already defined )

data "aws_instances" "nodes" {
  depends_on = [ "aws_autoscaling_group.one" ]
  
  instance_tags {
    Name = "some_unique_tag_in_your_asg"
  }
}

data "aws_instance" "asg-one-instances" {
  count = "${ var.asg_one_count }"
  depends_on = ["data.aws_instances.nodes"]
  instance_id = "${data.aws_instances.nodes.ids[count.index]}"
}

output "private-ips" {
  value = "${ data.aws_instance.asg-one-instances.*.private_ip }"
}

output "public-ips" {
  value = "${ data.aws_instance.asg-one-instances.*.public_ip }"
}

output "private-dnsnames" {
  value = "${ data.aws_instance.asg-one-instances.*.private_dns }"
}

output "public-dnsnames" {
  value = "${ data.aws_instance.asg-one-instances.*.public_dns }"
}

but I would much prefer to have the instance data directly available in the asg attributes.

@igoratencompass
Copy link

@syncroswitch the problem I see with this is the asg_one_count variable. It is a static value which will/may not match the actual state of the ASG on consecutive runs, i.e. teh ASG has grown or shrunk in the mean time.

@claywd
Copy link

claywd commented Jun 3, 2019

@syncroswitch @igoratencompass it works to get the endpoints and private ips when you launch, which is what is mostly needed.

Also, just set count = "${ var.asg_one_count }" to count = ${aws_autoscaling_group.one.desired_capacity}

If people truly have need of dynamic ips then they should write it up in python, bash, go, etc and call it from terraform then use that instead of the desired capacity but I doubt it will really be necessary or desired in the long run.

@minhajuddin
Copy link

I started off with @syncroswitch's config and ended with a simpler workaround:

data "aws_instances" "ecs_instances_meta" {
  instance_tags = {
    # Use whatever name you have given to your instances
    Name = var.ecs_cluster_name
  }
}

output "ecs-private-ips" {
  value = data.aws_instances.ecs_instances_meta.private_ips
}

@Xtigyro
Copy link

Xtigyro commented Mar 29, 2022

5 yrs later - and still unresolved?

@jasonkuehl
Copy link

A big no.

@BarbaraStanley
Copy link

Deep sigh, needed this.
data "aws_instances" "test" {
instance_tags = {
Role = "HardWorker"
}

filter {
name = "instance.group-id"
values = ["sg-12345678"]
}

instance_state_names = ["running", "stopped"]
}
Is there a way to use the filter to narrow things down, I gave the instances a prefix from the launch template

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Requests to existing resources that expand the functionality or scope. service/autoscaling Issues and PRs that pertain to the autoscaling service.
Projects
None yet
Development

No branches or pull requests