feat(ansible): use aws dynamic inventories properly with ssm and host variables

This commit is contained in:
Michele Cereda
2025-08-09 00:12:02 +02:00
parent a4423457db
commit a439a4e9ef
7 changed files with 105 additions and 29 deletions

View File

@@ -14,7 +14,8 @@ forks=10
gathering=smart
host_key_checking=False
nocows=True
remote_tmp=/tmp
remote_tmp=/tmp/ansible
async_dir = ~/.ansible/async # default: ~/.ansible_async/
use_persistent_connections=True
verbosity=3

View File

@@ -1,26 +0,0 @@
---
################################################################################
## aws_ec2.yml
##
## Dynamic inventory for integration with AWS SSM.
## Makes use of the 'aws_ec2' plugin.
## The file must be named 'aws_ec2.yml'.
################################################################################
plugin: aws_ec2
regions:
- eu-east-2
keyed_groups:
- key: tags.Name
# add hosts to 'tag_Name_<tag_value>' groups for each aws_ec2 host's 'Tags.Name' attribute
prefix: tag_Name_
separator: ""
- key: tags.application
# add hosts to 'tag_application_<tag_value>' groups for each aws_ec2 host's 'Tags.application' attribute
prefix: tag_application_
separator: ""
hostnames:
- instance-id
# acts as keyword to use the instances' 'InstanceId' attribute
# use 'private-ip-address' to use the instances' 'PrivateIpAddress' attribute instead

View File

@@ -179,7 +179,7 @@ diff 'path/to/plain/file' <(ansible-vault view --vault-password-file 'password_f
ansible-playbook 'playbook.yaml' -DCvvv \
-e 'ansible_aws_ssm_plugin=/usr/local/sessionmanagerplugin/bin/session-manager-plugin ansible_connection=aws_ssm' \
-e 'ansible_aws_ssm_bucket_name=ssm-bucket ansible_aws_ssm_region=eu-west-1' \
-e 'ansible_remote_tmp=/tmp/.ansible-\${USER}/tmp' \
-e 'ansible_remote_tmp=/tmp/.ansible/tmp' \
-i 'i-0123456789abcdef0,'
```
@@ -208,7 +208,8 @@ keywords, and variables.
The `ansible-config` utility allows to see all the configuration settings available, their defaults, how to set them and
where their current value comes from.
Ansible will process the following list and use the first file found; all the other files are ignored even if existing:
Ansible will process the following list and use the **first** file it founds, ignoring all the others even if they do
exist:
1. the `ANSIBLE_CONFIG` environment variable;
1. the `ansible.cfg` file in the current directory;
@@ -224,6 +225,31 @@ ansible-config init --disabled > 'ansible.cfg'
ansible-config init --disabled -t all > 'ansible.cfg'
```
One _can_ specify string values containing environment variables in the configuration file, e.g.:
```ini
[defaults]
remote_tmp = /tmp/ansible-${USER}/tmp
```
> [!warning]
> As of 2025-08-06, environment variables set in a configuration file are **not** expanded.<br/>
> Refer [async_dir not properly expanding variables].
Those values are passed to Ansible during execution **as-is**.<br/>
Since they are sometimes given as part of CLI commands, they might™ work as expected. Most of the times, in my
experience, they **did not**.
There are _some_ shell-expanded characters that do seem to mostly work, though, like `~`:
```ini
[defaults]
async_dir = ~/.ansible/async
```
> [!tip]
> Prefer just using static values in the configuration file.
### Performance tuning
Refer the following:
@@ -1707,6 +1733,7 @@ Another _better (?)_ solution in playbooks/roles would be to sanitize the input
[ansible navigator documentation]: https://ansible.readthedocs.io/projects/navigator/
[ansible runner]: https://ansible.readthedocs.io/projects/runner/en/stable/
[ansible v2.14 changelog]: https://github.com/ansible/ansible/blob/7bb078bd740fba8ad43cc69e18fc8aeb4719180a/changelogs/CHANGELOG-v2.14.rst#id11
[async_dir not properly expanding variables]: https://github.com/ansible/ansible/issues/85370
[asynchronous actions and polling]: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_async.html
[automating helm using ansible]: https://www.ansible.com/blog/automating-helm-using-ansible
[Blocks]: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_blocks.html

View File

@@ -12,6 +12,11 @@ ansible-inventory -i 'aws_ec2.yml' --list
ansible-playbook -i 'self-hosting.yml' 'gitlab.yml' --list-hosts
ansible -i 'webservers.yml' all --list-hosts
# List hosts with their variables
ansible-inventory -i 'aws_ec2.yml' --list
ansible-inventory -i 'inventory.ini' --graph --vars
ansible-inventory -i 'inventory.yml' --host 'client2'
# Show hosts' ansible facts
ansible -i 'inventory.yml' -m 'setup' all
ansible -i '192.168.1.34,gitlab.lan,' -m 'setup' 'gitlab.lan' -u 'admin'

View File

@@ -0,0 +1,55 @@
###
# Provide AWS EC2 instances by their Instance ID
# ------------------
# Dynamic inventory for integration with AWS SSM.
# Makes use of the 'aws_ec2' plugin.
# The file must be named 'aws_ec2.yml', or its name must end with it.
# Even if YAML file, it must *not* start with '---' or ansible will fail parsing it.
# Refer <https://docs.ansible.com/ansible/latest/collections/amazon/aws/aws_ec2_inventory.html> and
# <https://docs.ansible.com/ansible/latest/plugins/inventory.html#using-inventory-plugins>.
###
plugin: amazon.aws.aws_ec2
region: eu-north-1
include_filters:
- # exclude instances that are not running, which are inoperable
instance-state-name: running
exclude_filters:
- # skip EKS nodes, since they are managed in their own way
tag-key:
- aws:eks:cluster-name
- # skip GitLab Runners, since they are volatile and managed in their own way
tag:Application:
- GitLab
tag:Component:
- Runner
use_ssm_inventory: true # requires 'ssm:GetInventory' permissions on 'arn:aws:ssm:<region>:<account-id>:*'
hostnames:
- instance-id
keyed_groups:
- key: architecture
prefix: arch
- key: ssm_inventory.platform_name
prefix: os_Name
- key: ssm_inventory.platform_type
prefix: os_Type
- key: ssm_inventory.platform_version
prefix: os_Version
# - key: tags # would create a group per each tag value; prefer limiting groups to the useful ones
# prefix: tag
- key: tags.Team
prefix: tag_Team
- key: tags.Environment
prefix: tag_Environment
- key: tags.Application
prefix: tag_Application
- key: tags.Component
prefix: tag_Component
- key: tags.Name
prefix: tag_Name
compose:
# use non-jinja values (e.g. strings) by wrapping them in two sets of quotes
# if using awx, prefer keeping double quotes external (e.g. "'something'") as it just looks better in the ui
ansible_connection: "'aws_ssm'"
ansible_aws_ssm_region: "'eu-north-1'"
ansible_aws_ssm_timeout: "'300'"

View File

@@ -319,6 +319,8 @@
this_is_true_again: "{{ not false }}"
true_is_truthy: "{{ true is truthy }}"
false_is_falsy: "{{ false is falsy }}"
any_element_in_list_is_truthy_results_false: "{{ [false, '', None, 0] is any }}"
all_elements_in_list_are_truthy_results_true: "{{ [true, 'some string', 1] is all }}"
- name: Undefined variables
tags: undefined_variable

View File

@@ -520,3 +520,15 @@ aws sns list-subscriptions-by-topic --topic-arn 'arn:aws:sns:eu-west-1:012345678
# Get information about subscriptions
aws sns get-subscription-attributes \
--subscription-arn 'arn:aws:sns:eu-west-1:012345678901:aSucculentTopic:abcdef01-2345-6789-abcd-ef0123456789'
###
# SSM
# ------------------
###
# Check SSM registered an EC2 instance
aws ssm get-connection-status --target 'i-0123456789abcdef0' --query 'Status' --output 'text'
# Start a shell
aws ssm start-session --target 'i-0123456789abcdef0'