Ansible: ansible.cfg – adding roles to your path, tuning OpenSSH

A few config settings to tune Ansible:

`roles_path` let’s you add another directory for roles.

https://docs.ansible.com/ansible/2.4/intro_configuration.html#roles-path

 

ssh_connection lets you tune the OpenSSH connection. E.g. ControlPersist (note – only modern OS’s – i.e. > RHEL6).

https://docs.ansible.com/ansible/2.4/intro_configuration.html#openssh-specific-settings

which can improve Performance settings.

https://dzone.com/articles/speed-up-ansible

but beware some potential pitfalls – use unique ControlPath settings – e.g.

control_path = %(directory)s/%%h-%%r

https://docs.ansible.com/ansible/2.4/intro_configuration.html#control-path

Ansible: running through a bastion host

E.g. in inventory create:

ssh-config.yml

with:

ansible_ssh_common_args: "-o ProxyCommand='ssh -W %h:%p {{ AWS_IAM_ID }}@hostname' -o ControlMaster=auto -o ControlPersist=30m -o StrictHostKeyChecking=no"

Then make sure you’ve got both your private keys (bastion and destination) added via ssh-add.

E.g. ssh-add ~/.ssh/id_rsa

etc…

Debugging

  1. use ansible -vvvv to get ssh output
  2. run this ssh command
  3. I was getting

ec2-user@<ip>: Permission denied (publickey).

4. ssh to bastion and check you can access that host

5. on the bastion check the sshd logs

tail -f /var/log/auth.log

which revealed nothing.

Oct 24 13:22:27 0 systemd-logind[1268]: New session 61400 of user snowcrash.
Oct 24 13:22:28 0 sshd[23318]: Received disconnect from <my ip> port 61226:11: disconnected by user

i.e. the first line shows the successful ssh connection to the jumpbox. The second shows the disconnect.

Note: setting sshd logging to verbose did not help. e.g.

Oct 24 13:36:19 0 systemd-logind[1268]: New session 61405 of user snowcrash.
Oct 24 13:36:19 0 sshd[9788]: User child is on pid 9949
Oct 24 13:36:19 0 sshd[9949]: Received disconnect from <my ip> port 61404:11: disconnected by user

6. checking the destination box

Note this had a different sshd log at:

/var/log/secure

A successful connection (i.e. directly from the bastion host) would show:

Accepted publickey for ec2-user

but via the proxy command I’d get:

Connection closed by <bastion> [preauth]

 

 

 

Ansible: Dynamic Inventory (using the AWS EC2 External Inventory Script)

Where hosts can appear and disappear (e.g. with AWS ASGs) the EC2 external inventory script (ec2.py) comes in useful.

All you need to do is to export your AWS keys as environment variables and ec2.py is good.

ec2.ini options

The EC2 inventory output can become very large. To manage its size, you can configure which groups should be created using ec2.ini options. E.g.

group_by_instance_id = False
group_by_region = False
group_by_availability_zone = False
group_by_ami_id = False
group_by_instance_type = False
group_by_key_pair = False
group_by_vpc_id = False
group_by_security_group = False
group_by_tag_keys = True
group_by_tag_none = True
group_by_route53_names = True
group_by_rds_engine = True
group_by_rds_parameter_group = False

Note on how these are created:

  • format is tag_KEY_VALUE
  • special characters are changed to an underscore

E.g. with a NAME of my instance name we would get a tag of  tag_NAME_my_instance_name.

 

These inikeys are read in ec2.py. E.g.

        # Configure which groups should be created.
        group_by_options = [
            'group_by_instance_id',
            'group_by_region',
            'group_by_availability_zone',
            'group_by_ami_id',
            'group_by_instance_type',
            'group_by_instance_state',
            'group_by_key_pair',
            'group_by_vpc_id',
            'group_by_security_group',
            'group_by_tag_keys',
            'group_by_tag_none',
            'group_by_route53_names',
            'group_by_rds_engine',
            'group_by_rds_parameter_group',
            'group_by_elasticache_engine',
            'group_by_elasticache_cluster',
            'group_by_elasticache_parameter_group',
            'group_by_elasticache_replication_group',
            'group_by_aws_account',
        ]
        for option in group_by_options:
            if config.has_option('ec2', option):
                setattr(self, option, config.getboolean('ec2', option))
            else:
                setattr(self, option, True)

See also:

https://github.com/ansible/ansible/blob/devel/contrib/inventory/ec2.py#L482

and

https://docs.ansible.com/ansible/2.6/user_guide/intro_dynamic_inventory.html#example-aws-ec2-external-inventory-script