From a439a4e9ef70534cf16effa21033e46e06b8e5ac Mon Sep 17 00:00:00 2001 From: Michele Cereda Date: Sat, 9 Aug 2025 00:12:02 +0200 Subject: [PATCH] feat(ansible): use aws dynamic inventories properly with ssm and host variables --- examples/ansible/ansible.cfg | 3 +- examples/ansible/aws_ec2.yml | 26 --------- knowledge base/ansible.md | 31 ++++++++++- snippets/ansible/commands.sh | 5 ++ .../ec2 instances by instance id.aws_ec2.yml | 55 +++++++++++++++++++ snippets/ansible/tasks/manipulate data.yml | 2 + snippets/aws/other commands.fish | 12 ++++ 7 files changed, 105 insertions(+), 29 deletions(-) delete mode 100644 examples/ansible/aws_ec2.yml create mode 100644 snippets/ansible/ec2 instances by instance id.aws_ec2.yml diff --git a/examples/ansible/ansible.cfg b/examples/ansible/ansible.cfg index 390ba28..b2571d7 100644 --- a/examples/ansible/ansible.cfg +++ b/examples/ansible/ansible.cfg @@ -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 diff --git a/examples/ansible/aws_ec2.yml b/examples/ansible/aws_ec2.yml deleted file mode 100644 index 6c01300..0000000 --- a/examples/ansible/aws_ec2.yml +++ /dev/null @@ -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_' groups for each aws_ec2 host's 'Tags.Name' attribute - prefix: tag_Name_ - separator: "" - - key: tags.application - # add hosts to 'tag_application_' 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 diff --git a/knowledge base/ansible.md b/knowledge base/ansible.md index f05b2e3..1491d2c 100644 --- a/knowledge base/ansible.md +++ b/knowledge base/ansible.md @@ -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.
+> Refer [async_dir not properly expanding variables]. + +Those values are passed to Ansible during execution **as-is**.
+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 diff --git a/snippets/ansible/commands.sh b/snippets/ansible/commands.sh index fa762bc..4224632 100644 --- a/snippets/ansible/commands.sh +++ b/snippets/ansible/commands.sh @@ -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' diff --git a/snippets/ansible/ec2 instances by instance id.aws_ec2.yml b/snippets/ansible/ec2 instances by instance id.aws_ec2.yml new file mode 100644 index 0000000..69baaf6 --- /dev/null +++ b/snippets/ansible/ec2 instances by instance id.aws_ec2.yml @@ -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 and +# . +### + +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:::*' +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'" diff --git a/snippets/ansible/tasks/manipulate data.yml b/snippets/ansible/tasks/manipulate data.yml index 7ba9c36..7c05aab 100644 --- a/snippets/ansible/tasks/manipulate data.yml +++ b/snippets/ansible/tasks/manipulate data.yml @@ -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 diff --git a/snippets/aws/other commands.fish b/snippets/aws/other commands.fish index ff80546..a26b455 100644 --- a/snippets/aws/other commands.fish +++ b/snippets/aws/other commands.fish @@ -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'