<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>cdk on Digi Hunch</title><link>https://static.digihunch.com/tag/cdk/</link><description>Recent content in cdk on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Fri, 02 May 2025 10:58:45 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/cdk/index.xml" rel="self" type="application/rss+xml"/><item><title>Orchestrate Landing Zone with Landing Zone Accelerator on AWS</title><link>https://static.digihunch.com/2023/09/orchestrate-landing-zone-with-landing-zone-accelerator-on-aws/</link><pubDate>Fri, 22 Sep 2023 23:05:04 -0400</pubDate><guid>https://static.digihunch.com/2023/09/orchestrate-landing-zone-with-landing-zone-accelerator-on-aws/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-aws-lza.webp" alt="Featured image of post Orchestrate Landing Zone with Landing Zone Accelerator on AWS" /&gt;&lt;p class="wp-block-paragraph"&gt;As a continuation to the &lt;a href="https://static.digihunch.com/2023/08/control-tower-aws-landing-zone/"&gt;last post&lt;/a&gt;, we explore the &lt;a href="https://aws.amazon.com/solutions/implementations/landing-zone-accelerator-on-aws/"&gt;Landing Zone Accelerator on AWS&lt;/a&gt; (LZA) as an orchestration tool in this post. LZA borrows a lot from the &lt;a href="https://aws-samples.github.io/aws-secure-environment-accelerator/"&gt;ASEA&lt;/a&gt;, an accelerator project to deploy the security reference architecture (&lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/security-reference-architecture/welcome.html"&gt;SRA&lt;/a&gt;). LZA is a multi-purpose project that consists of both the orchestration engine (the accelerator itself) and a few reference architectures (as configuration files).&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Comparison with Control Tower&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;First, let&amp;#8217;s sort out how LZA is related to Control Tower. Control Tower&amp;#8217;s main functionalities are available as an AWS service, with some customization capabilities available as a standalone solution on top of the service, as I discussed in the &lt;a href="https://static.digihunch.com/2023/08/control-tower-aws-landing-zone/"&gt;last post&lt;/a&gt;. Unlike Control Tower, LZA as a whole is a standalone solution. Luckily, the installation of the solution itself is highly automated.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I see LZA both as an extension of Control Tower, and as a complement to Control Tower. It is an extension of Control Tower because LZA can co-exist with Control Tower. We can configure LZA to enable Control Tower and use its Account Factory to provision new accounts (alternatively but not recommended, we can opt out of Control Tower and manage account creation on our own). I also see LZA as a complement to Control Tower because it comes with full end to end automation scheme for networking infrastructure and most of the services involved. This is missing in Control Tower, which leaves it with users to provision networking infrastructure in the customization. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Thanks to the infrastructure automation capability, even if you do not have a strong regulatory requirement, there are still good reason to go with LZA for its low-code automation capability. Below is a table that summarizes the differences:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-light-green-cyan-background-color has-background"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Control Tower&lt;/th&gt;&lt;th&gt;Landing Zone Accelerator&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&amp;#8211; Multi-account management tool&lt;br&gt;&amp;#8211; Governance layer&lt;br&gt;&amp;#8211; Customization Framework to bring your own infrastructure automation&lt;/td&gt;&lt;td&gt;&amp;#8211; can manage Control Tower &lt;br&gt;&amp;#8211; low-code automation engine for infrastructure automation and service deployment based on CDK&lt;br&gt;&amp;#8211; reference configurations based on common industry profiles and regulatory requirements&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class="wp-element-caption"&gt;Comparison between Control Tower and Landing Zone Accelerator&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As the name suggests, LZA is an accelerator so there is no expectation of its user knowing how to program infrastructure as code. However, it still expects its users to know YAML very well. Knowing how CloudFormation and CDK works can greatly help the users troubleshoot deployment. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Reference architectures in LZA&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The input of LZA is configuration as code in YAML format. The LZA repository comes with a number of sample configurations to implement some industry-based best practices. The reference architectures currently include:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;General best practices reference configuration: for clients other than the categories below;&lt;/li&gt;&#10;&lt;li&gt;Government customers: US Gov Cloud (FedRAMP compliant, on aws-us-gov partition), US State and Local Government, China (on aws-cn partition), Canada Federal (CCCS compliant) TSE-SE (&lt;a href="https://d1.awsstatic.com/events/Summits/awscanberrasummit/NEW202_Transform%20national%20security%20and%20defence%20missions%20with%20AWS_PDF.pdf"&gt;Highly Trusted Secure Enclave Sensitive Edition&lt;/a&gt;) on commercial partition for governments, national security, defence, and law enforcement customers reference architecture;&lt;/li&gt;&#10;&lt;li&gt;Election: for election customers including elections agencies, committees and campaigns;&lt;/li&gt;&#10;&lt;li&gt;Healthcare: for healthcare customers. However, the document does not mention HIPAA compliance or anything related to the &lt;a href="https://aws-quickstart.github.io/quickstart-compliance-hipaa/"&gt;HIPAA Reference Architecture&lt;/a&gt;;&lt;/li&gt;&#10;&lt;li&gt;Finance and Taxation: for tax workload to secure Federal Tax Information (FTI) data;&lt;/li&gt;&#10;&lt;li&gt;Education: for education industry customers.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Many of these reference architecture shares a few common traits in the networking design. Take the &lt;a href="https://github.com/awslabs/landing-zone-accelerator-on-aws/tree/main/reference/sample-configurations/lza-sample-config-cccs-medium"&gt;CCCS reference &lt;/a&gt;as an example, the networking involves the followings:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Workload VPCs: consisting of a number VPCs for production and test environments;&lt;/li&gt;&#10;&lt;li&gt;Shared services VPC: hosting common services such as pipelines, Active Directories, etc&lt;/li&gt;&#10;&lt;li&gt;Endpoint VPCs: centrally hosting interface endpoints&lt;/li&gt;&#10;&lt;li&gt;Perimeter VPCs: acting as ingress, egress and inspection VPCs. &lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Perimeter VPC hosts firewalls (either AWS Network Firewall or NGFW appliances behind Gateway Load Balancers). All the VPCs are centrally managed in an AWS network account, and are shared to other accounts using Resource Access Manager. The &lt;a href="https://github.com/aws-samples/landing-zone-accelerator-on-aws-for-cccs-medium/blob/main/architecture-doc/readme.md"&gt;reference architecture &lt;/a&gt;document keeps the details of this architecture, which was derived from the security reference architecture (SRA).&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Special Purpose VPCs&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I consider the non-workload VPCs as special purpose VPCs. The shared services VPC is the most straight-forward. The Endpoint VPC is the most standardized. It is used to centrally host VPC interface endpoints for security and cost reasons. Unlike Gateway endpoint which is only available for S3 and DynamoDB, interface endpoint carries a standing charge and therefore should be consolidated. In addition, since interface endpoints are based on interfaces, we can centrally control the security group and interface policy. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To integrate the endpoint VPC, not only do we need to create those interface endpoint. We also need to account for routing (using Transit Gateway route tables) and name resolution. For name resolution, we need to create a Route53 private hosted zone for each DNS name, such as &lt;code&gt;ec2.us-east-1.amazonaws.com&lt;/code&gt; and associate them with each workload VPC. Note that the interface endpoints DNS name may not always follow the same format. See the exceptions in my &lt;a href="https://static.digihunch.com/2022/12/landing-zone-in-aws/"&gt;old post&lt;/a&gt;. Also note that this would create a lot of associations (between Private Hosted Zone for each Interface endpoint and each workload VPC). For example, 20 workload VPC with 30 private hosted zones will create 600 associations. To overcome this, use &lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/profiles.html"&gt;Route53 profile&lt;/a&gt; (introduced in April 2024).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another special purpose VPC is the perimeter VPC. This VPC vary greatly between customers because of different requirement and historical preferences. One of the key design areas is the placement of NGFW, which is discussed in &lt;a href="https://static.digihunch.com/2024/11/firewall-deployment-patterns/"&gt;this &lt;/a&gt;post.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;LZA Orchestration Engine&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The installation process may feel complex at the beginning because we have to first install the pipeline to that installs the pipeline. The initial setup consists the following steps:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;CloudFormation installs the installer. &lt;/strong&gt;We start with a CloudFormation template to deploy the LZA installer itself. It deploys resources such as CodePipeline (AWSAccelerator-Installer) and CodeBuild project (AWSAccelerator-InstallerProject). These resources are in the INSTALLER circle in the diagram below; &lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;The installer installs the accelerator core.&lt;/strong&gt; In the LZA installer, the CodePipeline (AWSAccelerator-Installer) and CodeBuild project (AWSAccelerator-InstallerProject) drive the installation of the LZA. The input is the official LZA GitHub and we need a GitHub token for this step. The output is the actual LZA orchestration engine, including CodePipeline (AWSAccelerator-Pipeline) and CodeBuild (AWSAccelerator-BuildProject and AWSAccelerator-ToolkitProject). The user may specify their own GitHub repo as the configuration repo. Otherwise, a CodeCommit repo will be created. The LZA resources are shown in the CORE circle in the diagram below;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;The acceleration core configures the landing zone. &lt;/strong&gt;The LZA orchestration engine deploys actual resources in the landing zone, with the CodeCommit repo (aws-accelerator-config) or the specified GitHub repo as input.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="549" src="https://static.digihunch.com/wp-content/uploads/2022/12/base-arch-lza-1024x549.webp" alt="" class="wp-image-12877" srcset="https://static.digihunch.com/wp-content/uploads/2022/12/base-arch-lza-1024x549.webp 1024w, https://static.digihunch.com/wp-content/uploads/2022/12/base-arch-lza-300x161.webp 300w, https://static.digihunch.com/wp-content/uploads/2022/12/base-arch-lza-768x412.webp 768w, https://static.digihunch.com/wp-content/uploads/2022/12/base-arch-lza.webp 1288w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If we enable Control Tower with LZA, we should first log in to management account and configure Landing Zone with Control Tower. we can also create (and register) the required OUs and accounts from Control Tower. Then we can deploy&amp;nbsp;&lt;a href="https://docs.aws.amazon.com/solutions/latest/landing-zone-accelerator-on-aws/step-1.-launch-the-stack.html"&gt;Landing Zone Accelerator&lt;/a&gt;&amp;nbsp;with default configuration. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After the initial setup, we will need to iterate over the &lt;code&gt;aws-accelerator-config&lt;/code&gt; repo. We implement our landing zone design in YAML configuration following the &lt;a href="https://awslabs.github.io/landing-zone-accelerator-on-aws/index.html"&gt;schema documentation&lt;/a&gt;. Changes in the configuration repo will trigger the pipeline (aka LZA&amp;#8217;s orchestration engine) to redo step 3, whereas step 1 and step 2 are performed only once. The duration of step 3 is significantly longer than the first two steps. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Pitfalls&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If LZA manages Control Tower, it expects existing OUs registered in Control Tower or it will report error. For account, LZA can create accounts listed in the manifest but not yet created. However, with the lengthy account vendor process for multiple account we run the risk of task time out in the pipeline.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;During the installation, some account may run into quota limit. For example, the Networking Account usually have more than five VPCs whereas the quota is 5 VPCs per region per account. We need to increase the quota on those accounts.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The full deployment usually creates some SCPs. However, if we ever need to re-deploy a configuration, some steps steps might be blocked by certain SCPs. Attempts to temporarily detach SCPs from OUs, or modify SCPs often get reverted. The cause is an EventBridgeRule in&amp;nbsp;us-east-1&amp;nbsp;region named&amp;nbsp;&lt;code&gt;RevertScpChangesModifySc&lt;/code&gt;. The rule should be disabled temporarily to perform the troubleshooting activity. We can do this with the following steps:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Disable the EventBridgeRule &amp;nbsp;RevertScpChangesModifySc , which is only present in us-east-1 region;&lt;/li&gt;&#10;&lt;li&gt;Detach SCPs and note down what are detached, one OU at a time;&lt;/li&gt;&#10;&lt;li&gt;Go to the failed CF stack in the region, delete the failed stacks (after turning off termination protection);&lt;/li&gt;&#10;&lt;li&gt;Rerun the pipeline step from where it failed. This time it should go past the failure to the end, if SCP is the cause as per our assumption;&lt;/li&gt;&#10;&lt;li&gt;Re-attach SCPs. Suppose Security and Infrastructure OUs share one group of SCPs, and Dev, Test, and Prod OUs share a different group of SCPs;&lt;/li&gt;&#10;&lt;li&gt;Re-enable the EventBridgeRule;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Even with the EventBridgeRule&amp;nbsp;&lt;code&gt;RevertScpChangesModifySc&lt;/code&gt; disabled, when you re-run LZA deployment pipeline, the Accounts step will re-attach the SCPs using the &lt;code&gt;AWSAccelerator-AccountsStack&lt;/code&gt; in the management account in &lt;code&gt;us-east-1&lt;/code&gt; region.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In general, how SCP works with organization structure is something to be very careful about, especially when the hierarchy consists of multiple layers of OUs. It is important to keep in mind, that deny statements in SCP take effect down the hierarchy, where as allow statements only affects the immediate child account of the OU where the SCP is attached to, as per the &lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_evaluation.html"&gt;evaluation logic&lt;/a&gt;. As a result, an SCP with allow * statement (in the &lt;code&gt;LZA-AWSFullAWSAccess&lt;/code&gt; managed policy) must be applied to Root, every OU at each level, and every account, for LZA to function. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition, there are some hard limits for SCP. Each SCP has a size limit of 5120 characters, and each OU can attach a limit of 5 SCPs. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Challenges&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Powered by CDK, LZA automates the creation of a lot of resources. The configuration files uses the &lt;code&gt;deploymentTargets&lt;/code&gt; attribute to allow users to specify to which accounts or OUs the declared resources will be deployed to.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Supporting many resources is a double-edge sword. Because the accelerator needs to go through every aspect of a landing zone, it is very slow to run. The accelerator pipeline may take as long as 40 minutes without any change to the configuration code. This is extremely slow if you just want to make some small changes in the configuration (e.g. update route table, add IAM role). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Even though LZA supports many resources, it&amp;#8217;s not flexible with every resource. For example, today we can deploy IAM roles using &lt;code&gt;&lt;a href="https://awslabs.github.io/landing-zone-accelerator-on-aws/latest/typedocs/latest/classes/_aws_accelerator_config.RoleSetConfig.html"&gt;RoleSet&lt;/a&gt;&lt;/code&gt;. However, in the trust policy of the IAM role you can only specify a two types of principals under the &lt;code&gt;&lt;a href="https://awslabs.github.io/landing-zone-accelerator-on-aws/latest/typedocs/latest/classes/_aws_accelerator_config.RoleConfig.html#assumedBy"&gt;assumedBy&lt;/a&gt;&lt;/code&gt; attribute: &lt;code&gt;account&lt;/code&gt; and &lt;code&gt;service&lt;/code&gt; types. On the other hand a trust policy can support many other &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html"&gt;types of principals&lt;/a&gt; such as another IAM role.&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="611" height="321" src="https://static.digihunch.com/wp-content/uploads/2023/09/lza-az-mapping.webp" alt="" class="wp-image-12957" srcset="https://static.digihunch.com/wp-content/uploads/2023/09/lza-az-mapping.webp 611w, https://static.digihunch.com/wp-content/uploads/2023/09/lza-az-mapping-300x158.webp 300w" sizes="auto, (max-width: 611px) 100vw, 611px" /&gt;&lt;figcaption class="wp-element-caption"&gt;AZ Mapping&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another important ability that LZA does not support is consistent AZ mapping across accounts. (&lt;strong&gt;Correction&lt;/strong&gt;: this is now supported in &lt;a href="https://github.com/awslabs/landing-zone-accelerator-on-aws/releases/tag/v1.5.0"&gt;LZA v1.5&lt;/a&gt; as of Oct 2023). In some example LZA configurations, we deploy VPCs across multiple accounts using two or three availability zones referenced by their logical ID, such as &lt;code&gt;us-east-1a&lt;/code&gt; and &lt;code&gt;us-east-1b&lt;/code&gt;. However, AWS &lt;a href="https://docs.aws.amazon.com/ram/latest/userguide/working-with-az-ids.html"&gt;maps logical ID to physical ID&lt;/a&gt; and the mapping may be different in each AWS account. Using the same logical ID cannot guarantee the physical AZ are the same across account. As of LZA 1.5, the ability to reference physical ID in &lt;a href="https://awslabs.github.io/landing-zone-accelerator-on-aws/latest/typedocs/interfaces/___packages__aws_accelerator_config_lib_models_network_config.ISubnetConfig.html#availabilityZone"&gt;availabilityZone&lt;/a&gt; is supported in LZA configuration file.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;ve spent a lot of time on LZA recently. It is extremely powerful. LZA streamlined the landing zone deployment process with configuration as code. It also allows users to customize their landing zone towards their own architectural needs and compliance requirement. For example, you can declare arbitrary SSM parameters in each account. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the down side, the LZA deployment is time consuming through the pipelines. It tries to automate too many aspects of the infrastructure, which makes itself quite a complex project. Expect lots of changes in each new version. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The idea of being a low-code solution is to make it simple for end users but it often sacrifices flexibility. For example, if you want to create an IAM role in each new account that references the Management account ID, it is not possible until such feature is implemented in the accelerator. When the accelerator pipeline fails, it still requires deep CloudFormation knowledge to troubleshoot. &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/08/control-tower-aws-landing-zone/"&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 AWS Control Tower&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2023/10/the-systems-manager-hodgepodge/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;AWS Systems Manager is an Omnipotent Hodgepodge&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>