6

No matter what I try, for some reason, when I run an ansible ad-hoc module using the ansible dynamic inventory script (ec2.py+ec2.ini) will only return public IPs for tag queries and attempt to connect over SSH to the public IP of the target(s). For instance, if I run:

ansible -m ping tag_env_dev

Then, it tries to connect over the public IP, despite the private IP being preferable (for security, complexity and cost reasons). I've tried to tweak the following options in my ec2.ini file:

regions = us-east-1 # to restrict to us-east-1 region
destination_variable = public_dns_name # I've also tried private_dns_name and private_ip_address, all of which still attempt to connect to the public IP of the destination instance(s)
vpc_destination_variable = ip_address # also tried private_ip_address 

If I run ./ec2.py --list --refresh-cache | grep -B 5 -A 5 "tag_env_dev", I get a result with only the public IP returned:

"tag_env_dev": [
  "{{public ip here}}"
], 

After each subsequent attempt, I've run ./ec2.py --list --refresh-cache to purge and regenerate the cache. Then I'll re-run ansible -m ping tag_env_dev (or similar) and I'll get a connection timeout on SSH to the public IP address of the instance.

I've confirmed that I can SSH into the "public hostname" (which resolves within a VPC to the private IP) and to the private IP directly, but not the public IP directly (as expected). So it's not a key auth issue.

I've also got an IAM role to which this server is assigned, with plenty of permissions to perform these operations (e.g. it does have readonly for ec2 and vpc).

Additional info:

I’m running ansible from an ec2 instance in the same VPC as the test target. And the security group on the target is configured to allow SSH from its internal CIDR block range. The ansible host also has an IAM role which is sufficient to discover the private IP of the target

Any help would be greatly appreciated.

4
  • 1
    Where are you connecting from? Unless you have a VPN, Bastion Host or Direct Connect to your VPC you cannot connect to private IPs from outside AWS. Nov 10, 2017 at 22:59
  • John - thanks for taking a look. I’m running ansible from an ec2 instance in the same VPC as the test target. And the security group on the target is configured to allow SSH from its internal CIDR block range. The ansible host also has an IAM role which is sufficient to discover the private IP of the target. Thanks!
    – cupcakes
    Nov 10, 2017 at 23:10
  • I don't know the answer. I would edit your question so that your new information is included to help others. Nov 10, 2017 at 23:16
  • I also had this problem, and I believe it's some other level of cache. Even after running --refresh-cache it was still returning the public IP, but after spending a while on Server Fault and not changing anything, it worked. Oct 5, 2018 at 5:00

2 Answers 2

4

Here is a working sample of ec2.ini (tested with ansible 2.1 & 2.3.1)

[ec2]
regions = us-east-1,us-west-2
regions_exclude =
destination_variable = private_ip_address
hostname_variable = peerio
vpc_destination_variable = private_ip_address
route53 = False
rds = False
elasticache = False
all_instances = False
#instance_states = pending, running, shutting-down, terminated, stopping, stopped
all_rds_instances = False
all_elasticache_replication_groups = False
all_elasticache_clusters = False
all_elasticache_nodes = False
cache_path = ~/.ansible/tmp
cache_max_age = 300
nested_groups = False
replace_dash_in_groups = True
expand_csv_tags = False
group_by_instance_id = True
group_by_region = True
group_by_availability_zone = True
group_by_ami_id = True
group_by_instance_type = True
group_by_key_pair = True
group_by_vpc_id = True
group_by_security_group = True
group_by_tag_keys = True
group_by_tag_none = True
group_by_route53_names = True
#pattern_include = staging-*
#pattern_exclude = staging-*
#instance_filters = instance-type=t1.micro,tag:env=staging
#only process items we tagged
instance_filters = tag:serviceclass=*
boto_profile = ansible

Then, instances should be listed using their private IP as identifier:

./ec2.py  --list 
{
  "_meta": {
    "hostvars": {
      "10.255.100.138": {
        "ansible_ssh_host": "10.255.100.138", 
        "ec2__in_monitoring_element": false, 
        "ec2_ami_launch_index": "0", 
...       "ec2_vpc_id": "vpc-57ed3733"
      }, 
      "10.255.100.142": {
        "ansible_ssh_host": "10.255.100.142", 
        "ec2__in_monitoring_element": false, 
...
1
  • SYN -- thank you! I believe the combination of comparing against a "known good" state that you shared (thanks!) and not trying to override a handful of ansible default paths was the last thing I needed to get it working. It's working perfectly now. Thank you again for the help!
    – cupcakes
    Nov 11, 2017 at 1:32
3

Within ec2.ini, edit this line:

vpc_destination_variable = ip_address

To this:

vpc_destination_variable = private_ip_address

From ec2.ini:

# For server inside a VPC, using DNS names may not make sense. When an instance
# has 'subnet_id' set, this variable is used. If the subnet is public, setting
# this to 'ip_address' will return the public IP address. For instances in a
# private subnet, this should be set to 'private_ip_address', and Ansible must
# be run from within EC2. The key of an EC2 tag may optionally be used; however
# the boto instance variables hold precedence in the event of a collision.
# WARNING: - instances that are in the private vpc, _without_ public ip address
# will not be listed in the inventory until You set:
# vpc_destination_variable = private_ip_address
vpc_destination_variable = ip_address

https://github.com/ansible/ansible/blob/devel/contrib/inventory/ec2.ini

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .