<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>configuration management on Digi Hunch</title><link>https://static.digihunch.com/tag/configuration-management/</link><description>Recent content in configuration management on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 08 Apr 2025 14:51:29 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/configuration-management/index.xml" rel="self" type="application/rss+xml"/><item><title>AWS Systems Manager is an Omnipotent Hodgepodge</title><link>https://static.digihunch.com/2023/10/the-systems-manager-hodgepodge/</link><pubDate>Sun, 29 Oct 2023 21:32:49 -0400</pubDate><guid>https://static.digihunch.com/2023/10/the-systems-manager-hodgepodge/</guid><description>&lt;img src="https://static.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://static.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1.webp" alt="" class="wp-image-12960" srcset="https://static.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/10/ssm-diag-1-300x155.webp 300w, https://static.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://static.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://static.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2.webp" alt="" class="wp-image-12961" srcset="https://static.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/10/ssm-diag-2-300x182.webp 300w, https://static.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://static.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://static.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><item><title>Helm – Configuration Management for Kubernetes Resources</title><link>https://static.digihunch.com/2021/07/helm-configuration-management-for-kubernetes-resources/</link><pubDate>Mon, 26 Jul 2021 19:28:22 -0400</pubDate><guid>https://static.digihunch.com/2021/07/helm-configuration-management-for-kubernetes-resources/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-helm.webp" alt="Featured image of post Helm – Configuration Management for Kubernetes Resources" /&gt;&lt;p class="wp-block-paragraph"&gt;Developer ships application in Docker container, so it can eventually hosted in Kubernetes cluster. However, there are still some installation steps, before the application can operate online in production. In this post, we use the container image of Orthanc application as a starting point. We first build services in Kubernetes to go through these steps. Then, to automate the steps, we build a helm chart. The code is kept in &lt;a href="https://github.com/digihunch/korthweb"&gt;Korthweb&lt;/a&gt; project, in which the &lt;a href="https://github.com/digihunch/korthweb/tree/main/manual"&gt;&lt;em&gt;manual&lt;/em&gt;&lt;/a&gt; directory has the files requirement for manual deployment, and the &lt;em&gt;&lt;a href="https://github.com/digihunch/korthweb/tree/main/helm"&gt;helm&lt;/a&gt;&lt;/em&gt; directory is the helm chart.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-manual-deployment"&gt;Manual Deployment&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://digihunch.github.io/korthweb/deployment/manual/"&gt;manual deployment steps&lt;/a&gt; include different kinds of activities, such as creating X.509 certificates, apply config map, create Kubernetes deployment using the YAML declarations, and use helm to install dependency. The steps need to take place in a particular sequence. Some step requires pulling information from secrets created in the previous step. This is why the deployment is not portable. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In order to automate the steps, one might think of wrapper script, which is very limited. A configuration management tool is needed in this scenario. Two common options are Kustomize, and Helm. &lt;a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/"&gt;Kustomize&lt;/a&gt; is a native tool which can be run by kubectl. It is also driven by declarative statement in YAML, which is simple to grasp. However, in lack of a templating mechanism, Kustomize may require wordy statements. Helm, on the other hand, comes with a templating mechanism which greatly increase reusability, making it more suitable for complex steps required in installation.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-helm-repo-and-chart"&gt;Helm Repo and Chart&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Helm is known as package manager for applications running on Kubernetes. Helm defines an application as a collection of related Kubernetes resources, and it manages application deployment through a templated approach. An installation workbook is called a &lt;strong&gt;&lt;em&gt;chart&lt;/em&gt;&lt;/strong&gt;. Charts are kept in repositories. There are some well-known repositories, such as &lt;a href="https://github.com/bitnami/charts"&gt;Bitnami&lt;/a&gt;, Helm &lt;a href="https://charts.helm.sh/stable/"&gt;stable&lt;/a&gt;. You need to add a repostory before using the Helm Charts in it. To add a repo, run:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm repo add bitnami https://charts.bitnami.com/bitnami&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;You can host your own repo (public or private) as well. To search for charts across repositories, the best place is &lt;a href="https://artifacthub.io/"&gt;artifact hub&lt;/a&gt;, which indexes charts from a lot of public repositories. To search for charts from the repositories added, run:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm search repo postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Template is the soul of Helm chart. A Helm chart consists of a directory of files following specific pattern so Helm can understand how to deploy the application. For example, the chart name is the name of the working directory. Under the directory, the values.yaml and chart.yaml defines variables and constants, both serving as template inputs. The template directory is the most important part of the directory where the installation logics are defined. Helm runs the entire directory hierarchy (except for paths specified in .helmignore file) through a Go template rendering engine. The template result spec out the detailed steps.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A great example of using Helm chart to simplify installation is the wordpress chart by Bitnami. You can install all the required components in a single command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install my-release bitnami/wordpress&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://github.com/digihunch/korthweb/tree/main/helm"&gt;helm chart&lt;/a&gt; in &lt;a href="https://github.com/digihunch/korthweb"&gt;Korthweb&lt;/a&gt; project is also an evolving helm chart I created for installing Orthanc application.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Helm V3 (released in late 2019) includes an important architectural change &amp;#8211; the removal of tiller. This means Helm can operate on the client-side &amp;#8211; a significant simplification. Helm graduated from CNCF project in 2020. There are also a few changes in V3, as outlined &lt;a href="https://helm.sh/docs/faq/changes_since_helm2/"&gt;here&lt;/a&gt;, including the &lt;a href="https://helm.sh/docs/faq/changes_since_helm2/#consolidation-of-requirementsyaml-into-chartyaml"&gt;consolidation&lt;/a&gt; of requirements.yaml into Charts.yaml.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-template-and-function"&gt;Template and Function&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As discussed, templating is the key towards reusability and flexibility in configuration management. We&amp;#8217;ve worked with Jinja2 template engine in &lt;a href="https://static.digihunch.com/2020/05/ansible-directory-for-scalability-2-of-2/"&gt;Ansible&lt;/a&gt; and Python. Here in &lt;a href="https://helm.sh/docs/howto/charts_tips_and_tricks/"&gt;Helm&lt;/a&gt;, we use Go templates with some enhancement. The syntax is mostly based on Go template, which is somewhat similar to Jinja2. Helm also added all functions from the &lt;a href="https://masterminds.github.io/sprig/"&gt;Sprig&lt;/a&gt; library, making it more powerful and flexible than Jinja2. Helm chart developer should be very familiar with these functions, as well as the &lt;a href="https://helm.sh/docs/howto/charts_tips_and_tricks/"&gt;best practices&lt;/a&gt;. For example, the &lt;a href="https://masterminds.github.io/sprig/crypto.html"&gt;cryptographic and security functions&lt;/a&gt; in Sprig library gives us the ability to create self-signed X509 certificates during installation.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Since template introduces another layer of abstraction, to help troubleshooting we should be able to preview rendered template with the template command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm template orthanc | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command above simply renders template without attempting to execute the chart. To go one step further, you can dry-run the installation with:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install orthweb ./orthanc --debug --dry-run | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Although Jinja2 (using {% &amp;#8230; %} to express template control) and Go (using {{ &amp;#8230; }} to express template control) have different syntaxes, one aspect that is similar between them, is chomping whitespace with minus sign (-). This is pretty common in templating language. The documentation of both &lt;a href="https://jinja.palletsprojects.com/en/3.0.x/templates/#whitespace-control"&gt;Jinja2&lt;/a&gt; and &lt;a href="https://helm.sh/docs/chart_template_guide/control_structures/#controlling-whitespace"&gt;Helm&lt;/a&gt; have a section on whitespace control. Not paying attention to this nuance may cause pesky errors. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-dependency"&gt;Dependency&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Orthanc application relies on Postgres database, which itself is deployed by a separate helm chart. This can be specified in Chart.yaml (Helm V3), 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;dependencies:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - condition: postgresql-ha.enabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: postgresql-ha&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repository: https://charts.bitnami.com/bitnami&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version: 7.8.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The values of variables of the dependency chart can be specified in values.yaml of the root chart. They can also be imperatively specified as a parameter of helm install command.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The section above also requires the dependency chart to be downloaded into the &lt;em&gt;charts&lt;/em&gt; sub-directory. This can be done with:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm dependency update&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then you will notice a file with tgz extension in the &lt;em&gt;charts&lt;/em&gt; sub-directory. Note that when you change the version of the dependency package in Chart.yaml, then you will need to run the command again. Alternatively, this command can be automatically executed before helm install if you specify the switch &amp;#8211;dependency-update with helm install.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The main chart (e.g. wordpress) is referred to as parent chart, and the charts it depends on are referred to as sub-chart (e.g. mariadb, memcached). When it comes to managing property values, values from parent chart can override those from sub-chart, as explained &lt;a href="https://helm.sh/docs/chart_template_guide/subcharts_and_globals/#overriding-values-from-a-parent-chart"&gt;here&lt;/a&gt;. On the other hand, values from sub-chart can override those from parent chart in two formats: &lt;a href="https://helm.sh/docs/topics/charts/#using-the-exports-format"&gt;export format&lt;/a&gt; (keyword &lt;em&gt;exports&lt;/em&gt;) and &lt;a href="https://helm.sh/docs/topics/charts/#using-the-exports-format"&gt;child-parent format&lt;/a&gt; (keyword import-values). This is something to be careful and we can use the aforementioned template command to display the rendered values.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-hooks"&gt;Hooks&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Helm does a great job in figuring out the dependency relationship between kubernetes objects defined in the chart, and create them in order. So typically you do not need hooks for objects in the chart. However, in certain circumstances, such as cleaning up after uninstallation, we may need hooks. &lt;a href="https://helm.sh/docs/topics/charts_hooks/#the-available-hooks"&gt;Here&lt;/a&gt; is a list of available hooks. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is worth-noting that hook is not tied to an action. Instead it is tied to a kubernetes resource. The resource could be a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/job/"&gt;job&lt;/a&gt;, a config map, etc. The resource is tied to a hook simply by resource &lt;a href="https://helm.sh/docs/topics/charts_hooks/#writing-a-hook"&gt;annotation&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-moving-to-gui"&gt;Moving to GUI&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Helm is a command-line tool. For a team with varying levels of familiarity with command-line, GUI-based tool is a better option. For that, some enterprises adopt &lt;a href="https://rancher.com/products/rancher/"&gt;Rancher&lt;/a&gt;, a &lt;a href="https://www.rancher.com/quick-start"&gt;comprehensive&lt;/a&gt; Kubernetes cluster management platform. Rancher manages many aspects of &lt;a href="https://rancher.com/why-rancher/rancher-strengthens-kubernetes/"&gt;Kubernetes cluster&lt;/a&gt; through web portal. One aspect is the support of &lt;a href="https://ranchermanager.docs.rancher.com/getting-started/installation-and-upgrade/installation-references/helm-chart-options"&gt;helm chart&lt;/a&gt;. Rancher can be install on a cluster of its own. For demo, it can also be &lt;a href="https://rafalfaro.medium.com/how-to-install-rancher-2-5-in-docker-desktops-bundled-kubernetes-cluster-ebd5e1b0ae8"&gt;installed&lt;/a&gt; on &lt;a href="https://docs.docker.com/desktop/kubernetes/"&gt;docker desktop&lt;/a&gt;, a single-node Kubernetes cluster by Docker. In both cases, Nginx ingress controller needs to be configured.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/07/traffic-management-in-kubernetes-service-and-ingress/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Service and Ingress -Traffic Management in Kubernetes&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/08/scalable-infrastructure-deployment-in-terraform/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Infrastructure deployment in Terraform 1/2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>AWS CDK example in Typescript – provision an AWX server</title><link>https://static.digihunch.com/2020/12/ansible-tower-lab-environment-on-aws/</link><pubDate>Sat, 19 Dec 2020 17:14:00 -0400</pubDate><guid>https://static.digihunch.com/2020/12/ansible-tower-lab-environment-on-aws/</guid><description>&lt;p class="wp-block-paragraph"&gt;This post provides an example of using AWS CDK in Typescript.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ansible-tower-and-awx"&gt;Ansible Tower and AWX&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We have used open-source &lt;a href="https://static.digihunch.com/2020/05/revamp-ansible-directory-for-scalability-1-of-2/" class="rank-math-link"&gt;Ansible&lt;/a&gt; extensively in the past. While the automation is convenient, the lack of UI makes it not as suitable as a team collaboration tool. One way to allow team collaboration with open-source Ansible, is to use Jenkins to glue the components together, as discussed in the &lt;a href="https://static.digihunch.com/2020/09/automated-deployment-pipeline-1-2/" class="rank-math-link"&gt;Automated Deployment Pipeline&lt;/a&gt; series. In this setup, the open-source Ansible remains command-line driven, with Jenkins building up the command, rather than a human user. There are many upsides in this configuration, but it is not built specifically for Ansible. Ansible is agent-less, and can be run from any host. This sounds appealing and can work well in smaller server fleet. However, since it requires some configuration on the controlling host for Ansible to function properly, it become unnecessary to configure Ansible environment on every single host (e.g. production). A typically environment only has Ansible environment configured on the bastion host. This brings the need for a dedicated controller server to drive all Ansible tasks.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.ansible.com/products/tower" class="rank-math-link"&gt;Ansible Tower&lt;/a&gt; is Red Hat&amp;#8217;s commercial enhancement to the open source Ansible, providing web-based console, REST API and other services such as Role-based Access Control (RBAC). Managing Ansible via REST API is still somewhat involving but this also enables other open-source contributions to simplify the use of API. For example &lt;a href="https://docs.ansible.com/ansible-tower/3.5.3/html/towerapi/tower_cli.html" class="rank-math-link"&gt;Tower CLI&lt;/a&gt; allows you to use Ansible Tower with simplified command. Ansible Tower has an open-source upstream project called &lt;a href="https://www.ansible.com/products/awx-project/faq" class="rank-math-link"&gt;AWX&lt;/a&gt;, maintained by Red Hat. &lt;a href="https://github.com/ansible/awx" class="rank-math-link"&gt;AWX&lt;/a&gt; is essentially a preview release of Ansible Tower without commercial support. AWX can serve as an engine for all Ansible related task. AWX server is essentially an Ansible control server. AWX, or Ansible Tower, also brings several concepts on top of Ansible:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Job template:&lt;/strong&gt; defines how an Ansible playbook should be executed, including details such as machine credential, project, inventory, and playbook file.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Job:&lt;/strong&gt; the actual execution of job template&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project: &lt;/strong&gt;connects Ansible Tower to source control such as BitBucket. It is tied to a Git repository and a branch within that repository&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To deploy AWX on EC2 instances, there is a &lt;a href="https://aws.amazon.com/quickstart/architecture/awx/" class="rank-math-link"&gt;reference deployment&lt;/a&gt; by AWS. However, it is provided as CloudFormation template and appears to be outdated (from 2018). In our &lt;a href="https://github.com/digihunch/atlab" class="rank-math-link"&gt;project&lt;/a&gt; (late 2020, named ansible tower lab, or dubbed as &amp;#8220;atlab&amp;#8221;), we provide the infrastructure in AWS CDK (written in typescript), to provision the AWX environment. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The goal is that once the configuration is completed, you can run ansible ping against a target EC2 instance. The steps are as automated as possible. However, a number of key steps are purposefully left manual for learning purpose, such as the installation of AWX on EC2 instance.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-infrastructure-as-code"&gt;Infrastructure as Code&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In previous &lt;a href="https://static.digihunch.com/2020/12/instance-initialization-with-aws-cdk-in-python/"&gt;posting&lt;/a&gt;, I created infrastructure as code in AWS CDK with Python, so I decided to change to typescript in this project, with the assumption it is just a matter of syntax mapping. However, I underestimated the transition to a new language I never learned before. A fuzzy understanding of little details such as when to use let a=4 vs this.a=4, may produce elusive errors that takes hours to troubleshoot. I would therefore strongly recommend reading the basic syntax &lt;a class="rank-math-link" href="https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-oop.html"&gt;guide&lt;/a&gt; for typescript, before getting started. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In typescript, this example project provides an implementation of configuring autoscaling groups, including cloud init, user data, etc on AWS. Other than the language, everything else is very similar to the project in this &lt;a href="https://static.digihunch.com/2020/12/instance-initialization-with-aws-cdk-in-python/" class="rank-math-link"&gt;post&lt;/a&gt;, which was developed in Python. Also, note that the project directory structure varies slightly based on the language being used.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you are absolutely new to AWS cdk, start with this &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/hello_world.html" class="rank-math-link"&gt;app&lt;/a&gt;. It is beyond the scope of this post, to cover extensively the installation and environment configuration of AWS CDK.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the provision process for Bastion host, the cloudformation init script pulls a specific version from AWX repository, then makes slight modification. User will need to install it manually. Note that AWX can be installed on three types of platforms:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;OpenShift&lt;/li&gt;&#10;&lt;li&gt;Kubernetes&lt;/li&gt;&#10;&lt;li&gt;Docker Compose&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All are documented in their &lt;a class="rank-math-link" href="https://github.com/ansible/awx/blob/devel/INSTALL.md"&gt;README file&lt;/a&gt;. For simplicity in this project, the installation is on standalone docker compose. This is the default mode so there is no need to modify the inventory file.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-the-code-repo"&gt;The code repo&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The repository is version controlled &lt;a href="https://github.com/digihunch/atlab" class="rank-math-link"&gt;here&lt;/a&gt;. To run the project, you need to have aws cli environment, then install the required packages including node js, and npm packages such as aws cdk. Once configured, validate with command:&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;cdk ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This should display the stacks available. Use cdk deploy to deploy each stack.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When BastionStack is deployed, dependent packages should be installed with user data and cloud init. You will just need to SSH on to the server to manually install AWX, as explained in the instruction, to manually install AWX:&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-playbook -i inventory install.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then you can browse to the server (at port 80 by default). Before the log-in page for the first time, the AWX will upgrade itself, with the following screen presented:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1446" height="988" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-1.png" alt="" class="wp-image-1968"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now log on with default credential (in README.md), you will have the UI for AWX:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1297" height="930" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-4.png" alt="" class="wp-image-1979"/&gt;&lt;figcaption class="wp-element-caption"&gt;AWX Web Console&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From here, you can edit inventory by adding the host. Or use the helper script (~/awxcompose-helper.sh) from bastion host to create a new inventory (named Private Instance Inventory), and populate it with the hosts in the stack. The helper script does so by querying aws resource, and isssue rest API calls to AWX. After executing the script, you can see a new inventory, and the Private instance inventory should contain all hosts in the stack:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="756" height="774" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-6.png" alt="" class="wp-image-1986"/&gt;&lt;figcaption class="wp-element-caption"&gt;Automatically populated inventory&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can then run Ansible ping against the host to validate connectivity. Note that during inventory creation, the ansible_user is already set to ec2-user (by the helper script):&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="921" height="908" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-7.png" alt="" class="wp-image-1987"/&gt;&lt;figcaption class="wp-element-caption"&gt;Ping result&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading" id="h-some-technical-details"&gt;Some technical details&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The initialization process on Bastion host creates an RSA key pair, stores the public key to AWS, for the upcoming private instances to uses. It keeps the private key locally in order to make outgoing SSH connection to the private instances. To ensure connectivity between AWX and private instances, there are a couple of (bash) helper scripts involved. Both reflects some technical details that I had to work through.&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;awxcompose-helper.sh&lt;/strong&gt;: the initialization process pulls AWX installation file from git repo. The installation process will build a docker-compose file in ~/.awx/awxcompose, based on a template (~/awx-*/installer/roles/local_docker/templates/docker-compose.yml.j2). When user tells AWX to connect to private instance, the connection was made out of a docker container (instead of from the OS of bastion host), we need this script to map SSH key file from host to container, by modifying the template file. Without this helper, outgoing SSH connection will fail with error (Permission denied (publickey,gssapi-keyex,gssapi-with-mic)). This script is invoked in the cloud init process without requiring manual execution.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;awxinvt-helper.sh&lt;/strong&gt;: once the private stack is up and the installation has completed, we need to add the hosts to AWX inventory. This script gets the instance ID and IP addresses of the private instances, and uses Rest API calls to create inventory and populate it with hosts. Ansible has multiple &lt;a href="https://www.ansible.com/blog/summary-of-authentication-methods-in-red-hat-ansible-tower" class="rank-math-link"&gt;ways of authentication&lt;/a&gt;. This script uses the non-stateful basic authentication with each curl command requiring credential. Ansible Rest API guide is provided &lt;a href="https://docs.ansible.com/ansible-tower/latest/html/towerapi/api_ref.html" class="rank-math-link"&gt;here&lt;/a&gt; and be wary of the &lt;a href="https://docs.ansible.com/ansible-tower/latest/html/towerapi/conventions.html" class="rank-math-link"&gt;convention&lt;/a&gt; where URI must end with a slash. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This project is just a start of AWX on AWS CDK project using Typescript. In real life scenarios, there are some work to do to make this even more automated. For example, use cfn-hup service to monitor changes of private stack, and therefore update inventories accordingly. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/12/high-performance-computing-cluster/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;High Performance Computing&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/01/basic-kubernetes-resource-object-1-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Basic Resource Object in Kubernetes 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>