<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Systems Manager on Digi Hunch</title><link>https://www.digihunch.com/tag/systems-manager/</link><description>Recent content in Systems Manager on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 10:34:44 -0400</lastBuildDate><atom:link href="https://www.digihunch.com/tag/systems-manager/index.xml" rel="self" type="application/rss+xml"/><item><title>Managing EC2 instances across accounts with Ansible</title><link>https://www.digihunch.com/2024/05/managing-ec2-instances-across-aws-accounts-ssm/</link><pubDate>Mon, 27 May 2024 14:00:22 -0400</pubDate><guid>https://www.digihunch.com/2024/05/managing-ec2-instances-across-aws-accounts-ssm/</guid><description>&lt;img src="https://www.digihunch.com/wp-content/uploads/2025/04/feature-ec2-ssm.webp" alt="Featured image of post Managing EC2 instances across accounts with Ansible" /&gt;&lt;p class="wp-block-paragraph"&gt;I regard &lt;a href="https://aws.amazon.com/systems-manager/"&gt;AWS Systems Manager&lt;/a&gt; as &lt;a href="https://www.digihunch.com/2023/10/the-systems-manager-hodgepodge/"&gt;omnipotent&lt;/a&gt;. Nonetheless, there are a few reasons that makes &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; still a prevalent VM (EC2) management tool over Systems Manager (SSM). First, organizations already vested in their custom Ansible &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html"&gt;roles&lt;/a&gt; and &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html"&gt;playbooks&lt;/a&gt; want to reuse, and expand their assets in Ansible. The benefit is consistency in the VM management, over time, and across platforms (AWS, on-prem, Azure, etc). Even for AWS shops, in the last few years many enterprises have adopted &lt;a href="https://www.digihunch.com/2022/12/landing-zone-in-aws/"&gt;AWS landing zone&lt;/a&gt; with the &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html"&gt;multiple AWS account&lt;/a&gt; prescriptive pattern. However AWS Systems Manager still lacks integration with &lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/services-that-can-integrate-ssm.html"&gt;AWS Organization&lt;/a&gt; (except for a few non-core capabilities). This creates the demand of managing EC2 instances across AWS accounts. In this post, we propose a secure method to manage a fleet of EC2 instances from multiple AWS accounts, using Systems Manager . It also enables connectivity from an Ansible control node.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Prerequisites&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This proposal ties a few CLI tools together, including AWS CLI, SSH, Ansible, etc. It also requires the cloud engineer to understand how they work. I&amp;#8217;ll start with the choice of the tools.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Above, I discussed the benefit of Ansible. Since Ansible operates on SSH, we&amp;#8217;ll still have to use SSH tools. Even though SSM agent provides a way to connect to EC2 instance without requiring an RSA key pair, we still need SSH since it is a well-established &lt;a href="https://datatracker.ietf.org/doc/html/rfc4253"&gt;industry standard&lt;/a&gt; (RFC4253) and the foundation of Ansible. These two technologies are not mutually exclusive. In fact, the SSM agent provides a secure enhancement to the operation with SSH. Traditionally, on each EC2 instance we&amp;#8217;d have to run SSHD services which opens TCP port 22 (or alternative TCP port as configured). For authentication we favour key pair over password but the open port is still an attack surface vulnerable to brute force and DDoS attacks. For EC2 instances on private networks there is no reachability to the instance&amp;#8217;s SSH port unless the bastion is also in a connected network. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As I cover in a &lt;a href="https://www.digihunch.com/2023/10/the-systems-manager-hodgepodge/"&gt;post&lt;/a&gt;, the SSM Session Manager comes in handy. The SSM agent operates from the instance and communicate outbound to AWS backend. Since the SSM agent runs under a privileged user on the OS, you can perform OS-level commands through SSM. Further, AWS developed a &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html"&gt;Session Manager plugin&lt;/a&gt; with AWS CLI, allowing AWS CLI as a proxy command when making an SSH connection. Therefore SSM enables SSH connection without requiring port 22 to be open. In addition we&amp;#8217;ll need to use RSA key pair as required for SSH, which is also an improvement to the security posture. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;That explains the dependent tools. On the Ansible &lt;a href="https://docs.ansible.com/ansible/latest/network/getting_started/basic_concepts.html#control-node"&gt;control node&lt;/a&gt;, apart from Ansible itself, we need the latest version of AWS CLI with the &lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/services-that-can-integrate-ssm.html"&gt;Session Manager plugin&lt;/a&gt;, we need to configure AWS CLI properly to connect to EC2 instances across multiple AWS accounts. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Configure AWS CLI&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This section discusses how to configure AWS CLI. I have a couple of handy aliases for productivity but they are not essential. For example, I often need to check the IAM identity making the call, and I often need to list out all profiles configured. So I added the following two entries in the &lt;code&gt;~/.aws/cli/alias&lt;/code&gt; file:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[toplevel]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;whoami = sts get-caller-identity --no-cli-pager --output yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;profile = configure list-profiles&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;With that I have an alias to check IAM identity and available profiles. Then we can start configuring the profiles for CLI (in the file &lt;code&gt;~/.aws/config&lt;/code&gt;). Since we&amp;#8217;ll be working with multiple AWS accounts, we have to manage multiple CLI profiles, which implies that:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;We better use the &lt;code&gt;--profile&lt;/code&gt; switch to explicitly specify profile being used, instead of relying on the &lt;code&gt;AWS_PROFILE&lt;/code&gt; environment variable;&lt;/li&gt;&#10;&lt;li&gt;As a security best practice, we should not configure profiles with &lt;a href="https://docs.aws.amazon.com/sdkref/latest/guide/access-iam-users.html"&gt;long-term IAM credential&lt;/a&gt; in the config file;&lt;/li&gt;&#10;&lt;li&gt;We must ensure the CLI doesn&amp;#8217;t prompt for log-in every time we switch profile&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To satisfy #3 there are many ways but we&amp;#8217;ll discuss two: using cross-account IAM role, and using AWS SSO.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Bonus point if you enable &lt;a href="https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-completion.html"&gt;auto-complete&lt;/a&gt; for AWS CLI.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Configure AWS CLI Profiles&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With cross-account IAM role, the idea, is that the client start with one IAM identity, and use that IAM identity to assume roles on several other accounts. The configuration looks like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[profile jump_account]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;credential_process = /opt/bin/awscreds-custom --username helen&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[profile target_account_1]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;role_arn = arn:aws:iam::123456789011:role/OrganizationAccountAccessRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source_profile = jump_account&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[profile target_account_2]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;role_arn = arn:aws:iam::123456789012:role/OrganizationAccountAccessRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source_profile = jump_account&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this example, you start with an validated identity in the jump account, then assume a privileged IAM role named OrganizationAccountAccessRole on the target accounts. Typically such IAM roles are pre-configured (e.g. in an multi-account landing zone) with appropriate trust policy to allow principals from the jump account. Once you&amp;#8217;re validated as the IAM identity in the jump account, then you can use profiles for target accounts without being prompted for credentials again.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If your have configured IAM Identity Center for the multi-account environment, consider an alternative approach using sso login. The configuration usually looks like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[sso-session sso]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_start_url = https://myorg.awsapps.com/start/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_region = us-east-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_registration_scopes = sso:account:access&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[profile target_account_1]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_session = sso&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_account_id = 123456789011&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_role_name = AWSAdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[profile target_account_2]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_session = sso&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_account_id = 123456789012&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sso_role_name = AWSAdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This is often used by human users with SSO credential. In this example, to authenticate the sso session, start with command &amp;#8220;aws sso login&amp;#8221; . Then you can use all profiles by specifying &lt;code&gt;--profile&lt;/code&gt; switch without having to log in again.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Configure SSH to EC2 via SSM&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The EC2 instance must connect to Systems Manager &lt;a href="https://docs.aws.amazon.com/general/latest/gr/ssm.html"&gt;endpoint&lt;/a&gt;, before one can SSH to the instance using the plugin. Once connected, you should find the instance in &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/fleet.html"&gt;Fleet Manager&lt;/a&gt;. For this to happen, there are a few conditions. First, the instance must be able to reach the endpoint, either via public Internet, or via VPC interface endpoints if in a private subnet. Second, the instance profile must contain an IAM role with appropriate permissions. We can use AWS managed policy AmazonSSMManagedInstanceCore in the role. In addition, if we record the SSM session to an S3 bucket with encryption the instance profile must have permission to use the encryption key.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="511" height="141" src="https://www.digihunch.com/wp-content/uploads/2024/05/ssh-ssm.webp" alt="" class="wp-image-12985" srcset="https://www.digihunch.com/wp-content/uploads/2024/05/ssh-ssm.webp 511w, https://www.digihunch.com/wp-content/uploads/2024/05/ssh-ssm-300x83.webp 300w" sizes="auto, (max-width: 511px) 100vw, 511px" /&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SSM agent uses the IAM role. The agent runs as a service on Linux or Windows machines. Many AWS managed AMIs come with SSM agent pre-installed. If that is not the case, you&amp;#8217;d install the agent in your own AMI, or in user data which requires downloading the installer. With these configuration you&amp;#8217;d be able to connect to the instance via SSM. We can use AWS &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-sessions-start.html#sessions-start-cli"&gt;CLI SSM command&lt;/a&gt;, or AWS web console to start an SSH session. To use SSH CLI utility, we install the &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/plugin-version-history.html"&gt;session manager plugin&lt;/a&gt; along with AWS CLI on the SSH client machine. We also specify a public key for EC2 instance and run ssh command with the private key. The SSH configuration needs a configuration such as:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;host i-* mi-*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProxyCommand sh -c &amp;#34;aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters &amp;#39;portNumber=%p&amp;#39;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; User ec2-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IdentityFile ~/.ssh/id_rsa&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;With this entry, you may directly SSH by instance ID (usually starting with i-* and mi-*), and the specified Proxy Command with SSM session document AWS-StartSSHSession will be invoked. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Configure Ansible Inventory&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can SSH to an instance (without port 22 open, on top of SSM) using the method above. Similarly, we can also configure Ansible to connect to the instance, without port 22. The inventory configuration looks like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mytest:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; instance1:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_host: i-00aabbffcc7755221&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_user: ubuntu&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_ssh_common_args: -o ProxyCommand=&amp;#34;aws ssm start-session --target %h --document-name AWS-StartSSHSession --profile target_account_1&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; instance2:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_host: i-eedd88ff66aa22442&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_user: ubuntu&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_ssh_common_args: -o StrictHostKeyChecking=no -o ProxyCommand=&amp;#34;sh -c \&amp;#34;aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters &amp;#39;portNumber=%p&amp;#39; --profile target_account_2 \&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note I used two patterns for ansible_ssh_common_args that are similar. Both works. Each entry references its own profile. This is necessary because Ansible does not have the knowledge which instance belongs to which profile&amp;#8217;s account.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another way to get Ansible connect to instances is to use the connection plugin &lt;a href="https://docs.ansible.com/ansible/latest/collections/community/aws/aws_ssm_connection.html"&gt;community.aws.aws_ssm&lt;/a&gt;, by specifying ansible_connection: aws_ssm (e.g. as host variable) and other required variables (e.g. profile). This method does not require SSH channel but it requires an S3 bucket, and hence IAM permission on the controller node.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ansible supports dynamic inventory, in three ways: inventory source file (with existing plugin), custom inventory plugin, and inventory script (in Python). Take source file as an example for EC2, add the followings as the content of aws_ec2.yaml:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plugin: amazon.aws.aws_ec2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Attach the default AWS profile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws_profile: target_account_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;compose:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_host: instance_id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_user: &amp;#34;&amp;#39;ubuntu&amp;#39;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_ssh_common_args: &amp;#34;&amp;#39;-o ProxyCommand=\&amp;#34;aws ssm start-session --target %h --document-name AWS-StartSSHSession --profile target_account_1 \&amp;#34;&amp;#39;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then we can display the rendered inventory list, and Ansible-ping the instances. &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ansible-inventory -i aws_ec2.yaml --list -y | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ansible all -i aws_ec2.yaml -m ping&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;For more flexibility, for the composed variables, we could use jinja2 expression to generate the value. In both ways, we produce an inventory source per profile using the &lt;a href="https://vexpose.blog/2023/11/20/ansible-dynamic-inventory-tutorial/"&gt;built-in inventory plugin&lt;/a&gt; aws_ec2. For greater flexibility, such as consolidating instances from all accounts into a single inventory, consider writing your own&lt;a href="https://www.redhat.com/sysadmin/ansible-dynamic-inventories"&gt; inventory script&lt;/a&gt;, or even &lt;a href="https://www.redhat.com/sysadmin/ansible-plugin-inventory-files"&gt;own inventory plugin&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this post we propose a way to manage instances across AWS accounts. Two main challenges are establishing the communication channel (SSH on top of SSM) and generating inventory data in Ansible. Some AWS services can generate inventory data, such as &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-inventory-datasync.html"&gt;resource data sync&lt;/a&gt; in Systems Manager, or using AWS Config Aggregator. It is unfortunate that neither way produces the inventory data in a format that is directly compatible with Ansible inventory. Therefore, you might have to create a custom Ansible dynamic inventory script (in Python) that reads from the inventory data from AWS Config Aggregator (which supports AWS Organization). The side benefit of this script is that it is usually faster than the built-in &lt;a href="https://docs.ansible.com/ansible/latest/collections/amazon/aws/aws_ec2_inventory.html"&gt;aws_ec2&lt;/a&gt; inventory plugin.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2024/03/public-key-infrastructure-3-of-3-use-cases/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Public Key Infrastructure 3 of 3 – PKI Implementation&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2024/07/iam-roles-for-any-workload/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;IAM Roles for any workload&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>AWS Systems Manager is an Omnipotent Hodgepodge</title><link>https://www.digihunch.com/2023/10/the-systems-manager-hodgepodge/</link><pubDate>Sun, 29 Oct 2023 21:32:49 -0400</pubDate><guid>https://www.digihunch.com/2023/10/the-systems-manager-hodgepodge/</guid><description>&lt;img src="https://www.digihunch.com/wp-content/uploads/2025/04/feature-ssm.webp" alt="Featured image of post AWS Systems Manager is an Omnipotent Hodgepodge" /&gt;&lt;h2 class="wp-block-heading"&gt;Introduction to Systems Manager&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS Systems Manager addresses a lot of SysOps requirements for configuration management, including server automation. In this domain, there is another AWS service called OpsWorks. However, with OpsWorks Stack, OpsWorks Chef and OpsWorks Puppet all coming EOL in 2024, the entire OpsWorks service is mostly deprecated. By partnering with leaders such as Chef and Puppet, OpsWork services represent the era when AWS needed to mirror the configuration management capability on premise, in an effort to convince customers migrating to the cloud. Today, AWS Systems Manager has evolved to fill a lot of gaps around configuration management for servers in the cloud. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="530" src="https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1.webp" alt="" class="wp-image-12960" srcset="https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1.webp 1024w, https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1-300x155.webp 300w, https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1-768x398.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although AWS Systems Manager sounds like a single service. It consists a collection of many seemingly disparate capabilities that serves similar requirements around configuration management. In fact, many of the Systems Manager capabilities are built on top of a couple of what I call core capabilities, such as Session Manager, RunCommand, Automation. This post will review these core capabilities and how Systems Manager employs them to expand with other capabilities.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;SSM Agent and Session Manager&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;What enables all other capabilities is the SSM agent installed on the EC2 instances. The agent running as a systemctl task by ssm-user on EC2 instances. Most of AMIs come with this agent pre-installed. It stores the logs in /var/log/amazon/ssm/. This agent works with an instance profile with a role with the AmazonSSMManagedInstanceCore managed policy, in order to communicate with AWS Systems Manager (ssm.&amp;lt;region&amp;gt;.amazonaws.com) backend. Because of that, you also need to provide a network path to the backend endpoint, either via Internet, or interface endpoint. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This communication also allows an IAM user to connect to an instance&amp;#8217;s shell. A common use case is for private instance that do not have Internet access but do have access to SSM backend endpoint. In &lt;a href="https://www.digihunch.com/2023/06/connect-kubectl-to-private-kubernetes-cluster-in-eks-and-aks/"&gt;a previous post&lt;/a&gt; I discussed using Session Manager to replace a bastion host to connect to EKS nodes. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When launching an instance using an AMI with SSM pre-installed, the SSM agent should launch after all the config sets from &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html"&gt;Cloudformation Init&lt;/a&gt; are finished. As a result, the Cloudformation Init script is not able to communicate with SSM backend via the agent, unless you install and start SSM agent first on your own, in CloudFormation Init. To troubleshoot SSM, it is important to review its &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-agent-logs.html"&gt;logs&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Through Systems Manager Hybrid Activation, the SSM agent can also work on virtual machines out of AWS and report back to with SSM backend. This gives on-prem servers the identities (instance tags, instance profiles) required for Systems Manager to manage them as if they were EC2 instances. As a result, extend Systems Manager capabilities to on-prem fleet (requiring advanced instances tier).&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Types of SSM Documents&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are several &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/documents.html"&gt;types&lt;/a&gt; of document that SSM uses, including:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Command Document&lt;/li&gt;&#10;&lt;li&gt;Automation Document&lt;/li&gt;&#10;&lt;li&gt;Package Document&lt;/li&gt;&#10;&lt;li&gt;Session Document&lt;/li&gt;&#10;&lt;li&gt;Policy Document&lt;/li&gt;&#10;&lt;li&gt;Change Calendar Document&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The AWS documentation has a &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/documents.html#what-are-document-types"&gt;table&lt;/a&gt; on what they each are for. Here I&amp;#8217;ll focus on three types of documents: Command Document, Automation Document and Session Document.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Command Document is for the RunCommand capability. It executes on EC2 instances usually performing tasks relating to the operating system or application. I think of a Command Document as an Ansible Playbook that consists of Ansible tasks. We can author Command document that runs configuration steps using &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/documents-command-ssm-plugin-reference.html"&gt;plugins&lt;/a&gt;, such as &lt;code&gt;aws:downloadContents&lt;/code&gt;, &lt;code&gt;aws:runShellScript&lt;/code&gt;, etc. This feature directly competes with Ansible. To troubleshoot why a command fail on an instance, check the file &lt;code&gt;ssm-document-worker.log&lt;/code&gt; in the ssm agent log directory. Each log entry should have a command ID as reference.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Automation Document (aka runbooks) is for the Automation Capability. You can define sequence of actions for automation. There are many pre-defined &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/automation-actions.html"&gt;actions &lt;/a&gt;such as executing AWS API calls (&lt;code&gt;aws:executeAwsApi&lt;/code&gt;), run commands (&lt;code&gt;aws:runCommand&lt;/code&gt;), or executing a Lambda function. Therefore a runbook requires an IAM role (Automation Role). The schema of action sequence (YAML or JSON) looks very similar to an Ansible playbook. The web console comes with an UI to visualize the action sequence but most of the time I&amp;#8217;d rather . &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Session Document is for Session Manager capability. AWS Systems Manager Session Manager uses Session documents to determine which type of session to start, such as a standard session, a port forwarding session, or a session to run an interactive command. In most cases, automation developers do not need to create their own Session document, because the pre-built ones are sufficient:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;AWS-PasswordReset&lt;/li&gt;&#10;&lt;li&gt;AWS-StartInteractiveCommand&lt;/li&gt;&#10;&lt;li&gt;AWS-StartPortForwardingSession&lt;/li&gt;&#10;&lt;li&gt;AWS-StartPortForwardingSessionToSocket&lt;/li&gt;&#10;&lt;li&gt;AWS-StartSSHSession&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In my experience, I use the &lt;code&gt;AWS-StartSSHSession&lt;/code&gt; and &lt;code&gt;AWS-StartPortForwardingSession&lt;/code&gt; documents most often. To establish SSH connection for forward port to connecting host for Remote Desktop session. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To author your own document, reference the &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/documents-schemas-features.html#documents-schema-twox"&gt;schema&lt;/a&gt; correctly and use the latest SSM agent. However, I would explore if any existing &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/documents-ssm-sharing.html"&gt;shared document&lt;/a&gt; in the library already covers what you need. For example, the command document AWS-JoinDirectoryServiceDomain help join a Windows server to a managed Active Directory domain. The command document AWS-RunPatchBaseline is used by Systems Manager Patch Manager capability to check and apply operating system patches. They include steps for Windows, MacOS and Linux instances. The automation runbook AWS-AttachIAMToInstance helps you add IAM role to an EC2 instance. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;RunCommand and Automation&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Run Command capability run on top of SSM agent. You can specify one or more target instances. You also specify other other options such as command parameters, rate control and where the output goes. This capability allows an IAM user to run command directly on the OS of an instance (using an OS user ssm-agent) and centrally keep track of those command runs on the AWS side. The most common commands to run on the OS is packaged into Command Documents. There is even a Command Document that allows you to run a pre-built &lt;a href="https://aws.amazon.com/blogs/mt/running-ansible-playbooks-using-ec2-systems-manager-run-command-and-state-manager/"&gt;Ansible playbook&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another way this capability is extremely helpful, is that we can reduce the load of cloud init process. Traditionally, we put a log of logics in the user data script for the cloud init process to execute. The &lt;a href="https://help.ubuntu.com/community/CloudInit"&gt;cloud-init&lt;/a&gt; mechanism comes from Linux OS and the execution of the user data script is not very transparent to troubleshoot. You have to check the cloud-init-output log from the OS. The use of the UserData script should be reserved for establishing communication with CloudFormation endpoint and SSM endpoint. From there, other automation tasks should be done using SSM capabilities (e.g. State Manager) for better manageabilities. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Take an example of joining a newly provisioned Windows server to a domain. If we do this in user data script, we will have a few problems. First, we can only tell success/fail state from logs in the OS. Second, if an OS user inadvertently removed the instance from domain, there is no mechanism to capture that. If we use Systems Manager&amp;#8217;s RunCommand capability, along with State Manager association, the AWS management console will be able to tell whether domain joining is successful, and the association can detect when the instance is removed from domain, report this finding as out of compliance, and remediate the issue. We&amp;#8217;ll discuss State Manager in more detail in the next section.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As part of automation, we often have to invoke AWS API calls, which happens outside of any target VMs. The Automation capability of Systems Manager is for this scenario. You can orchestrate your API calls using Automation runbooks. These automation steps do not execute on any target EC2 instance, so they do not rely on SSM agent. However, it needs its own IAM role to perform API tasks. This capability saves you from having to run API calls by creating a new Shell environment to run AWS CLI, or from your own Lambda function using the &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html"&gt;boto3 &lt;/a&gt;SDK library. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When we combine Automation and RunCommand capabilities, we can perform most of the automation orchestration steps. They are the core capabilities that further enable a variety of other Systems Manager capabilities.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Maintenance Window and State Manager&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Maintenance window is a very straight forward capability to schedule RunCommand activity with a cron or rate &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/reference-cron-and-rate-expressions.html"&gt;expression&lt;/a&gt;. You can specify target by instance tags, define one or more tasks, and define a window of activity and at what point prior to the end of Windows should the agent stop performing more activities (cutoff). Each task can be a type of a RunCommand command, Step Function, Lambda function and automation runbooks.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;State Manager is a similar capabilities with a lot of feature overlap with Maintenance Window. State Manager operates on the concept of &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/state-manager-associations.html"&gt;associations&lt;/a&gt;. An association connects target instances to command document or automation runbook to execute. Similar to Maintenance Window, you can specify a schedule expression, document parameters and instance tags. State Manager was brought in to combat configuration drift. The associated document should consist of idempotent scripts so that a State Manager association can repeatedly execute these documents to ensure compliance.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Maintenance Window is more about scheduling one or more tasks. On the State Manager side however, association failure by default will be reported as out of compliance compliance. This is useful in scenarios such as keeping a Window instance in the domain, or keeping SSM agent up to date. You can choose either capability for many common setups but they have subtle differences. For example, for Patch management, you can use State Manager to detect missing patches and report compliance, and Maintenance Window to actually apply the missing patches. In fact, there is a document page on &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/state-manager-vs-maintenance-windows.html"&gt;choosing between State Manager and Maintenance Windows&lt;/a&gt; to distinguish their best use cases.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Fleet Manager and Inventory&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Fleet Manager presents a centralized view for all instances for users to perform common administration tasks, such as exploring file systems and logs, admin users and groups, manage registry and events on Windows instances, check processes and performance metrics. It also gives shortcuts to patch nodes, run commands, start session, etc. I think of Fleet Manager as a minimalist configuration management UI. It is not as sophisticated as those from Ansible Tower or Puppet but it comes at no additional cost.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A very useful feature of Fleet Manager is to run a web-based remote desktop to connect to Windows Instances. This saves the need for a bastion host as long as the instances have SSM connection. You will need the RSA private key to decrypt the Administrator password, which I would not recommend. If the Windows server is on a domain, you can enter your domain credential via Fleet Manager. If the users logged in via IAM identity center, Fleet Manager also has the login option for them via SSO using &lt;a href="https://aws.amazon.com/blogs/security/how-to-enable-secure-seamless-single-sign-on-to-amazon-ec2-windows-instances-with-aws-sso/"&gt;IAM Identity Center identity&lt;/a&gt;. When a user logs in this way, Fleet Manager uses RunCommand capability to execute &lt;code&gt;AWSSSO-CreateSSOUser&lt;/code&gt; document against the server to create a local admin user.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another aspect of configuration management is the inventory management. Unlike in Ansible, the term inventory in the context of Systems Manager refers to the metadata of instances, which includes installed applications, AWS components, network configurations, instance details, services, Windows registry and roles, etc. The full list of what is part of metadata is in the &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-inventory.html"&gt;document&lt;/a&gt; and you can even define your own inventory item. To gather inventory data, we can makes use of a State Manager association to execute the AWS-GatherSoftwareInventory &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/syman-inventory-troubleshooting.html"&gt;document&lt;/a&gt;. Once we set up the association, the agents will report inventory data back to Systems Manager. More importantly, we can create Resource Data Sync objects to write inventory data (along with compliance data) to S3 buckets, allowing downstream applications to consume. A common use case is to run Athena query against those bucket and produce QuickSight dashboard. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Patch Manager and Compliance&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Patch Manager also operates on State Manager associations. The automation runbook is &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager-aws-runpatchbaseline.html"&gt;AWSRunPatchBaseline&lt;/a&gt;, where you can just scan for missing patches or install them as well. The SSM document can run on all three platforms (Windows, Linux and MacOS) and determines which patches are missing relative to a the Patch Baseline. There should be at least one default Patch baseline. Each OS (e.g. Ubuntu, Debian, Amazon Linux, etc) classifies patches differently, and a &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager-predefined-and-custom-patch-baselines.html"&gt;patch baseline&lt;/a&gt; is a configuration that defines whether a patch is approved based on operating system and their classifications. The automation document also allows you to override the patch baseline. When executing the document to scan for patches, it records patch compliance information using the PutInventory API command. When using the document to install patches, you can run the document from a Maintenance Window and specify whether you need to reboot the target instance if required.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The compliance capability reports compliance status for instances. By default there are two types of compliance: association and patch. The association compliance detects whether a state manager association is failed on certain instances. The patch compliance, as just mentioned, checks whether patches are up to date relative to the specified patch baseline. You can also define custom compliance item (with put-compliance-items API) but the documentation isn&amp;#8217;t clear on what exactly it can achieve and where on the instance does it pull the compliance status. From the example in put-compliance-items, custom compliance type seems to check the installation of additional software package in the inventory.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Other capabilities&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amongst the other capabilities, the one I use the most often is parameter store, which is a way to store a variable for different services to consume. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the domain of change management, the change manager is a mini change management system. Organization can use it to manage their change process such as approvals. More importantly, you can fire automation runbook from change manager and tie it back to the change control item. Change calendar allows you to block changes during specific period. Both of them are organization level capabilities.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When it comes to operations management, the Incident Manager capability allows you to create response plan for incidents. Response plan can execute runbook actions once an incident is logged. It also helps you notify the on-call incident response team. On the other hand, OpsCenter capability allows you to create OpsItem, which also includes a way to execute runbook. The OpsData can aggregate to Explorer, which is a centralized dashboard for operations data. The Explorer, OpsCenter and Incident Manager capabilities can operate at organization level. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These capabilities around change management and operations management come nowhere close to full-fledged ITSM solutions such as ServiceNow or SMAX. However, they have the ability to trigger runbooks and natively integrate with other AWS services.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is also a quick setup capability which uses pre-baked CloudFormation template to configure other services. For Patch manager the current recommendation is to use quick setup to configure patch policy.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Systems Manager has so many capabilities that I cannot cover everything in a single post. &lt;a href="https://www.youtube.com/watch?v=SYsp-AnciZA"&gt;Here&lt;/a&gt; is a good walk-through. Some capabilities like session manager, fleet manager and state manager, are extremely helpful. However, in my opinion, there are two problems with grouping all these capabilities under Systems Manager. First, With too many different capabilities, this service lacks focus, which makes it difficult to learn. Second, some capabilities have overlap with other capabilities, or another AWS services, which also makes it confusing. I try to sort out how these capabilities enable each other in the diagram below: &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="620" src="https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2.webp" alt="" class="wp-image-12961" srcset="https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2.webp 1024w, https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2-300x182.webp 300w, https://www.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2-768x465.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This diagram may not be 100% accurate but it demonstrate the dependencies and can assist troubleshooting. For example, when compliance is missing data, check the execution history of run command. It also illustrates the key role of SSM agent as the underlying enabler of most of the other capabilities.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Overall, Systems Manager is extremely powerful. You can try to replace your server management solutions (e.g. Ansible, Chef and Puppet) with Systems Manager configurations. With a good understanding of its capabilities, you can build your fleet automation in an efficient and scalable way. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2023/09/orchestrate-landing-zone-with-landing-zone-accelerator-on-aws/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Orchestrate Landing Zone with Landing Zone Accelerator on AWS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2023/11/wordpress-security/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;WordPress Security Basics&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>