<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: John  Ajera</title>
    <description>The latest articles on DEV Community by John  Ajera (@jajera).</description>
    <link>https://dev.to/jajera</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2461160%2Fefda9ea8-49f8-4d07-b358-445b8e7d5a20.png</url>
      <title>DEV Community: John  Ajera</title>
      <link>https://dev.to/jajera</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jajera"/>
    <language>en</language>
    <item>
      <title>Configuring AWS Business Support+</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Mon, 13 Apr 2026 23:21:19 +0000</pubDate>
      <link>https://dev.to/jajera/configuring-aws-business-support-3kdb</link>
      <guid>https://dev.to/jajera/configuring-aws-business-support-3kdb</guid>
      <description>&lt;h2&gt;
  
  
  Configuring AWS Business Support+
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/premiumsupport/plans/business-plus/" rel="noopener noreferrer"&gt;AWS Business Support+&lt;/a&gt; is AWS’s paid support tier that combines &lt;strong&gt;24/7 expert access&lt;/strong&gt;, &lt;strong&gt;AI-assisted troubleshooting&lt;/strong&gt;, &lt;strong&gt;Trusted Advisor&lt;/strong&gt; and health-oriented guidance, and &lt;strong&gt;targeted initial response&lt;/strong&gt; commitments for business-critical issues (see &lt;a href="https://aws.amazon.com/premiumsupport/plans/business-plus/" rel="noopener noreferrer"&gt;official plan page&lt;/a&gt; for current feature wording and pricing). This guide focuses on &lt;strong&gt;how to turn it on and who can do it&lt;/strong&gt;: console enrollment, &lt;strong&gt;organization-wide versus single-account&lt;/strong&gt; subscription, &lt;strong&gt;IAM&lt;/strong&gt; for the Support Plans console, and &lt;strong&gt;Organizations SCP&lt;/strong&gt; pitfalls when regions are restricted.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;strong&gt;&lt;a href="https://console.aws.amazon.com/support/plans/home" rel="noopener noreferrer"&gt;AWS Support Plans console&lt;/a&gt;&lt;/strong&gt; and upgrade from &lt;strong&gt;Basic&lt;/strong&gt; to &lt;strong&gt;Business Support+&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;organization-wide&lt;/strong&gt; (management account, Organizations all features) or &lt;strong&gt;account-only&lt;/strong&gt; enrollment&lt;/li&gt;
&lt;li&gt;Grant &lt;strong&gt;IAM&lt;/strong&gt; access to change plans (&lt;code&gt;supportplans:*&lt;/code&gt; or AWS managed policies) and fix &lt;strong&gt;SCP&lt;/strong&gt; denies if Support Plans fails in member accounts&lt;/li&gt;
&lt;li&gt;Know how to &lt;strong&gt;downgrade&lt;/strong&gt; (console path) and where to &lt;strong&gt;compare pricing&lt;/strong&gt; before you confirm&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Root user&lt;/strong&gt; or an IAM principal allowed to change support plans (see &lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/security-support-plans.html" rel="noopener noreferrer"&gt;Manage access to AWS Support Plans&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;organization-level&lt;/strong&gt; Business Support+: the account must be the &lt;strong&gt;Organizations management account&lt;/strong&gt;, with &lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_org_support-all-features.html" rel="noopener noreferrer"&gt;all features enabled&lt;/a&gt;&lt;/strong&gt; for the organization&lt;/li&gt;
&lt;li&gt;Billing in good standing; paid support has a &lt;strong&gt;minimum one-month&lt;/strong&gt; commitment (&lt;a href="https://aws.amazon.com/premiumsupport/faqs/" rel="noopener noreferrer"&gt;Support FAQs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Subscribe from the Support Plans console
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Open the console
&lt;/h4&gt;

&lt;p&gt;Sign in and go to &lt;a href="https://console.aws.amazon.com/support/plans/home" rel="noopener noreferrer"&gt;AWS Support Plans&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Optional but recommended before you subscribe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Compare all Support plans and features&lt;/strong&gt; to line up Business Support+ against other tiers&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Pricing calculator&lt;/strong&gt; (in the console) to estimate support charges from expected monthly AWS usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Upgrade from Basic to Business Support+
&lt;/h4&gt;

&lt;p&gt;Steps follow &lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/changing-support-plans.html" rel="noopener noreferrer"&gt;Changing AWS Support plans&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;AWS Business Support+&lt;/strong&gt; section, choose &lt;strong&gt;Get started&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose scope:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;My organization&lt;/strong&gt; — only if you use &lt;strong&gt;AWS Organizations&lt;/strong&gt; with &lt;strong&gt;all-feature mode&lt;/strong&gt;; only the &lt;strong&gt;management account&lt;/strong&gt; can enroll the whole org. New accounts created in the org are &lt;strong&gt;automatically&lt;/strong&gt; on Business Support+. In the console, &lt;strong&gt;My organization&lt;/strong&gt; is &lt;strong&gt;disabled&lt;/strong&gt; when it does not apply (for example, you are signed in to a &lt;strong&gt;member account&lt;/strong&gt;, Organizations is not in use, or &lt;strong&gt;all features&lt;/strong&gt; are not enabled for the organization)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My account&lt;/strong&gt; — subscribe &lt;strong&gt;this account&lt;/strong&gt; only&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Review plan details and pricing (&lt;a href="https://aws.amazon.com/premiumsupport/pricing/" rel="noopener noreferrer"&gt;AWS Support pricing&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Accept the subscription terms (checkbox)&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Confirm upgrade&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;After enrollment:&lt;/strong&gt; confirm the tier in &lt;strong&gt;&lt;a href="https://console.aws.amazon.com/support/home" rel="noopener noreferrer"&gt;AWS Support Center&lt;/a&gt;&lt;/strong&gt; (the console shows your current plan) and verify you can open a &lt;strong&gt;support case&lt;/strong&gt; with the severity options you expect.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. IAM: who may view or change the plan
&lt;/h3&gt;

&lt;p&gt;Users need &lt;code&gt;supportplans&lt;/code&gt; API permissions. Common actions (&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/security-support-plans.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;supportplans:GetSupportPlan&lt;/code&gt; — view current plan&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;supportplans:StartSupportPlanUpdate&lt;/code&gt; — start an upgrade or downgrade request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;supportplans:GetSupportPlanUpdateStatus&lt;/code&gt; — poll update status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS managed policies (names may evolve; confirm in IAM):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AWSSupportPlansFullAccess&lt;/code&gt;&lt;/strong&gt; — change plans&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AWSSupportPlansReadOnlyAccess&lt;/code&gt;&lt;/strong&gt; — view only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example &lt;strong&gt;read-only&lt;/strong&gt; custom policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"supportplans:Get*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"supportplans:List*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;strong&gt;full&lt;/strong&gt; access (delegate carefully):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"supportplans:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Organizations: SCPs and global services
&lt;/h3&gt;

&lt;p&gt;If member accounts see errors &lt;strong&gt;even with correct IAM&lt;/strong&gt;, an &lt;strong&gt;SCP&lt;/strong&gt; that denies by &lt;strong&gt;Region&lt;/strong&gt; can block &lt;strong&gt;Support Plans&lt;/strong&gt; because it is a &lt;strong&gt;global&lt;/strong&gt; console/API.&lt;/p&gt;

&lt;p&gt;Per &lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/security-support-plans.html" rel="noopener noreferrer"&gt;Manage access to AWS Support Plans&lt;/a&gt;, add &lt;strong&gt;&lt;code&gt;supportplans:*&lt;/code&gt;&lt;/strong&gt; to the &lt;strong&gt;&lt;code&gt;NotAction&lt;/code&gt;&lt;/strong&gt; list on any broad Region-deny SCP (exact structure depends on your org’s policy layout). If you use &lt;strong&gt;AWS Control Tower&lt;/strong&gt; Region deny controls, read AWS guidance on &lt;strong&gt;drift&lt;/strong&gt; before hand-editing SCPs, because repairs can revert custom exceptions.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Downgrades and higher tiers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Downgrade from Business Support+:&lt;/strong&gt; on &lt;a href="https://console.aws.amazon.com/support/plans/home" rel="noopener noreferrer"&gt;Manage Support Plans&lt;/a&gt;, use &lt;strong&gt;Review downgrade&lt;/strong&gt; in the &lt;strong&gt;Basic Support&lt;/strong&gt; section (&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/changing-support-plans.html" rel="noopener noreferrer"&gt;Changing AWS Support plans&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Support or Unified Operations:&lt;/strong&gt; use &lt;strong&gt;Contact sales&lt;/strong&gt; in the console; Enterprise downgrades go through your &lt;strong&gt;TAM&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account leaves the org&lt;/strong&gt; after org-level Business Support+: AWS documents that the account &lt;strong&gt;drops to Basic&lt;/strong&gt; support&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  7. Optional follow-on configuration
&lt;/h3&gt;

&lt;p&gt;These are not strictly “subscription” steps but are how teams &lt;strong&gt;use&lt;/strong&gt; paid support day to day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/aws-support-app-for-slack.html" rel="noopener noreferrer"&gt;AWS Support App in Slack&lt;/a&gt;&lt;/strong&gt; — create and update cases from Slack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/about-support-api.html" rel="noopener noreferrer"&gt;AWS Support API&lt;/a&gt;&lt;/strong&gt; — automate case operations (separate IAM/service permissions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusted Advisor&lt;/strong&gt; and &lt;strong&gt;AWS Health&lt;/strong&gt; — visible in console once the plan includes them; use &lt;a href="https://aws.amazon.com/premiumsupport/technology/trusted-advisor/" rel="noopener noreferrer"&gt;Trusted Advisor&lt;/a&gt; and &lt;a href="https://aws.amazon.com/premiumsupport/technology/aws-health/" rel="noopener noreferrer"&gt;AWS Health&lt;/a&gt; docs for check types and alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Promotional &lt;strong&gt;trial&lt;/strong&gt; or &lt;strong&gt;pricing&lt;/strong&gt; offers change over time; use the &lt;a href="https://aws.amazon.com/premiumsupport/plans/business-plus/" rel="noopener noreferrer"&gt;Business Support+ plan page&lt;/a&gt; and in-console &lt;strong&gt;offer&lt;/strong&gt; links for current eligibility and refund rules.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Summary: Copy-Paste
&lt;/h3&gt;

&lt;p&gt;Console entry points (sign in first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://console.aws.amazon.com/support/plans/home
https://console.aws.amazon.com/support/home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IAM: attach &lt;strong&gt;&lt;code&gt;AWSSupportPlansFullAccess&lt;/code&gt;&lt;/strong&gt; to a named role used only for billing/support changes, or merge the JSON examples in section 4 into your least-privilege model.&lt;/p&gt;

&lt;p&gt;Organizations: if Region-deny SCPs exist, ensure &lt;strong&gt;&lt;code&gt;supportplans:*&lt;/code&gt;&lt;/strong&gt; is excluded from the deny per AWS documentation.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Access Denied on Support Plans:&lt;/strong&gt; Attach &lt;strong&gt;&lt;code&gt;AWSSupportPlansFullAccess&lt;/code&gt;&lt;/strong&gt; (or equivalent &lt;code&gt;supportplans:*&lt;/code&gt;) to the role or user; confirm you are not using a &lt;strong&gt;member account&lt;/strong&gt; when only the &lt;strong&gt;management account&lt;/strong&gt; may enroll the org.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Member account cannot open the page:&lt;/strong&gt; Check &lt;strong&gt;SCP&lt;/strong&gt; Region denies and add &lt;strong&gt;&lt;code&gt;supportplans:*&lt;/code&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;code&gt;NotAction&lt;/code&gt;&lt;/strong&gt; as documented; verify &lt;strong&gt;Control Tower&lt;/strong&gt; drift if that platform manages SCPs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong scope after the fact:&lt;/strong&gt; Org-wide subscription is a &lt;strong&gt;management-account&lt;/strong&gt; decision; single-account subscription does not extend to siblings. Adjust scope only by following AWS &lt;strong&gt;change plan&lt;/strong&gt; / &lt;strong&gt;downgrade&lt;/strong&gt; flows and org enrollment rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Charges surprise you:&lt;/strong&gt; Revisit the console &lt;strong&gt;Pricing calculator&lt;/strong&gt; and &lt;a href="https://aws.amazon.com/premiumsupport/pricing/" rel="noopener noreferrer"&gt;Support pricing&lt;/a&gt;; support fees are &lt;strong&gt;separate&lt;/strong&gt; from service usage on the bill.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/changing-support-plans.html" rel="noopener noreferrer"&gt;Change AWS Support plans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/aws-support-plans.html" rel="noopener noreferrer"&gt;AWS Support plans (User Guide)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/security-support-plans.html" rel="noopener noreferrer"&gt;Manage access to AWS Support Plans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/awssupport/latest/user/managed-policies-aws-support-plans.html" rel="noopener noreferrer"&gt;AWS managed policies for AWS Support Plans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_org_support-all-features.html" rel="noopener noreferrer"&gt;Enabling all features for an organization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/premiumsupport/plans/business-plus/" rel="noopener noreferrer"&gt;AWS Business Support+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/premiumsupport/faqs/" rel="noopener noreferrer"&gt;AWS Support FAQs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>support</category>
      <category>iam</category>
      <category>organizations</category>
    </item>
    <item>
      <title>Greenfield EKS: Choosing Standard EKS vs EKS Auto Mode Without Legacy Baggage</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Tue, 07 Apr 2026 23:35:59 +0000</pubDate>
      <link>https://dev.to/jajera/greenfield-eks-choosing-standard-eks-vs-eks-auto-mode-without-legacy-baggage-39f3</link>
      <guid>https://dev.to/jajera/greenfield-eks-choosing-standard-eks-vs-eks-auto-mode-without-legacy-baggage-39f3</guid>
      <description>&lt;h2&gt;
  
  
  Greenfield EKS: Choosing Standard EKS vs EKS Auto Mode Without Legacy Baggage
&lt;/h2&gt;

&lt;p&gt;If you are standing up &lt;strong&gt;your first&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html" rel="noopener noreferrer"&gt;Amazon EKS&lt;/a&gt; cluster and you are &lt;strong&gt;not&lt;/strong&gt; dragging along years of Terraform modules, custom AMIs, or a mandated node strategy from another team, the choice between &lt;strong&gt;Standard EKS&lt;/strong&gt; (you own how nodes are provisioned and wired) and &lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/automode.html" rel="noopener noreferrer"&gt;EKS Auto Mode&lt;/a&gt;&lt;/strong&gt; (AWS runs more of that for you) is mostly about &lt;strong&gt;defaults&lt;/strong&gt;: speed and delegated operations versus transparency and fine-grained control. This article is a practical decision guide for that &lt;strong&gt;greenfield&lt;/strong&gt; scenario—what differs, how to think about &lt;strong&gt;cost&lt;/strong&gt; and &lt;strong&gt;maintenance&lt;/strong&gt;, and how to separate &lt;strong&gt;the EKS operating model&lt;/strong&gt; from &lt;strong&gt;optional add-ons&lt;/strong&gt; you install on top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k4027o7x1ulwq0tee4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k4027o7x1ulwq0tee4s.png" alt="Diagram of Amazon EKS: Kubernetes control plane managed by AWS and worker nodes running in your VPC" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html" rel="noopener noreferrer"&gt;What is Amazon EKS?&lt;/a&gt; (AWS Documentation).&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;This guide helps you decide, for a &lt;strong&gt;new&lt;/strong&gt; cluster with &lt;strong&gt;no legacy constraints&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What &lt;strong&gt;Standard EKS&lt;/strong&gt; and &lt;strong&gt;EKS Auto Mode&lt;/strong&gt; each optimize for in the first weeks and months&lt;/li&gt;
&lt;li&gt;How to compare &lt;strong&gt;cost&lt;/strong&gt; at a high level (control plane, compute, Auto Mode management fees, and people time)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who runs what&lt;/strong&gt; (nodes, scaling, ingress/LB), including an &lt;strong&gt;AWS-documented checklist&lt;/strong&gt; of what Auto Mode manages as built-in infrastructure&lt;/li&gt;
&lt;li&gt;A short &lt;strong&gt;rubric&lt;/strong&gt; for “default to Auto Mode” versus “start explicit with managed node groups”&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Familiarity with &lt;strong&gt;containers&lt;/strong&gt; and the idea of a &lt;strong&gt;Kubernetes control plane&lt;/strong&gt; versus &lt;strong&gt;worker nodes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Access to current &lt;strong&gt;&lt;a href="https://aws.amazon.com/eks/pricing" rel="noopener noreferrer"&gt;Amazon EKS pricing&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/automode.html" rel="noopener noreferrer"&gt;EKS Auto Mode documentation&lt;/a&gt;&lt;/strong&gt; for numbers and feature details that change over time&lt;/li&gt;
&lt;li&gt;No assumption that you already run &lt;strong&gt;Karpenter&lt;/strong&gt;, &lt;strong&gt;managed node groups&lt;/strong&gt;, or a corporate standard—this article assumes &lt;strong&gt;greenfield&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Name the two starting paths
&lt;/h3&gt;

&lt;p&gt;Same managed control plane; &lt;strong&gt;who owns the node story&lt;/strong&gt; is what splits the paths.&lt;/p&gt;

&lt;h4&gt;
  
  
  Side-by-side
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Standard EKS&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;EKS Auto Mode&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You choose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How nodes are created and scaled: &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html" rel="noopener noreferrer"&gt;managed node groups&lt;/a&gt;, self-managed nodes, or later &lt;a href="https://karpenter.sh/" rel="noopener noreferrer"&gt;Karpenter&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Less DIY wiring; AWS runs more of &lt;strong&gt;lifecycle + integration&lt;/strong&gt; (&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/automode.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mental model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“These are &lt;strong&gt;my&lt;/strong&gt; instances / ASGs, &lt;strong&gt;my&lt;/strong&gt; scaling and upgrade path”&lt;/td&gt;
&lt;td&gt;“&lt;strong&gt;AWS-shaped&lt;/strong&gt; automation; fewer knobs, less assembly”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;APIs you will see&lt;/strong&gt; (examples)&lt;/td&gt;
&lt;td&gt;EC2, MNG, launch templates, plus whatever provisioner you pick&lt;/td&gt;
&lt;td&gt;Platform-oriented CRDs such as &lt;code&gt;NodePool&lt;/code&gt; / &lt;code&gt;NodeClaim&lt;/code&gt;, &lt;code&gt;NodeClass&lt;/code&gt;, &lt;code&gt;CNINode&lt;/code&gt;, LB-related types—&lt;strong&gt;exact set&lt;/strong&gt; varies by version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Standard EKS — responsibility flow
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------------------+
| AWS: Kubernetes API           |  (managed control plane)
+-------------------------------+
              |
              v
+-------------------------------+
| You: pick node strategy       |
| MNG / self-managed / Karpenter|
+-------------------------------+
              |
              v
+-------------------------------+
| Workloads / Pods              |
+-------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  EKS Auto Mode — responsibility flow
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------------------+
| AWS: Kubernetes API           |  (managed control plane)
+-------------------------------+
              |
              v
+-------------------------------+
| AWS: node lifecycle +         |
| integrations (opinionated)    |
+-------------------------------+
              |
              v
+-------------------------------+
| Workloads / Pods              |
+-------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Same for both:&lt;/strong&gt; observability, backups, secrets, RBAC, network policy, ingress, and mesh are &lt;strong&gt;still yours&lt;/strong&gt;. Picking a mode ≠ production-ready.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4. Cost at a glance
&lt;/h3&gt;

&lt;p&gt;Pricing moves; always verify against the &lt;a href="https://aws.amazon.com/eks/pricing/" rel="noopener noreferrer"&gt;Amazon EKS pricing page&lt;/a&gt;. The figures below use &lt;strong&gt;US West (Oregon)&lt;/strong&gt; On-Demand rates at the time of writing and a &lt;strong&gt;small greenfield&lt;/strong&gt; scenario: &lt;strong&gt;one cluster, three worker nodes&lt;/strong&gt; (&lt;code&gt;m5a.xlarge&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Estimated monthly AWS bill
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Line item&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;Standard EKS&lt;/th&gt;
&lt;th&gt;Auto Mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Control plane&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.10 / cluster / hr&lt;/td&gt;
&lt;td&gt;~$73&lt;/td&gt;
&lt;td&gt;~$73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;EC2 instances&lt;/strong&gt; (3 x &lt;code&gt;m5a.xlarge&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;$0.172 / instance / hr&lt;/td&gt;
&lt;td&gt;~$377&lt;/td&gt;
&lt;td&gt;~$377&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auto Mode management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.02064 / instance / hr&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;~$45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS invoice total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$450&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$495&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Source for *&lt;/em&gt;$0.02064 / hr** (Auto Mode) and &lt;strong&gt;$0.172 / hr&lt;/strong&gt; (EC2) for &lt;code&gt;m5a.xlarge&lt;/code&gt;: AWS &lt;strong&gt;Example 4: EKS Auto Mode&lt;/strong&gt; on &lt;a href="https://aws.amazon.com/eks/pricing/" rel="noopener noreferrer"&gt;Amazon EKS pricing&lt;/a&gt; (US West Oregon, On-Demand). Auto Mode fees are &lt;strong&gt;per instance type&lt;/strong&gt;; use that page or the &lt;a href="https://calculator.aws/#/createCalculator/EKS" rel="noopener noreferrer"&gt;AWS Pricing Calculator for EKS&lt;/a&gt; for other shapes.*&lt;/p&gt;

&lt;p&gt;Auto Mode adds roughly &lt;strong&gt;10-12%&lt;/strong&gt; to the AWS bill in this scenario. The management fee is billed per-second (one-minute minimum) and applies regardless of EC2 purchase option (On-Demand, Reserved, Savings Plan, or Spot).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Watch out for extended support.&lt;/strong&gt; If you let a Kubernetes version drift past &lt;strong&gt;standard support&lt;/strong&gt; (14 months), the cluster fee jumps to &lt;strong&gt;$0.60 / hr (~$438 / month)&lt;/strong&gt;. Plan upgrades regardless of mode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  What the invoice does not show
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hidden cost&lt;/th&gt;
&lt;th&gt;Standard EKS&lt;/th&gt;
&lt;th&gt;Auto Mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Engineer time&lt;/strong&gt; building node automation, LB controller Helm charts, upgrade runbooks&lt;/td&gt;
&lt;td&gt;Higher -- you build and maintain the glue&lt;/td&gt;
&lt;td&gt;Lower -- AWS ships more of that glue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Incident cost&lt;/strong&gt; when nodes misbehave, AMIs drift, or scaling stalls&lt;/td&gt;
&lt;td&gt;Yours to debug end-to-end&lt;/td&gt;
&lt;td&gt;Shared with AWS; fewer levers but also fewer moving parts you wrote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Idle capacity&lt;/strong&gt; from over-provisioned groups or generous defaults&lt;/td&gt;
&lt;td&gt;Risk if you set scaling bounds loosely&lt;/td&gt;
&lt;td&gt;Risk if Auto Mode defaults are generous for your workload&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; the ~$45 / month management fee in this example is roughly &lt;strong&gt;one hour of a platform engineer's loaded cost&lt;/strong&gt;. If Auto Mode saves more than that in reduced toil per month, it pays for itself. If your team already has solid automation and rarely touches nodes, Standard keeps the invoice leaner.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  5. Who runs what—and what the first year feels like
&lt;/h3&gt;

&lt;p&gt;The choice shows up in &lt;strong&gt;division of labor&lt;/strong&gt;: who keeps &lt;strong&gt;nodes&lt;/strong&gt;, &lt;strong&gt;scaling&lt;/strong&gt;, and &lt;strong&gt;traffic into the cluster&lt;/strong&gt; healthy. That is what fills your calendar in months &lt;strong&gt;six through twelve&lt;/strong&gt;—upgrade planning and Helm charts on one side, AWS platform changes and support cases on the other—not an abstract “mode” badge.&lt;/p&gt;

&lt;h4&gt;
  
  
  Where the work lands
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Standard EKS (typical greenfield)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;EKS Auto Mode&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nodes and scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You pick the mechanism—&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html" rel="noopener noreferrer"&gt;managed node groups&lt;/a&gt;, self-managed nodes, or &lt;a href="https://karpenter.sh/" rel="noopener noreferrer"&gt;Karpenter&lt;/a&gt;—and you own &lt;strong&gt;upgrades&lt;/strong&gt;, &lt;strong&gt;behavior&lt;/strong&gt;, and &lt;strong&gt;capacity tuning&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;AWS delivers a more &lt;strong&gt;integrated&lt;/strong&gt; node and scaling experience; you align with &lt;strong&gt;Kubernetes objects and practices AWS documents for Auto Mode&lt;/strong&gt; instead of assembling the same stack yourself (&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/automode.html" rel="noopener noreferrer"&gt;Auto Mode&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ingress and load balancers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Teams usually &lt;strong&gt;install and operate&lt;/strong&gt; something like &lt;strong&gt;AWS Load Balancer Controller&lt;/strong&gt;—chart upgrades, compatibility with new cluster versions, incidents when labels or annotations drift&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;More of that integration is AWS-operated&lt;/strong&gt; for Auto Mode, so you typically spend &lt;strong&gt;less&lt;/strong&gt; time babysitting that slice—still read &lt;strong&gt;AWS release notes&lt;/strong&gt; when the platform changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Standard EKS in practice
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity and skill-building:&lt;/strong&gt; Obvious ownership (“we chose MNG / Karpenter / …”), strong &lt;strong&gt;learning&lt;/strong&gt; for engineers who will live in AWS and Kubernetes, and a concrete story when &lt;strong&gt;auditors&lt;/strong&gt; ask what creates instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recurring toil:&lt;/strong&gt; &lt;strong&gt;Upgrade choreography&lt;/strong&gt; across the control plane version, &lt;strong&gt;node AMIs&lt;/strong&gt;, and &lt;strong&gt;add-on compatibility&lt;/strong&gt;; deliberate choices for &lt;strong&gt;scaling bounds&lt;/strong&gt; and instance families; ongoing ownership of &lt;strong&gt;ingress/LB&lt;/strong&gt; tooling unless you outsource it elsewhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  EKS Auto Mode in practice
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Less assembly, faster baseline:&lt;/strong&gt; Shorter path to a &lt;strong&gt;working data plane&lt;/strong&gt;, fewer Terraform or CloudFormation resources tied to &lt;strong&gt;node plumbing&lt;/strong&gt;, and less day-to-day ownership of the &lt;strong&gt;LB integration&lt;/strong&gt; layer described above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tradeoff:&lt;/strong&gt; &lt;strong&gt;Fewer levers&lt;/strong&gt; when behavior surprises you; success depends on &lt;strong&gt;solid observability&lt;/strong&gt; (logs, metrics, tracing) and comfort escalating or adapting when &lt;strong&gt;AWS-owned&lt;/strong&gt; behavior changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  What Auto Mode treats as managed infrastructure (AWS checklist)
&lt;/h4&gt;

&lt;p&gt;AWS describes these as &lt;strong&gt;built-in cluster capabilities&lt;/strong&gt;, not as separate EKS console add-ons you install and version yourself. This is the high-level list from &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/automode.html" rel="noopener noreferrer"&gt;Automate cluster infrastructure with EKS Auto Mode&lt;/a&gt; and the &lt;strong&gt;Automated components&lt;/strong&gt; section there—use the docs for the latest detail and limits.&lt;/p&gt;

&lt;h5&gt;
  
  
  Compute and nodes
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Data-plane &lt;strong&gt;EC2 instances&lt;/strong&gt; (Bottlerocket-based variants): AMI selection, locked-down OS (SELinux enforcing, read-only root), &lt;strong&gt;no direct SSH or SSM&lt;/strong&gt; to nodes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security and lifecycle:&lt;/strong&gt; patching and upgrades with minimal disruption; &lt;strong&gt;maximum node lifetime&lt;/strong&gt; (default up to &lt;strong&gt;21 days&lt;/strong&gt;) so nodes are replaced regularly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accelerated workloads:&lt;/strong&gt; GPU-related kernel drivers and plugins (for example &lt;strong&gt;NVIDIA&lt;/strong&gt; and &lt;strong&gt;AWS Neuron&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot:&lt;/strong&gt; handling of &lt;strong&gt;Spot interruption notices&lt;/strong&gt; and EC2 instance health signals&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Scaling
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Karpenter&lt;/strong&gt;-style autoscaling: reacts to unschedulable Pods, adds capacity, and removes or consolidates nodes when demand drops&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Load balancing
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Elastic Load Balancing&lt;/strong&gt; tied to Kubernetes &lt;strong&gt;Service&lt;/strong&gt; and &lt;strong&gt;Ingress&lt;/strong&gt; objects: provisions and manages &lt;strong&gt;ALB&lt;/strong&gt; and &lt;strong&gt;NLB&lt;/strong&gt; resources and scales them with cluster demand&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Networking
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pod and Service networking&lt;/strong&gt;, including &lt;strong&gt;IPv4/IPv6&lt;/strong&gt; and use of &lt;strong&gt;secondary CIDRs&lt;/strong&gt; where needed for Pod IP space&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network policy&lt;/strong&gt; enforcement for Pods&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster DNS&lt;/strong&gt; (local DNS for the cluster)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Storage
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EBS CSI&lt;/strong&gt;-class block storage as a managed capability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ephemeral storage&lt;/strong&gt; defaults on nodes (volume type, size, encryption, and cleanup behavior on termination—per AWS documentation)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Identity
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EKS Pod Identity:&lt;/strong&gt; you &lt;strong&gt;do not&lt;/strong&gt; install the &lt;strong&gt;EKS Pod Identity Agent&lt;/strong&gt; yourself on Auto Mode clusters (AWS documents that it is not required in this model)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Neither mode delivers “production in a box.”&lt;/strong&gt; Metrics, secret rotation, mesh, policy engines, backups, and business-specific operators remain &lt;strong&gt;your&lt;/strong&gt; software lifecycle unless you adopt separate managed services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid the “busy cluster” trap.&lt;/strong&gt; A Standard environment can &lt;em&gt;look&lt;/em&gt; heavier because it has &lt;strong&gt;more add-ons&lt;/strong&gt; (monitoring, GitOps, security tools). That says what &lt;strong&gt;you installed&lt;/strong&gt;, not that &lt;strong&gt;Standard&lt;/strong&gt; is inherently more capable than &lt;strong&gt;Auto Mode&lt;/strong&gt;. Judge the choice on &lt;strong&gt;who operates nodes and built-in integrations&lt;/strong&gt;, not on how crowded the UI feels.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Decision rubric (greenfield, no baggage)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lean toward EKS Auto Mode&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The team is &lt;strong&gt;small&lt;/strong&gt; and the priority is &lt;strong&gt;shipping&lt;/strong&gt; a standard container platform quickly&lt;/li&gt;
&lt;li&gt;Workloads are &lt;strong&gt;typical&lt;/strong&gt; Linux containers without exotic kernel, sysctl, or custom AMI requirements &lt;strong&gt;today&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You are comfortable adopting &lt;strong&gt;AWS-shaped&lt;/strong&gt; APIs for nodes and integrations for the next phase of growth&lt;/li&gt;
&lt;li&gt;You prefer &lt;strong&gt;fewer&lt;/strong&gt; moving parts &lt;strong&gt;you&lt;/strong&gt; must patch and tune in the first year&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lean toward Standard EKS (often with managed node groups first)&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want &lt;strong&gt;maximum transparency&lt;/strong&gt; into every layer for &lt;strong&gt;training&lt;/strong&gt;, &lt;strong&gt;compliance groundwork&lt;/strong&gt;, or &lt;strong&gt;multi-cloud&lt;/strong&gt; discipline&lt;/li&gt;
&lt;li&gt;You already know you need &lt;strong&gt;specific&lt;/strong&gt; instance families, purchase options, or &lt;strong&gt;strict&lt;/strong&gt; cost caps encoded &lt;strong&gt;explicitly&lt;/strong&gt; from day one&lt;/li&gt;
&lt;li&gt;You expect to &lt;strong&gt;standardize&lt;/strong&gt; on an in-house or community &lt;strong&gt;node provisioning&lt;/strong&gt; story (for example Karpenter you fully control) and want to &lt;strong&gt;learn&lt;/strong&gt; that model without an additional management layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Default suggestion for a true greenfield product team:&lt;/strong&gt; if your main risk is &lt;strong&gt;slow delivery&lt;/strong&gt; and &lt;strong&gt;operational overload&lt;/strong&gt;, &lt;strong&gt;EKS Auto Mode&lt;/strong&gt; is often the better &lt;strong&gt;starting&lt;/strong&gt; default; if your main risk is &lt;strong&gt;understanding and owning&lt;/strong&gt; every dependency for regulatory or career reasons, &lt;strong&gt;Standard EKS&lt;/strong&gt; with &lt;strong&gt;managed node groups&lt;/strong&gt; is a clean teaching path. You can revisit the choice after the team has real production traffic and metrics.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Troubleshooting: common misconceptions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;“Auto Mode is more Kubernetes.”&lt;/strong&gt; It is &lt;strong&gt;more AWS-managed automation&lt;/strong&gt; exposed through Kubernetes APIs, not a superset of every optional addon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“Standard is cheaper.”&lt;/strong&gt; &lt;strong&gt;Invoice lines&lt;/strong&gt; can be lower; &lt;strong&gt;total cost&lt;/strong&gt; may not be once you count &lt;strong&gt;engineering time&lt;/strong&gt; and &lt;strong&gt;incidents&lt;/strong&gt; for a small team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“We picked a mode, so we are secure and observable.”&lt;/strong&gt; &lt;strong&gt;RBAC&lt;/strong&gt;, &lt;strong&gt;network policy&lt;/strong&gt;, &lt;strong&gt;secrets&lt;/strong&gt;, &lt;strong&gt;auditing&lt;/strong&gt;, and &lt;strong&gt;monitoring&lt;/strong&gt; are still &lt;strong&gt;your&lt;/strong&gt; design choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“Our Standard cluster has more moving parts, so it must be better.”&lt;/strong&gt; Often that is &lt;strong&gt;more optional software you added&lt;/strong&gt;—not proof that Standard beats Auto Mode; see &lt;strong&gt;section 5&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html" rel="noopener noreferrer"&gt;What is Amazon EKS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/eks/pricing/" rel="noopener noreferrer"&gt;Amazon EKS pricing&lt;/a&gt; (see &lt;strong&gt;Example 4: EKS Auto Mode&lt;/strong&gt; for per-instance-type Auto Mode fees used in section 4)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/automode.html" rel="noopener noreferrer"&gt;EKS Auto Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/auto-reference.html" rel="noopener noreferrer"&gt;Learn how EKS Auto Mode works&lt;/a&gt; (deeper component topics)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/eks/resources/best-practices/" rel="noopener noreferrer"&gt;Amazon EKS best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html" rel="noopener noreferrer"&gt;Managed node groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://karpenter.sh/" rel="noopener noreferrer"&gt;Karpenter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>eks</category>
      <category>aws</category>
      <category>kubernetes</category>
      <category>automode</category>
    </item>
    <item>
      <title>Argo CD and AWS CodeConnections: The Upside, the Redeploy Pain, and How I Fixed It</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sat, 28 Mar 2026 10:46:16 +0000</pubDate>
      <link>https://dev.to/jajera/argo-cd-and-aws-codeconnections-the-upside-the-redeploy-pain-and-how-i-fixed-it-2k1m</link>
      <guid>https://dev.to/jajera/argo-cd-and-aws-codeconnections-the-upside-the-redeploy-pain-and-how-i-fixed-it-2k1m</guid>
      <description>&lt;h2&gt;
  
  
  Argo CD and AWS CodeConnections: The Upside, the Redeploy Pain, and How I Fixed It
&lt;/h2&gt;

&lt;p&gt;I run &lt;a href="https://argo-cd.readthedocs.io/" rel="noopener noreferrer"&gt;Argo CD&lt;/a&gt; on &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html" rel="noopener noreferrer"&gt;Amazon EKS&lt;/a&gt; using the managed &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argo-cd.html" rel="noopener noreferrer"&gt;Argo CD capability&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/codeconnections/latest/userguide/welcome.html" rel="noopener noreferrer"&gt;AWS CodeConnections&lt;/a&gt; for Git. CodeConnections has been a clear win for day-to-day operations. Then I had to &lt;strong&gt;recreate&lt;/strong&gt; the connection (new resource, new identity in the URL). Every Application went to &lt;strong&gt;Sync: Unknown&lt;/strong&gt; until I updated URLs in &lt;strong&gt;two&lt;/strong&gt; places—Git &lt;strong&gt;and&lt;/strong&gt; the live cluster—and fixed &lt;strong&gt;ApplicationSets&lt;/strong&gt; so they stopped writing the old URL back. This article leads with &lt;strong&gt;why I still choose CodeConnections&lt;/strong&gt;, then &lt;strong&gt;what breaks on redeploy&lt;/strong&gt;, then &lt;strong&gt;what I did&lt;/strong&gt; when it inevitably happened, in that order.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Why CodeConnections is worth it for Argo CD on EKS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No SSH keys or personal tokens in the cluster.&lt;/strong&gt; Argo pulls Git using IAM: the capability role is allowed to use the connection (&lt;code&gt;UseConnection&lt;/code&gt;, &lt;code&gt;GetConnection&lt;/code&gt;). You are not copying PATs into Secrets or rotating leaked keys because someone printed &lt;code&gt;kubectl get secret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One connection, many repos.&lt;/strong&gt; The HTTPS URL includes your account, region, a &lt;strong&gt;connection UUID&lt;/strong&gt;, and then &lt;code&gt;owner/repo&lt;/code&gt;. Same connection, different path segment for each repository. Setup details and Terraform patterns are in &lt;a href="https://dev.to/jajera/argo-cd-on-eks-git-repo-access-with-aws-codeconnections-and-terraform-3ejl"&gt;Argo CD on EKS: Git repo access with AWS CodeConnections and Terraform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fits how enterprises already govern access.&lt;/strong&gt; Connections are AWS resources; approval and auditing live next to the rest of your cloud controls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That does not mean zero tradeoffs.&lt;/strong&gt; Managed Argo CD often applies &lt;strong&gt;one&lt;/strong&gt; Git credential broadly (for example every &lt;code&gt;github.com&lt;/code&gt; fetch through Kustomize can inherit it). If that bites you, vendoring or URL strategy fixes it—see &lt;a href="https://dev.to/jajera/why-your-kustomize-remote-bases-break-on-managed-argo-cd-and-how-to-fix-it-26i6"&gt;Why Your Kustomize Remote Bases Break on Managed Argo CD (and How to Fix It)&lt;/a&gt;. The tradeoff this article focuses on is different: &lt;strong&gt;replacing&lt;/strong&gt; the connection.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. What actually hurts when you update or redeploy the connection
&lt;/h3&gt;

&lt;p&gt;The Git URL Argo uses is not abstract. It embeds a &lt;strong&gt;connection UUID&lt;/strong&gt; in the path. &lt;strong&gt;A new connection is a new UUID.&lt;/strong&gt; Anything that still points at the old path keeps asking AWS to authorize the wrong resource, so repo fetch fails and sync never reconciles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pain point one — Git only is not enough.&lt;/strong&gt; Your GitOps repo is the source of truth, but Kubernetes already has &lt;code&gt;Application&lt;/code&gt; and &lt;code&gt;ApplicationSet&lt;/code&gt; objects applied &lt;strong&gt;yesterday&lt;/strong&gt;. Their &lt;code&gt;spec.source.repoURL&lt;/code&gt; (and generator URLs on sets) stay on the old string until something updates them. Pushing Git does not retroactively patch those CRs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pain point two — ApplicationSets fight you.&lt;/strong&gt; Many sets declare &lt;code&gt;repoURL&lt;/code&gt; twice: on the &lt;strong&gt;git&lt;/strong&gt; generator and again on the &lt;strong&gt;template&lt;/strong&gt;. If you patch child Applications but leave the set on the old URL, the controller reconciles and &lt;strong&gt;puts the old URL back&lt;/strong&gt; on the apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pain point three — Terraform layout.&lt;/strong&gt; If CodeConnections and the EKS cluster share one tangled module and state, &lt;strong&gt;recreating&lt;/strong&gt; the connection can feel like you are planning half the platform when you only wanted a new Git pipe. I now prefer the connection (and its IAM attachment) in something &lt;strong&gt;standalone&lt;/strong&gt;, with outputs the cluster stack consumes—so the next rotation is a smaller blast radius.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this is not.&lt;/strong&gt; If Argo shows &lt;strong&gt;forbidden&lt;/strong&gt; listing some API group (for example heavy CRD surfaces from controllers like ACK), that is usually &lt;strong&gt;cluster RBAC / EKS access policies&lt;/strong&gt; for the Argo identity, not the CodeConnections URL. Fix that on its own; do not confuse it with a UUID swap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not mass-delete Applications&lt;/strong&gt; to “fix” a bad URL. Workloads may still be fine; you risk prune tearing down real resources. Fix the URLs.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; against the cluster, with permission to read and patch &lt;code&gt;applications&lt;/code&gt; and &lt;code&gt;applicationsets&lt;/code&gt; in the Argo CD namespace (below I use &lt;code&gt;argocd&lt;/code&gt;, the usual default)&lt;/li&gt;
&lt;li&gt;Rights to &lt;strong&gt;commit and push&lt;/strong&gt; every Git repo that hardcodes the CodeConnections URL&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;new&lt;/strong&gt; clone URL or at least the new UUID from the AWS Console or Terraform output&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. If it happens to you: what worked for me
&lt;/h3&gt;

&lt;p&gt;These steps assume you already know the &lt;strong&gt;old&lt;/strong&gt; and &lt;strong&gt;new&lt;/strong&gt; connection UUID (search your shell history, Terraform state, or an old Application YAML). The host pattern is documented in the CodeConnections and EKS guides linked at the end.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step A — Fix Git first, everywhere
&lt;/h4&gt;

&lt;p&gt;Search across &lt;strong&gt;all&lt;/strong&gt; repos that participate in GitOps—not only the “main” infra repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rg &lt;span class="s1"&gt;'codeconnections\.'&lt;/span&gt; &lt;span class="nt"&gt;--glob&lt;/span&gt; &lt;span class="s1"&gt;'*.yaml'&lt;/span&gt; &lt;span class="nt"&gt;--glob&lt;/span&gt; &lt;span class="s1"&gt;'*.yml'&lt;/span&gt; &lt;span class="nt"&gt;--glob&lt;/span&gt; &lt;span class="s1"&gt;'*.tf'&lt;/span&gt; &lt;span class="nt"&gt;--glob&lt;/span&gt; &lt;span class="s1"&gt;'*.md'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update bootstrap &lt;code&gt;Application&lt;/code&gt; manifests, every &lt;code&gt;ApplicationSet&lt;/code&gt; &lt;strong&gt;generator&lt;/strong&gt; and &lt;strong&gt;template&lt;/strong&gt; &lt;code&gt;repoURL&lt;/code&gt;, any child &lt;code&gt;Application&lt;/code&gt; checked in with a literal URL, and docs or scripts that build repository secrets. Commit and push.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step B — Patch Applications in the cluster
&lt;/h4&gt;

&lt;p&gt;Still in a broken state, the cluster cannot always sync from Git, so you patch live objects once. Set shell variables to your real values (namespace if not &lt;code&gt;argocd&lt;/code&gt;, old UUID, new UUID):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;argocd
&lt;span class="nv"&gt;OLD_UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
&lt;span class="nv"&gt;NEW_UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ffffffff-eeee-dddd-cccc-bbbbbbbbbbbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List apps whose single &lt;code&gt;spec.source.repoURL&lt;/code&gt; still contains the old UUID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get applications &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; u &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OLD_UUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'.items[] | select(.spec.source.repoURL // "" | contains($u)) | .metadata.name'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each name, the safest approach is to take the existing URL from the object and swap the UUID in the shell, then merge-patch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-app
&lt;span class="nv"&gt;oldurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get application &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.source.repoURL}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;newurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;oldurl&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;$OLD_UUID&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$NEW_UUID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
kubectl patch application &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; merge &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;spec&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;source&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;repoURL&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$newurl&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use &lt;strong&gt;&lt;code&gt;spec.sources&lt;/code&gt;&lt;/strong&gt; (multi-source), repeat the idea per entry that points at CodeConnections.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step C — Patch ApplicationSets (do not skip this)
&lt;/h4&gt;

&lt;p&gt;Confirm the old UUID still appears on &lt;strong&gt;spec&lt;/strong&gt; (ignore &lt;strong&gt;status&lt;/strong&gt; for a moment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get applicationsets &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; yaml | rg &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OLD_UUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To replace the UUID everywhere under each set’s JSON (review before you run this in production—I exported one set first and eyeballed it):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;name &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;kubectl get applicationsets &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; u &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OLD_UUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'.items[] | select(.. | strings? | contains($u)) | .metadata.name'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;kubectl get applicationset &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | &lt;span class="se"&gt;\&lt;/span&gt;
    jq &lt;span class="nt"&gt;--arg&lt;/span&gt; o &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OLD_UUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NEW_UUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s1"&gt;'del(.status) | walk(if type == "string" then gsub($o; $n) else . end)'&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
    kubectl replace &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;walk&lt;/code&gt; replaces &lt;strong&gt;every&lt;/strong&gt; occurrence of the old UUID string in that JSON. Pick a UUID substring unique to the connection so you do not hit unrelated fields.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step D — Refresh and converge
&lt;/h4&gt;

&lt;p&gt;Hard refresh apps in the UI or CLI, then let GitOps catch up. If Git still cannot be fetched until &lt;strong&gt;one&lt;/strong&gt; app is fixed, patch your &lt;strong&gt;bootstrap&lt;/strong&gt; Application (the one that applies the rest of the tree) to the new URL first, then repeat the rest—classic chicken-and-egg.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Troubleshooting
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Application stuck deleting
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch application my-app &lt;span class="nt"&gt;-n&lt;/span&gt; argocd &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'{"metadata":{"finalizers":null}}'&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  I deleted an app and it came back
&lt;/h4&gt;

&lt;p&gt;An &lt;strong&gt;ApplicationSet&lt;/strong&gt; owns it (&lt;code&gt;ownerReferences&lt;/code&gt;). Fix the set and Git; deleting the app alone will not stick.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/codeconnections/latest/userguide/welcome.html" rel="noopener noreferrer"&gt;AWS CodeConnections User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argo-cd.html" rel="noopener noreferrer"&gt;Amazon EKS: Argo CD capability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/application-specification/" rel="noopener noreferrer"&gt;Argo CD – Application spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/" rel="noopener noreferrer"&gt;Argo CD – ApplicationSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/jajera/argo-cd-on-eks-git-repo-access-with-aws-codeconnections-and-terraform-3ejl"&gt;Argo CD on EKS: Git repo access with AWS CodeConnections and Terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/jajera/why-your-kustomize-remote-bases-break-on-managed-argo-cd-and-how-to-fix-it-26i6"&gt;Why Your Kustomize Remote Bases Break on Managed Argo CD (and How to Fix It)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>argocd</category>
      <category>codeconnections</category>
      <category>eks</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Host a Static Site on EC2 with Terraform (VPC, Optional ALB)</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sat, 28 Mar 2026 08:54:20 +0000</pubDate>
      <link>https://dev.to/jajera/host-a-static-site-on-ec2-with-terraform-vpc-optional-alb-1ba9</link>
      <guid>https://dev.to/jajera/host-a-static-site-on-ec2-with-terraform-vpc-optional-alb-1ba9</guid>
      <description>&lt;h2&gt;
  
  
  Host a Static Site on EC2 with Terraform (VPC, Optional ALB, Session Manager)
&lt;/h2&gt;

&lt;p&gt;For static sites, &lt;strong&gt;S3 + CloudFront&lt;/strong&gt; is usually the better default. This post points at a small Terraform demo and pulls a few excerpts from &lt;strong&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;iam.tf&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;code&gt;user_data.tftpl&lt;/code&gt;&lt;/strong&gt;. Full layout: &lt;a href="https://github.com/jdevto/tf-aws-ec2-static-demo" rel="noopener noreferrer"&gt;tf-aws-ec2-static-demo&lt;/a&gt; (local path &lt;code&gt;~/workspace/jdevto/tf-aws-ec2-static-demo&lt;/code&gt; if you keep it beside this blog repo). &lt;strong&gt;S3 + CloudFront&lt;/strong&gt; with Terraform: &lt;a href="https://github.com/jdevto/blog/blob/main/articles/art0018.md" rel="noopener noreferrer"&gt;art0018&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;The demo provisions a VPC, &lt;strong&gt;nginx&lt;/strong&gt; on &lt;strong&gt;Amazon Linux 2023&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/strong&gt; (AZ + private IP from &lt;strong&gt;IMDSv2&lt;/strong&gt;), and &lt;strong&gt;&lt;code&gt;robots.txt&lt;/code&gt;&lt;/strong&gt;. &lt;strong&gt;&lt;code&gt;use_alb=false&lt;/code&gt; (default):&lt;/strong&gt; one instance in one &lt;strong&gt;public&lt;/strong&gt; subnet; clients hit &lt;strong&gt;:80&lt;/strong&gt; on the instance public IP (CIDR from &lt;strong&gt;&lt;code&gt;allowed_http_cidr&lt;/code&gt;&lt;/strong&gt;). &lt;strong&gt;&lt;code&gt;use_alb=true&lt;/code&gt;:&lt;/strong&gt; &lt;strong&gt;internet ALB&lt;/strong&gt; across &lt;strong&gt;&lt;code&gt;az_count&lt;/code&gt; ≥ 2&lt;/strong&gt; public subnets; &lt;strong&gt;&lt;code&gt;az_count&lt;/code&gt;&lt;/strong&gt; instances in &lt;strong&gt;private&lt;/strong&gt; subnets (one per AZ), &lt;strong&gt;NAT&lt;/strong&gt; for egress, no instance public IP; instances register to one target group with &lt;strong&gt;HTTP /&lt;/strong&gt; health check expecting &lt;strong&gt;200&lt;/strong&gt;; instance SG allows &lt;strong&gt;:80&lt;/strong&gt; from the &lt;strong&gt;ALB&lt;/strong&gt; SG and from the &lt;strong&gt;VPC CIDR&lt;/strong&gt;. &lt;strong&gt;&lt;code&gt;enable_ssm=true&lt;/code&gt; (default):&lt;/strong&gt; &lt;strong&gt;Session Manager&lt;/strong&gt; with &lt;strong&gt;AmazonSSMManagedInstanceCore&lt;/strong&gt;—no SSH in the template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_count&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;az_count&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;instance_count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;az_count&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"az_count"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="nx"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;condition&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;az_count&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;az_count&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;az_count&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;error_message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"az_count must be between 1 and 6, and at least 2 when use_alb is true (ALB requirement)."&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why EC2?
&lt;/h3&gt;

&lt;p&gt;Learning stack (Terraform + VPC + optional ELB), policy that prefers VPC-hosted sites, temporary lift-and-shift, or a box that might grow non-static behavior later. None of that makes EC2 the default for a &lt;strong&gt;pure&lt;/strong&gt; static site.&lt;/p&gt;

&lt;h3&gt;
  
  
  VPC
&lt;/h3&gt;

&lt;p&gt;Every instance is in a &lt;strong&gt;VPC&lt;/strong&gt; and a &lt;strong&gt;subnet&lt;/strong&gt; (&lt;a href="https://aws.amazon.com/ec2/faqs/#ec2-classic" rel="noopener noreferrer"&gt;EC2-Classic&lt;/a&gt; is gone for new accounts). The demo creates its own VPC—public subnets always; &lt;strong&gt;private subnets + NAT&lt;/strong&gt; when &lt;strong&gt;&lt;code&gt;use_alb=true&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use_alb = false
  +----------+   :80 (public IP)   +----------------+
  | Clients  | ------------------&amp;gt; | EC2 (nginx)    |
  +----------+                     +----------------+

use_alb = true
  +----------+   :80   +-----+   :80   +----------------+
  | Clients  | ------&amp;gt; | ALB | ------&amp;gt; | EC2 × az_count |
  +----------+         +-----+         | (private)      |
                                      +----------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NAT&lt;/strong&gt; is billed when the ALB path is on. Repeated &lt;strong&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt; to the ALB can show different &lt;strong&gt;AZ / private IP&lt;/strong&gt; in &lt;strong&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/strong&gt; as backends rotate. &lt;strong&gt;&lt;code&gt;user_data&lt;/code&gt;&lt;/strong&gt; fills those fields via &lt;strong&gt;IMDSv2&lt;/strong&gt; after &lt;strong&gt;nginx&lt;/strong&gt; is up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;IMDS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; PUT &lt;span class="s2"&gt;"http://169.254.169.254/latest/api/token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-aws-ec2-metadata-token-ttl-seconds: 21600"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;PRIVATE_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-aws-ec2-metadata-token: &lt;/span&gt;&lt;span class="nv"&gt;$IMDS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"http://169.254.169.254/latest/meta-data/local-ipv4"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;AZ&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-aws-ec2-metadata-token: &lt;/span&gt;&lt;span class="nv"&gt;$IMDS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"http://169.254.169.254/latest/meta-data/placement/availability-zone"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.tf&lt;/code&gt; — placement and bootstrap:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"web"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_count&lt;/span&gt;

  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_security_group_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/user_data.tftpl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;enable_ssm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enable_ssm&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;user_data_replace_on_change&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;iam_instance_profile&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enable_ssm&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_instance_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.tf&lt;/code&gt; — instance ingress (ALB on) and target group health check:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"ingress"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP from ALB security group (forwarded client traffic)"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;security_groups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"ingress"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP from VPC for ALB health checks and internal probes"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_block&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lb_target_group"&lt;/span&gt; &lt;span class="s2"&gt;"web"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use_alb&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="nx"&gt;port&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
  &lt;span class="nx"&gt;protocol_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP1"&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="nx"&gt;health_check&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;enabled&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
    &lt;span class="nx"&gt;port&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"traffic-port"&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;
    &lt;span class="nx"&gt;matcher&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt;
    &lt;span class="nx"&gt;interval&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="nx"&gt;healthy_threshold&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;unhealthy_threshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Session Manager
&lt;/h3&gt;

&lt;p&gt;Agent + &lt;strong&gt;AmazonSSMManagedInstanceCore&lt;/strong&gt;; &lt;strong&gt;&lt;code&gt;user_data.tftpl&lt;/code&gt;&lt;/strong&gt; via &lt;strong&gt;&lt;code&gt;templatefile&lt;/code&gt;&lt;/strong&gt; so &lt;strong&gt;&lt;code&gt;#!/bin/bash&lt;/code&gt;&lt;/strong&gt; is at column 0 (indented &lt;strong&gt;&lt;code&gt;heredoc&lt;/code&gt;&lt;/strong&gt; in Terraform often breaks the shebang). With &lt;strong&gt;&lt;code&gt;enable_ssm&lt;/code&gt;&lt;/strong&gt;, the template pulls the &lt;strong&gt;SSM Agent RPM from S3&lt;/strong&gt; and starts the service. Use the AMI’s &lt;strong&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt;—do not &lt;strong&gt;&lt;code&gt;dnf install curl&lt;/code&gt;&lt;/strong&gt; on AL2023 (conflicts with &lt;strong&gt;&lt;code&gt;curl-minimal&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;set -e&lt;/code&gt;&lt;/strong&gt; aborts before &lt;strong&gt;nginx&lt;/strong&gt;). Egress: &lt;strong&gt;NAT&lt;/strong&gt; or &lt;strong&gt;SSM VPC endpoints&lt;/strong&gt;. Docs: &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/agent-install-al2.html" rel="noopener noreferrer"&gt;agent install&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-status-and-restart.html" rel="noopener noreferrer"&gt;status&lt;/a&gt;. Your principal needs &lt;strong&gt;&lt;code&gt;ssm:StartSession&lt;/code&gt;&lt;/strong&gt;; &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html" rel="noopener noreferrer"&gt;Session Manager plugin&lt;/a&gt; for CLI. After apply, wait for &lt;strong&gt;Online&lt;/strong&gt; in Fleet Manager; with &lt;strong&gt;&lt;code&gt;use_alb=true&lt;/code&gt;&lt;/strong&gt;, use &lt;strong&gt;&lt;code&gt;instance_ids&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;ssm_start_session_command&lt;/code&gt;&lt;/strong&gt; (first instance). &lt;strong&gt;&lt;code&gt;%{ if enable_ssm ~}&lt;/code&gt;&lt;/strong&gt; … &lt;strong&gt;&lt;code&gt;%{ endif ~}&lt;/code&gt;&lt;/strong&gt; wraps the SSM block in the template.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;iam.tf&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"ssm_core"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enable_ssm&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;user_data.tftpl&lt;/code&gt; (SSM path):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Column-0 shebang required: indented Terraform heredocs break #!/bin/bash and cloud-init may skip the script.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eux&lt;/span&gt;
&lt;span class="c"&gt;# Do not `dnf install curl` here: AL2023 ships curl-minimal; installing full curl conflicts and aborts the whole script under set -e.&lt;/span&gt;
&lt;span class="nv"&gt;SSM_RPM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in
  &lt;/span&gt;x86_64&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;SSM_RPM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  aarch64&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;SSM_RPM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_arm64/amazon-ssm-agent.rpm"&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Unsupported arch for SSM agent RPM"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1 &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;esac&lt;/span&gt;
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/amazon-ssm-agent.rpm &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSM_RPM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; /tmp/amazon-ssm-agent.rpm
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/amazon-ssm-agent.rpm
systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;amazon-ssm-agent
systemctl restart amazon-ssm-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  robots.txt
&lt;/h3&gt;

&lt;p&gt;Crawler hint file—not security. The demo writes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: *
Allow: /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;user_data.tftpl&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/usr/share/nginx/html/robots.txt &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;ROBOTS&lt;/span&gt;&lt;span class="sh"&gt;'
User-agent: *
Allow: /
&lt;/span&gt;&lt;span class="no"&gt;ROBOTS
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://developers.google.com/search/docs/crawling-indexing/robots/intro" rel="noopener noreferrer"&gt;Google: robots.txt&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/jdevto/tf-aws-ec2-static-demo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;tf-aws-ec2-static-demo
terraform init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ALB (needs ≥2 AZs; default &lt;strong&gt;&lt;code&gt;az_count&lt;/code&gt;&lt;/strong&gt; is 3):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform apply &lt;span class="nt"&gt;-var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"use_alb=true"&lt;/span&gt;
&lt;span class="c"&gt;# terraform apply -var="use_alb=true" -var="az_count=2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait &lt;strong&gt;1–2 minutes&lt;/strong&gt; after first boot for &lt;strong&gt;&lt;code&gt;user_data&lt;/code&gt;&lt;/strong&gt;. &lt;strong&gt;&lt;code&gt;user_data_replace_on_change = true&lt;/code&gt;&lt;/strong&gt; replaces instances when the template changes. Variables: repo &lt;strong&gt;&lt;a href="https://github.com/jdevto/tf-aws-ec2-static-demo/blob/main/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"use_alb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"allowed_http_cidr"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"enable_ssm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform output verify_commands
&lt;span class="c"&gt;# use_alb=false:&lt;/span&gt;
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="s2"&gt;"http://&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;terraform output &lt;span class="nt"&gt;-raw&lt;/span&gt; instance_public_ip&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/robots.txt"&lt;/span&gt;
&lt;span class="c"&gt;# use_alb=true (no instance public IP):&lt;/span&gt;
&lt;span class="c"&gt;# curl -sS "$(terraform output -raw website_url_alb)/robots.txt"&lt;/span&gt;
terraform output &lt;span class="nt"&gt;-raw&lt;/span&gt; ssm_start_session_command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Timeout / connection refused&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;use_alb=true&lt;/code&gt;:&lt;/strong&gt; use ALB URL, not instance IP. &lt;strong&gt;&lt;code&gt;false&lt;/code&gt;:&lt;/strong&gt; SG, &lt;strong&gt;&lt;code&gt;allowed_http_cidr&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;user_data&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;instance_public_ip&lt;/code&gt;&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ALB unhealthy / &lt;strong&gt;502&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;SG &lt;strong&gt;:80&lt;/strong&gt; from ALB + VPC; &lt;strong&gt;&lt;code&gt;/&lt;/code&gt;&lt;/strong&gt; returns &lt;strong&gt;200&lt;/strong&gt;. &lt;strong&gt;&lt;code&gt;cloud-init-output.log&lt;/code&gt;:&lt;/strong&gt; failed &lt;strong&gt;&lt;code&gt;user_data&lt;/code&gt;&lt;/strong&gt; (e.g. &lt;strong&gt;&lt;code&gt;dnf install curl&lt;/code&gt;&lt;/strong&gt; vs &lt;strong&gt;&lt;code&gt;curl-minimal&lt;/code&gt;&lt;/strong&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply limits&lt;/td&gt;
&lt;td&gt;Other region/account or limit increase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSM offline / denied&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;enable_ssm&lt;/code&gt;&lt;/strong&gt;, agent time, &lt;strong&gt;&lt;code&gt;ssm:StartSession&lt;/code&gt;&lt;/strong&gt;, outbound to SSM (NAT or endpoints).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jdevto/tf-aws-ec2-static-demo" rel="noopener noreferrer"&gt;tf-aws-ec2-static-demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs" rel="noopener noreferrer"&gt;Terraform AWS provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html" rel="noopener noreferrer"&gt;Amazon VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html" rel="noopener noreferrer"&gt;Application Load Balancer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html" rel="noopener noreferrer"&gt;Session Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html" rel="noopener noreferrer"&gt;Session Manager plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terraform</category>
      <category>ec2</category>
      <category>vpc</category>
      <category>ssm</category>
    </item>
    <item>
      <title>Using GoAccess to View nginx Logs</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sat, 28 Mar 2026 08:54:19 +0000</pubDate>
      <link>https://dev.to/jajera/using-goaccess-to-view-nginx-logs-1d1c</link>
      <guid>https://dev.to/jajera/using-goaccess-to-view-nginx-logs-1d1c</guid>
      <description>&lt;h2&gt;
  
  
  Using GoAccess to View nginx Logs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://goaccess.io/" rel="noopener noreferrer"&gt;GoAccess&lt;/a&gt; is a fast terminal and HTML log analyzer for nginx access logs (requests/sec, status codes, top URLs, referrers, user agents). This guide covers installation, optional S3 download, and typical run modes.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;strong&gt;GoAccess&lt;/strong&gt; (package manager, source, or &lt;a href="https://github.com/jdevto/cli-tools" rel="noopener noreferrer"&gt;jdevto/cli-tools&lt;/a&gt; script)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional:&lt;/strong&gt; sync logs from &lt;strong&gt;S3&lt;/strong&gt; when they are not on the machine you analyze from&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;TUI&lt;/strong&gt;, &lt;strong&gt;HTML report&lt;/strong&gt;, &lt;strong&gt;live tail&lt;/strong&gt;, or &lt;strong&gt;compressed&lt;/strong&gt; input; use &lt;code&gt;COMBINED&lt;/code&gt; or &lt;code&gt;COMMON&lt;/code&gt; to match nginx &lt;code&gt;log_format&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip §4 if logs are already on disk.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Readable &lt;strong&gt;nginx access logs&lt;/strong&gt; (usually &lt;strong&gt;combined&lt;/strong&gt; or &lt;strong&gt;common&lt;/strong&gt; format)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sudo&lt;/strong&gt; for distro package installs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 (optional):&lt;/strong&gt; AWS CLI v2 and &lt;code&gt;s3:GetObject&lt;/code&gt; / &lt;code&gt;s3:ListBucket&lt;/code&gt; for the prefix you use&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Install GoAccess
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Fedora / RHEL / CentOS Stream
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; goaccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Debian / Ubuntu
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; goaccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Newer or custom build:&lt;/strong&gt; &lt;a href="https://goaccess.io/download" rel="noopener noreferrer"&gt;official build instructions&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  jdevto/cli-tools installer (optional)
&lt;/h4&gt;

&lt;p&gt;Builds from the &lt;a href="https://tar.goaccess.io" rel="noopener noreferrer"&gt;official tarball&lt;/a&gt;; details and env vars in &lt;a href="https://github.com/jdevto/cli-tools/blob/main/docs/install_goaccess.md" rel="noopener noreferrer"&gt;install_goaccess.md&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://raw.githubusercontent.com/jdevto/cli-tools/main/scripts/install_goaccess.sh&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://raw.githubusercontent.com/jdevto/cli-tools/main/scripts/install_goaccess.sh&lt;span class="o"&gt;)&lt;/span&gt; uninstall
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Optional: Download nginx Logs from S3
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Single file
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/nginx-logs
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://my-bucket/path/to/access.log ~/nginx-logs/access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key is &lt;code&gt;.gz&lt;/code&gt; only:&lt;/strong&gt; download, decompress, or stream without extracting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://my-bucket/path/to/access.log.gz ~/nginx-logs/access.log.gz
&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; ~/nginx-logs/access.log.gz
&lt;span class="c"&gt;# or: zcat ~/nginx-logs/access.log.gz | goaccess - --log-format=COMBINED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Prefix (many files)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/nginx-logs
aws s3 &lt;span class="nb"&gt;sync &lt;/span&gt;s3://my-bucket/nginx-logs/ ~/nginx-logs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace bucket and prefix. If you only have &lt;strong&gt;&lt;code&gt;*.gz&lt;/code&gt;&lt;/strong&gt;, after sync use &lt;code&gt;zcat ~/nginx-logs/*.gz &amp;gt; ~/nginx-logs/merged-access.log&lt;/code&gt; (order across files may not be chronological) or decompress then merge plain &lt;code&gt;*.log&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Merge plain logs (optional)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/nginx-logs/&lt;span class="k"&gt;*&lt;/span&gt;.log &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/nginx-logs/merged-access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Run GoAccess
&lt;/h3&gt;

&lt;p&gt;Match &lt;strong&gt;&lt;code&gt;--log-format&lt;/code&gt;&lt;/strong&gt; to nginx (&lt;code&gt;COMBINED&lt;/code&gt; is the usual default).&lt;/p&gt;

&lt;h4&gt;
  
  
  Terminal UI
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  HTML report
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED &lt;span class="nt"&gt;-o&lt;/span&gt; report.html &lt;span class="nt"&gt;--no-parsing-spinner&lt;/span&gt;
xdg-open report.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Live log
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/log/nginx/access.log | goaccess - &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Common log format
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMMON
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Custom &lt;code&gt;log_format&lt;/code&gt;: map fields with GoAccess &lt;a href="https://goaccess.io/man" rel="noopener noreferrer"&gt;custom format&lt;/a&gt; tokens.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compressed on disk
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zcat /var/log/nginx/access.log.&lt;span class="k"&gt;*&lt;/span&gt;.gz | goaccess - &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Summary: Copy-Paste
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; goaccess
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/nginx-logs &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; aws s3 &lt;span class="nb"&gt;sync &lt;/span&gt;s3://YOUR_BUCKET/YOUR_PREFIX/ ~/nginx-logs/   &lt;span class="c"&gt;# optional&lt;/span&gt;
goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED &lt;span class="nt"&gt;-o&lt;/span&gt; report.html &lt;span class="nt"&gt;--no-parsing-spinner&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; xdg-open report.html
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/log/nginx/access.log | goaccess - &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Parsed 0 lines / wrong numbers:&lt;/strong&gt; Log line shape ≠ &lt;code&gt;COMBINED&lt;/code&gt;/&lt;code&gt;COMMON&lt;/code&gt;. Compare &lt;code&gt;head -1&lt;/code&gt; to nginx &lt;code&gt;log_format&lt;/code&gt; and adjust &lt;code&gt;--log-format&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permission denied on log:&lt;/strong&gt; &lt;code&gt;sudo goaccess ...&lt;/code&gt;, fix group on log files, or copy the log to your home directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S3 Access Denied:&lt;/strong&gt; IAM on bucket/prefix; check &lt;code&gt;AWS_PROFILE&lt;/code&gt; / role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live tail idle:&lt;/strong&gt; Confirm nginx &lt;code&gt;access_log&lt;/code&gt; path and read permissions on the active file.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://goaccess.io/" rel="noopener noreferrer"&gt;GoAccess&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goaccess.io/man" rel="noopener noreferrer"&gt;GoAccess man (log formats)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nginx.org/en/docs/http/ngx_http_log_module.html" rel="noopener noreferrer"&gt;nginx log module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html" rel="noopener noreferrer"&gt;AWS CLI s3 cp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>goaccess</category>
      <category>nginx</category>
      <category>logs</category>
      <category>aws</category>
    </item>
    <item>
      <title>Using GoAccess to View nginx Logs</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sun, 22 Mar 2026 23:22:42 +0000</pubDate>
      <link>https://dev.to/jajera/using-goaccess-to-view-nginx-logs-1491</link>
      <guid>https://dev.to/jajera/using-goaccess-to-view-nginx-logs-1491</guid>
      <description>&lt;h2&gt;
  
  
  Using GoAccess to View nginx Logs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://goaccess.io/" rel="noopener noreferrer"&gt;GoAccess&lt;/a&gt; is a fast terminal and HTML log analyzer for nginx access logs (requests/sec, status codes, top URLs, referrers, user agents). This guide covers installation, optional S3 download, and typical run modes.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;strong&gt;GoAccess&lt;/strong&gt; (package manager, source, or &lt;a href="https://github.com/jdevto/cli-tools" rel="noopener noreferrer"&gt;jdevto/cli-tools&lt;/a&gt; script)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional:&lt;/strong&gt; sync logs from &lt;strong&gt;S3&lt;/strong&gt; when they are not on the machine you analyze from&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;TUI&lt;/strong&gt;, &lt;strong&gt;HTML report&lt;/strong&gt;, &lt;strong&gt;live tail&lt;/strong&gt;, or &lt;strong&gt;compressed&lt;/strong&gt; input; use &lt;code&gt;COMBINED&lt;/code&gt; or &lt;code&gt;COMMON&lt;/code&gt; to match nginx &lt;code&gt;log_format&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip §4 if logs are already on disk.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Readable &lt;strong&gt;nginx access logs&lt;/strong&gt; (usually &lt;strong&gt;combined&lt;/strong&gt; or &lt;strong&gt;common&lt;/strong&gt; format)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sudo&lt;/strong&gt; for distro package installs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 (optional):&lt;/strong&gt; AWS CLI v2 and &lt;code&gt;s3:GetObject&lt;/code&gt; / &lt;code&gt;s3:ListBucket&lt;/code&gt; for the prefix you use&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Install GoAccess
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Fedora / RHEL / CentOS Stream
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; goaccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Debian / Ubuntu
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; goaccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Newer or custom build:&lt;/strong&gt; &lt;a href="https://goaccess.io/download" rel="noopener noreferrer"&gt;official build instructions&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  jdevto/cli-tools installer (optional)
&lt;/h4&gt;

&lt;p&gt;Builds from the &lt;a href="https://tar.goaccess.io" rel="noopener noreferrer"&gt;official tarball&lt;/a&gt;; details and env vars in &lt;a href="https://github.com/jdevto/cli-tools/blob/main/docs/install_goaccess.md" rel="noopener noreferrer"&gt;install_goaccess.md&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://raw.githubusercontent.com/jdevto/cli-tools/main/scripts/install_goaccess.sh&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://raw.githubusercontent.com/jdevto/cli-tools/main/scripts/install_goaccess.sh&lt;span class="o"&gt;)&lt;/span&gt; uninstall
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Optional: Download nginx Logs from S3
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Single file
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/nginx-logs
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://my-bucket/path/to/access.log ~/nginx-logs/access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key is &lt;code&gt;.gz&lt;/code&gt; only:&lt;/strong&gt; download, decompress, or stream without extracting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://my-bucket/path/to/access.log.gz ~/nginx-logs/access.log.gz
&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; ~/nginx-logs/access.log.gz
&lt;span class="c"&gt;# or: zcat ~/nginx-logs/access.log.gz | goaccess - --log-format=COMBINED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Prefix (many files)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/nginx-logs
aws s3 &lt;span class="nb"&gt;sync &lt;/span&gt;s3://my-bucket/nginx-logs/ ~/nginx-logs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace bucket and prefix. If you only have &lt;strong&gt;&lt;code&gt;*.gz&lt;/code&gt;&lt;/strong&gt;, after sync use &lt;code&gt;zcat ~/nginx-logs/*.gz &amp;gt; ~/nginx-logs/merged-access.log&lt;/code&gt; (order across files may not be chronological) or decompress then merge plain &lt;code&gt;*.log&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Merge plain logs (optional)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/nginx-logs/&lt;span class="k"&gt;*&lt;/span&gt;.log &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/nginx-logs/merged-access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Run GoAccess
&lt;/h3&gt;

&lt;p&gt;Match &lt;strong&gt;&lt;code&gt;--log-format&lt;/code&gt;&lt;/strong&gt; to nginx (&lt;code&gt;COMBINED&lt;/code&gt; is the usual default).&lt;/p&gt;

&lt;h4&gt;
  
  
  Terminal UI
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  HTML report
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED &lt;span class="nt"&gt;-o&lt;/span&gt; report.html &lt;span class="nt"&gt;--no-parsing-spinner&lt;/span&gt;
xdg-open report.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Live log
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/log/nginx/access.log | goaccess - &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Common log format
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMMON
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Custom &lt;code&gt;log_format&lt;/code&gt;: map fields with GoAccess &lt;a href="https://goaccess.io/man" rel="noopener noreferrer"&gt;custom format&lt;/a&gt; tokens.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compressed on disk
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zcat /var/log/nginx/access.log.&lt;span class="k"&gt;*&lt;/span&gt;.gz | goaccess - &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Summary: Copy-Paste
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; goaccess
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/nginx-logs &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; aws s3 &lt;span class="nb"&gt;sync &lt;/span&gt;s3://YOUR_BUCKET/YOUR_PREFIX/ ~/nginx-logs/   &lt;span class="c"&gt;# optional&lt;/span&gt;
goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
goaccess /var/log/nginx/access.log &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED &lt;span class="nt"&gt;-o&lt;/span&gt; report.html &lt;span class="nt"&gt;--no-parsing-spinner&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; xdg-open report.html
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/log/nginx/access.log | goaccess - &lt;span class="nt"&gt;--log-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;COMBINED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Parsed 0 lines / wrong numbers:&lt;/strong&gt; Log line shape ≠ &lt;code&gt;COMBINED&lt;/code&gt;/&lt;code&gt;COMMON&lt;/code&gt;. Compare &lt;code&gt;head -1&lt;/code&gt; to nginx &lt;code&gt;log_format&lt;/code&gt; and adjust &lt;code&gt;--log-format&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permission denied on log:&lt;/strong&gt; &lt;code&gt;sudo goaccess ...&lt;/code&gt;, fix group on log files, or copy the log to your home directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S3 Access Denied:&lt;/strong&gt; IAM on bucket/prefix; check &lt;code&gt;AWS_PROFILE&lt;/code&gt; / role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live tail idle:&lt;/strong&gt; Confirm nginx &lt;code&gt;access_log&lt;/code&gt; path and read permissions on the active file.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://goaccess.io/" rel="noopener noreferrer"&gt;GoAccess&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goaccess.io/man" rel="noopener noreferrer"&gt;GoAccess man (log formats)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nginx.org/en/docs/http/ngx_http_log_module.html" rel="noopener noreferrer"&gt;nginx log module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html" rel="noopener noreferrer"&gt;AWS CLI s3 cp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>goaccess</category>
      <category>nginx</category>
      <category>logs</category>
      <category>aws</category>
    </item>
    <item>
      <title>Why Your Kustomize Remote Bases Break on Managed Argo CD (and How to Fix It)</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Mon, 16 Mar 2026 10:50:40 +0000</pubDate>
      <link>https://dev.to/jajera/why-your-kustomize-remote-bases-break-on-managed-argo-cd-and-how-to-fix-it-26i6</link>
      <guid>https://dev.to/jajera/why-your-kustomize-remote-bases-break-on-managed-argo-cd-and-how-to-fix-it-26i6</guid>
      <description>&lt;h2&gt;
  
  
  Why Your Kustomize Remote Bases Break on Managed Argo CD (and How to Fix It)
&lt;/h2&gt;

&lt;p&gt;You switched to managed Argo CD (e.g. EKS Capabilities) and use AWS CodeConnections for Git. Your Applications that pull from &lt;strong&gt;public&lt;/strong&gt; GitHub remotes in Kustomize suddenly fail with errors like "Password authentication is not supported" or "Authentication failed". The same kustomization worked with self-managed Argo CD. This article explains why CodeConnections causes that and how &lt;strong&gt;vendoring&lt;/strong&gt; those remote bases into your repo fixes it.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this guide does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explains why Kustomize remote resources (e.g. &lt;code&gt;github.com/open-policy-agent/gatekeeper-library/...&lt;/code&gt;) break when Argo CD uses CodeConnections for Git&lt;/li&gt;
&lt;li&gt;Shows that the credential helper is applied to every &lt;code&gt;github.com&lt;/code&gt; URL, including public repos, and GitHub rejects those credentials&lt;/li&gt;
&lt;li&gt;Describes when to vendor and a minimal how-to: download remote files at a pinned ref, add them to your repo, and point your kustomization at local files instead of remote URLs&lt;/li&gt;
&lt;li&gt;Suggests keeping a README in the vendored directory so future upgrades are a repeatable re-download and commit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With managed Argo CD + CodeConnections, one credential is used for all GitHub access. When Kustomize runs &lt;code&gt;git fetch&lt;/code&gt; for a remote base, Argo CD passes that same credential. Public repos don't need auth—but they receive it anyway, and GitHub rejects the format (e.g. "Password authentication is not supported").&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Managed Argo CD (e.g. &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argo-cd.html" rel="noopener noreferrer"&gt;EKS Argo CD capability&lt;/a&gt;) with &lt;a href="https://docs.aws.amazon.com/codeconnections/latest/userguide/welcome.html" rel="noopener noreferrer"&gt;AWS CodeConnections&lt;/a&gt; used for Git (see &lt;a href="https://dev.to/jajera/argo-cd-on-eks-git-repo-access-with-aws-codeconnections-and-terraform-3ejl"&gt;Argo CD on EKS: Git repo access with AWS CodeConnections and Terraform&lt;/a&gt; for setup)&lt;/li&gt;
&lt;li&gt;At least one Argo CD Application whose source uses Kustomize with &lt;strong&gt;remote&lt;/strong&gt; &lt;code&gt;resources&lt;/code&gt; or &lt;code&gt;bases&lt;/code&gt; pointing at GitHub (e.g. &lt;code&gt;github.com/org/repo/path?ref=master&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Why remote bases break with CodeConnections
&lt;/h3&gt;

&lt;p&gt;When Argo CD syncs an Application, the repo-server runs &lt;code&gt;kustomize build&lt;/code&gt; over your repo. If your &lt;code&gt;kustomization.yaml&lt;/code&gt; lists remote resources like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;github.com/open-policy-agent/gatekeeper-library/library/general/httpsonly?ref=master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kustomize invokes &lt;code&gt;git fetch&lt;/code&gt; for that URL. Argo CD configures a Git credential helper so that any git operation gets credentials. With CodeConnections, that helper returns the &lt;strong&gt;same&lt;/strong&gt; credential (the one for your connected repos) for &lt;strong&gt;every&lt;/strong&gt; &lt;code&gt;github.com&lt;/code&gt; request—including requests to public repos such as &lt;code&gt;open-policy-agent/gatekeeper-library&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Git sends those credentials to GitHub. GitHub then responds with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fatal: Authentication failed for 'https://github.com/open-policy-agent/gatekeeper-library/'
remote: Invalid username or token. Password authentication is not supported for Git operations.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the build fails even though the remote repo is public and would work with no credentials. With self-managed Argo CD you might have used SSH for your app repo; Kustomize’s HTTPS fetches to public GitHub then didn’t use that credential and succeeded. With CodeConnections, one HTTPS credential is used everywhere, and it gets sent to public URLs where it’s invalid.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. When to vendor
&lt;/h3&gt;

&lt;p&gt;Vendor remote bases when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You use &lt;strong&gt;managed Argo CD with CodeConnections&lt;/strong&gt; and your Kustomize app references &lt;strong&gt;public&lt;/strong&gt; GitHub remotes (e.g. gatekeeper-library, shared bases from other orgs).&lt;/li&gt;
&lt;li&gt;You see authentication or "Password authentication is not supported" errors during manifest generation for those remotes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also vendor remotes you don’t control so that upgrades are explicit and reproducible (pin to a commit, re-download when you want to upgrade).&lt;/p&gt;




&lt;h3&gt;
  
  
  5. How to vendor
&lt;/h3&gt;

&lt;p&gt;Vendoring means copying the remote manifest files into your repo and pointing Kustomize at local files instead of remote URLs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose a ref&lt;/strong&gt; — Use a commit SHA or tag from the upstream repo (e.g. &lt;code&gt;master&lt;/code&gt; or a specific SHA) so you can reproduce the same content later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Download the remote files&lt;/strong&gt; — Each remote resource is usually a directory containing one or more YAML files (e.g. &lt;code&gt;template.yaml&lt;/code&gt;). Download those files using the raw GitHub URL pattern:
&lt;code&gt;https://raw.githubusercontent.com/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;/&amp;lt;ref&amp;gt;/&amp;lt;path&amp;gt;/&amp;lt;file&amp;gt;.yaml&lt;/code&gt;
Save them under a directory in your repo (e.g. &lt;code&gt;infrastructure/my-app/vendored/&lt;/code&gt;) with clear names (e.g. &lt;code&gt;httpsonly.yaml&lt;/code&gt;, &lt;code&gt;requiredlabels.yaml&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update your kustomization&lt;/strong&gt; — Replace remote &lt;code&gt;resources&lt;/code&gt; entries with the local file names:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before (remote – fails with CodeConnections)&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;github.com/open-policy-agent/gatekeeper-library/library/general/httpsonly?ref=master&lt;/span&gt;

&lt;span class="c1"&gt;# After (vendored)&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;httpsonly.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Document the source and upgrade process&lt;/strong&gt; — Add a README in the vendored directory that lists:

&lt;ul&gt;
&lt;li&gt;The upstream repo and the ref (commit SHA) you used&lt;/li&gt;
&lt;li&gt;The mapping from each local file to its upstream path&lt;/li&gt;
&lt;li&gt;How to upgrade: re-download from a new ref, overwrite the files, run &lt;code&gt;kustomize build .&lt;/code&gt; to verify, commit, and update the README with the new ref.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Optionally, add a small script or one-liner (e.g. a shell loop with &lt;code&gt;curl&lt;/code&gt;) that downloads all vendored files given a ref, so upgrades are a single command plus commit.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Managed Argo CD + CodeConnections sends one GitHub credential to every git URL. Kustomize remote bases to public GitHub repos get that credential; GitHub rejects it and the build fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Vendor those remote bases: download the manifest files at a pinned ref, put them in your repo, and point &lt;code&gt;kustomization.yaml&lt;/code&gt; at the local files. No remote fetch at build time, so no credential is used for those resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrades:&lt;/strong&gt; Re-download from a new ref, overwrite the vendored files, verify with &lt;code&gt;kustomize build .&lt;/code&gt;, commit, and update the README with the new ref.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Checklist when vendoring:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick a ref (e.g. latest &lt;code&gt;master&lt;/code&gt; or a commit SHA) from the upstream repo.&lt;/li&gt;
&lt;li&gt;Download each remote file via &lt;code&gt;https://raw.githubusercontent.com/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;/&amp;lt;ref&amp;gt;/&amp;lt;path&amp;gt;/&amp;lt;file&amp;gt;.yaml&lt;/code&gt; into a directory in your repo.&lt;/li&gt;
&lt;li&gt;Replace remote &lt;code&gt;resources&lt;/code&gt; in &lt;code&gt;kustomization.yaml&lt;/code&gt; with the local file names.&lt;/li&gt;
&lt;li&gt;Add a README in that directory with source ref, file mapping, and upgrade steps (and optionally a download script).&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  7. Troubleshooting
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Manifest generation still fails after vendoring
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Confirm &lt;code&gt;kustomization.yaml&lt;/code&gt; lists only &lt;strong&gt;local&lt;/strong&gt; file names (e.g. &lt;code&gt;httpsonly.yaml&lt;/code&gt;), not &lt;code&gt;github.com/...&lt;/code&gt; URLs.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;kustomize build .&lt;/code&gt; from the directory that contains the kustomization and vendored files; fix any path or resource errors before relying on Argo CD.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Upstream added or removed a file
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Re-download from the ref you want (e.g. new commit on &lt;code&gt;master&lt;/code&gt;). Add or remove the corresponding local file and update the &lt;code&gt;resources&lt;/code&gt; list and README.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://argo-cd.readthedocs.io/en/stable/user-guide/kustomize/" rel="noopener noreferrer"&gt;Argo CD – Kustomize&lt;/a&gt; (including private remote bases)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/jajera/argo-cd-on-eks-git-repo-access-with-aws-codeconnections-and-terraform-3ejl"&gt;Argo CD on EKS: Git repo access with AWS CodeConnections and Terraform&lt;/a&gt; (CodeConnections setup)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/open-policy-agent/gatekeeper-library" rel="noopener noreferrer"&gt;gatekeeper-library&lt;/a&gt; (example upstream that’s often used as a Kustomize remote)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>argocd</category>
      <category>kubernetes</category>
      <category>kustomize</category>
      <category>vendoring</category>
    </item>
    <item>
      <title>Argo CD on EKS: Git repo access with AWS CodeConnections and Terraform</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sat, 14 Mar 2026 07:31:29 +0000</pubDate>
      <link>https://dev.to/jajera/argo-cd-on-eks-git-repo-access-with-aws-codeconnections-and-terraform-kck</link>
      <guid>https://dev.to/jajera/argo-cd-on-eks-git-repo-access-with-aws-codeconnections-and-terraform-kck</guid>
      <description>&lt;h2&gt;
  
  
  Argo CD on EKS: Git repo access with AWS CodeConnections and Terraform
&lt;/h2&gt;

&lt;p&gt;Argo CD on EKS Capabilities needs to pull from your Git repos. Instead of storing personal access tokens or SSH keys in the cluster, use &lt;strong&gt;AWS CodeConnections&lt;/strong&gt;: one connection authorizes Argo CD to access GitHub via IAM. This guide gives the minimal Terraform (connection + IAM policy on the Argo CD role) and the one-time Console steps to move the connection from Pending to Available. One connection can serve many repos; you only change the owner/repo in the URL.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this guide does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a CodeStar connection (GitHub) and grants the Argo CD capability role &lt;code&gt;codeconnections:UseConnection&lt;/code&gt; and &lt;code&gt;codeconnections:GetConnection&lt;/code&gt; so Argo CD can pull from Git without credentials in the cluster&lt;/li&gt;
&lt;li&gt;Walks through the one-time Console step to complete the connection (Pending → Available), including using the &lt;strong&gt;GitHub App&lt;/strong&gt; (e.g. AWS Connector for GitHub) for org repos&lt;/li&gt;
&lt;li&gt;Shows the CodeConnections repo URL format for Argo CD Applications (connection ID is the UUID only, not the ARN)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why CodeConnections?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No PAT or SSH key in Kubernetes; the Argo CD role gets IAM permission to use the connection&lt;/li&gt;
&lt;li&gt;One connection = multiple GitHub repos (same connection ID, different owner/repo in the URL)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster with the &lt;strong&gt;Argo CD capability&lt;/strong&gt; enabled (Identity Center configured)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;name&lt;/strong&gt; of the Argo CD capability IAM role (e.g. from your EKS module: &lt;code&gt;cluster_name-argocd-capability-role&lt;/code&gt;, or from AWS Console → IAM → Roles)&lt;/li&gt;
&lt;li&gt;AWS Console access to complete the connection (GitHub OAuth)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Terraform: connection and IAM
&lt;/h3&gt;

&lt;p&gt;Add the following to your Terraform. Replace &lt;code&gt;argocd_capability_role_name&lt;/code&gt; with the actual role name (the role EKS created for the Argo CD capability).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"argocd_capability_role_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the IAM role used by the Argo CD EKS Capability"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_codestarconnections_connection"&lt;/span&gt; &lt;span class="s2"&gt;"github"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github"&lt;/span&gt;
  &lt;span class="nx"&gt;provider_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GitHub"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"argocd_codeconnections"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"codeconnections:UseConnection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"codeconnections:GetConnection"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_codestarconnections_connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy"&lt;/span&gt; &lt;span class="s2"&gt;"argocd_codeconnections"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"argocd-codeconnections"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argocd_capability_role_name&lt;/span&gt;
  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argocd_codeconnections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;terraform apply&lt;/code&gt;, the connection exists in &lt;strong&gt;Pending&lt;/strong&gt; state. Terraform cannot complete it; you do that once in the Console.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. After apply: complete the connection (Pending → Available)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;a href="https://console.aws.amazon.com/" rel="noopener noreferrer"&gt;AWS Console&lt;/a&gt; in the same region as your Terraform.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Developer Tools&lt;/strong&gt; → &lt;strong&gt;Connections&lt;/strong&gt; (or search &lt;strong&gt;Connections&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Find the connection (e.g. &lt;code&gt;github&lt;/code&gt;). Status will be &lt;strong&gt;Pending&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click the connection name → &lt;strong&gt;Update pending connection&lt;/strong&gt; (or &lt;strong&gt;Connect to GitHub&lt;/strong&gt;). You’ll land on the &lt;strong&gt;Connect to GitHub&lt;/strong&gt; page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;GitHub connection settings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connection name&lt;/strong&gt; — Confirm or set the name (e.g. &lt;code&gt;github&lt;/code&gt; to match your Terraform &lt;code&gt;name&lt;/code&gt;). This is how the connection appears in the Console.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App Installation (optional)&lt;/strong&gt; — Two choices:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leave blank&lt;/strong&gt; to connect as a &lt;strong&gt;GitHub user&lt;/strong&gt;. That user must have (at least read) access to the repos you use in Argo CD. Fine for personal or single-account repos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a GitHub App&lt;/strong&gt; (recommended for org repos): e.g. choose &lt;strong&gt;AWS Connector for GitHub&lt;/strong&gt; via “Install a new app”, then select &lt;strong&gt;the org where your repos live&lt;/strong&gt; (e.g. &lt;code&gt;my-org&lt;/code&gt;) as the installation target.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Click the orange &lt;strong&gt;Connect&lt;/strong&gt; button to start the GitHub authorization flow (or complete it after installing the app).&lt;/li&gt;

&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;If you chose the GitHub App&lt;/strong&gt;, you’ll land on GitHub’s &lt;strong&gt;Install &amp;amp; Authorize AWS Connector for GitHub&lt;/strong&gt; page for that org. Choose &lt;strong&gt;Only select repositories&lt;/strong&gt;, click &lt;strong&gt;Select repositories&lt;/strong&gt;, and pick the repo(s) Argo CD will use (e.g. &lt;code&gt;my-org/my-repo&lt;/code&gt;). Review the permissions (read/write access to code, pull requests, etc.), then click &lt;strong&gt;Install &amp;amp; Authorize&lt;/strong&gt;. You’ll be redirected to &lt;code&gt;https://redirect.codestar.aws/return&lt;/code&gt;. Back on the AWS &lt;strong&gt;Connect to GitHub&lt;/strong&gt; page, the &lt;strong&gt;App Installation&lt;/strong&gt; field will show your installation (e.g. an installation ID such as &lt;code&gt;123456789&lt;/code&gt;—yours will differ). Confirm &lt;strong&gt;Connection name&lt;/strong&gt; (e.g. &lt;code&gt;github&lt;/code&gt;), then click the orange &lt;strong&gt;Connect&lt;/strong&gt; button. The connection status should become &lt;strong&gt;Available&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you connected as a GitHub user&lt;/strong&gt;, complete the OAuth prompt, then return to the Console and confirm status is &lt;strong&gt;Available&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  5. Test the connection
&lt;/h3&gt;

&lt;p&gt;Once the connection is &lt;strong&gt;Available&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Register the repo in Argo CD&lt;/strong&gt; (one-time). Create a repository Secret so the repo appears under Settings → Repositories. Use your real &lt;strong&gt;region&lt;/strong&gt;, &lt;strong&gt;account ID&lt;/strong&gt;, &lt;strong&gt;connection UUID&lt;/strong&gt;, and &lt;strong&gt;org/repo&lt;/strong&gt;—do not leave literal &lt;code&gt;OWNER/REPO&lt;/code&gt; in the URL or you’ll get “repository not found”. Example (replace the values if yours differ):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-southeast-2
   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class="nt"&gt;--query&lt;/span&gt; Account &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;
   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONN_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;a1b2c3d4-e5f6-7890-abcd-ef1234567890   &lt;span class="c"&gt;# your connection UUID from Console or Terraform&lt;/span&gt;
   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OWNER_REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-org/my-repo                     &lt;span class="c"&gt;# your org and repo&lt;/span&gt;
   kubectl create secret generic argocd-repo-github &lt;span class="nt"&gt;-n&lt;/span&gt; argocd &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://codeconnections.&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com/git-http/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CONN_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OWNER_REPO&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.git"&lt;/span&gt;
   kubectl label secret argocd-repo-github &lt;span class="nt"&gt;-n&lt;/span&gt; argocd argocd.argoproj.io/secret-type&lt;span class="o"&gt;=&lt;/span&gt;repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the secret already exists with the wrong URL, delete it first: &lt;code&gt;kubectl delete secret argocd-repo-github -n argocd&lt;/code&gt;, then run the &lt;code&gt;create&lt;/code&gt; and &lt;code&gt;label&lt;/code&gt; commands above.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;Argo CD&lt;/strong&gt; → &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Repositories&lt;/strong&gt;, click &lt;strong&gt;REFRESH LIST&lt;/strong&gt;. The repo should show with a green check (Successful). If it shows Failed, see the Troubleshooting section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create an Application&lt;/strong&gt; that uses this repo: set &lt;code&gt;source.repoURL&lt;/code&gt; to the same CodeConnections URL and a path/targetRevision. Sync the application and confirm it syncs without errors.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  6. Using the repo URL in Argo CD
&lt;/h3&gt;

&lt;p&gt;CodeConnections URL format (replace placeholders):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://codeconnections.&amp;lt;region&amp;gt;.amazonaws.com/git-http/&amp;lt;account-id&amp;gt;/&amp;lt;region&amp;gt;/&amp;lt;connection-id&amp;gt;/OWNER/REPO.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;connection-id:&lt;/strong&gt; Must be the &lt;strong&gt;connection ID (UUID only)&lt;/strong&gt;, e.g. &lt;code&gt;9b6c3274-31da-4d1d-8955-e7d5cd9d15e2&lt;/code&gt;. Do &lt;strong&gt;not&lt;/strong&gt; put the full ARN in the URL path—that causes HTTP 400. In Terraform the AWS provider’s &lt;code&gt;aws_codestarconnections_connection.github.id&lt;/code&gt; is the ARN; use the UUID (the segment after the last &lt;code&gt;/&lt;/code&gt; in the ARN) or an output from your module that exposes the UUID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OWNER/REPO:&lt;/strong&gt; Your Git org and repo (e.g. &lt;code&gt;my-org/my-repo&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In your Argo CD Application, set &lt;code&gt;source.repoURL&lt;/code&gt; to that URL. One connection works for many repos—same connection ID, change only owner/repo.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Summary: copy-paste
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Terraform:&lt;/strong&gt; Connection + IAM policy (role name from your EKS setup):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_codestarconnections_connection"&lt;/span&gt; &lt;span class="s2"&gt;"github"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github"&lt;/span&gt;
  &lt;span class="nx"&gt;provider_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GitHub"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy"&lt;/span&gt; &lt;span class="s2"&gt;"argocd_codeconnections"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"argocd-codeconnections"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argocd_capability_role_name&lt;/span&gt;  &lt;span class="c1"&gt;# your Argo CD capability role name&lt;/span&gt;
  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;Version&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;Effect&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
      &lt;span class="nx"&gt;Action&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"codeconnections:UseConnection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"codeconnections:GetConnection"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_codestarconnections_connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Console:&lt;/strong&gt; Developer Tools → Connections → select connection → Update pending connection → on the Connect to GitHub page set/confirm Connection name, then either leave App Installation blank (user connection) or install &lt;strong&gt;AWS Connector for GitHub&lt;/strong&gt; and select the org that owns your repos (e.g. my-org) → click &lt;strong&gt;Connect&lt;/strong&gt; → complete GitHub auth → status &lt;strong&gt;Available&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Argo CD:&lt;/strong&gt; Use the CodeConnections URL with the connection ID and your &lt;code&gt;OWNER/REPO&lt;/code&gt; as &lt;code&gt;source.repoURL&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Troubleshooting
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;What to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection stays &lt;strong&gt;Pending&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Complete the connection in the AWS Console (authorize in GitHub or install the app). Check region.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;HTTP 400&lt;/strong&gt; when Argo CD tests repo&lt;/td&gt;
&lt;td&gt;The repo URL path must use the &lt;strong&gt;connection ID (UUID only)&lt;/strong&gt;, not the full ARN. If your URL contains &lt;code&gt;arn:aws:codestar-connections:&lt;/code&gt; in the path, fix the URL to use only the UUID (e.g. from Terraform use a value that outputs the UUID, not &lt;code&gt;connection.id&lt;/code&gt; which is the ARN).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;repository not found&lt;/strong&gt; / &lt;strong&gt;ProviderResourceNotFoundException&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;The URL still has literal &lt;code&gt;OWNER/REPO&lt;/code&gt; instead of your real org and repo (e.g. &lt;code&gt;my-org/my-repo&lt;/code&gt;). Delete the repo Secret and recreate it with the correct URL (see §5).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;authorization failed: Write access to repository not granted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The GitHub identity (user or app) used by the connection doesn’t have access to that repo. Install the &lt;strong&gt;GitHub App&lt;/strong&gt; (e.g. AWS Connector for GitHub) on the &lt;strong&gt;org that owns the repo&lt;/strong&gt; (e.g. my-org), or ensure the GitHub user that authorized has read access to the repo. Then re-authorize the connection if needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Argo CD cannot fetch repo&lt;/td&gt;
&lt;td&gt;Argo CD role has &lt;code&gt;codeconnections:UseConnection&lt;/code&gt; and &lt;code&gt;codeconnections:GetConnection&lt;/code&gt; on the connection ARN; connection status &lt;strong&gt;Available&lt;/strong&gt;; &lt;code&gt;source.repoURL&lt;/code&gt; uses the UUID as connection-id and correct owner/repo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong region&lt;/td&gt;
&lt;td&gt;Connection is regional. Console and Terraform region must match.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  9. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argocd-configure-repositories.html" rel="noopener noreferrer"&gt;Configure repository access (Argo CD, CodeConnections)&lt;/a&gt; – AWS EKS User Guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/capabilities.html" rel="noopener noreferrer"&gt;EKS Capabilities&lt;/a&gt; – Argo CD, ACK, KRO&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>argocd</category>
      <category>codeconnections</category>
      <category>eks</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Bitwarden Secrets Manager on EKS – Per-App Integration with Atlantis</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Mon, 02 Mar 2026 10:01:15 +0000</pubDate>
      <link>https://dev.to/jajera/bitwarden-secrets-manager-on-eks-per-app-integration-with-atlantis-5995</link>
      <guid>https://dev.to/jajera/bitwarden-secrets-manager-on-eks-per-app-integration-with-atlantis-5995</guid>
      <description>&lt;h2&gt;
  
  
  Bitwarden Secrets Manager on EKS – Per-App Integration with Atlantis
&lt;/h2&gt;

&lt;p&gt;Sync secrets from Bitwarden Secrets Manager into Kubernetes on EKS using the sm-operator, AWS Secrets Manager for the machine token, and the Secrets Store CSI Driver. This guide expands on the base integration with a &lt;strong&gt;per-app, per-namespace pattern&lt;/strong&gt; and uses &lt;strong&gt;Atlantis&lt;/strong&gt; as a concrete example. It covers Terraform, Kustomize overlays, Argo CD, sync waves, and troubleshooting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use placeholder values for org IDs and secret IDs. Never commit real tokens. For production, follow least-privilege IAM and rotation practices.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this guide does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrates Bitwarden Secrets Manager with EKS via sm-operator, AWS Secrets Manager, and Secrets Store CSI Driver&lt;/li&gt;
&lt;li&gt;Uses a &lt;strong&gt;per-app namespace pattern&lt;/strong&gt;: each app (e.g. Atlantis) gets its own SecretProviderClass, &lt;code&gt;bw-auth-token-sync&lt;/code&gt;, and BitwardenSecret in its own namespace&lt;/li&gt;
&lt;li&gt;Walks through Terraform (EKS + Pod Identity per app), manifests, Argo CD Applications, validation, and force-sync&lt;/li&gt;
&lt;li&gt;Uses Atlantis (Terraform PR automation) as a worked example with GitHub App credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why per-app namespaces?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolation: each app has its own Bitwarden machine token (scoped in AWS)&lt;/li&gt;
&lt;li&gt;Simplicity: the sm-operator creates the K8s Secret in the app’s namespace; no cross-namespace wiring&lt;/li&gt;
&lt;li&gt;Consistency: same pattern for every new app&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster with &lt;strong&gt;Secrets Store CSI Driver&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Argo CD&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;Terraform-managed EKS (e.g. &lt;code&gt;terraform-aws-eks-basic&lt;/code&gt; with Secrets Manager support)&lt;/li&gt;
&lt;li&gt;Bitwarden Secrets Manager organization with Machine Account&lt;/li&gt;
&lt;li&gt;Per-app AWS secret path: &lt;code&gt;bitwarden/sm-operator/&amp;lt;app&amp;gt;/machine-token&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Architecture Overview
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bitwarden SM (Machine Account + App Secrets)
        │
        │ machine token (per app: bitwarden/sm-operator/&amp;lt;app&amp;gt;/machine-token)
        ▼
AWS Secrets Manager
        │
        │ Pod Identity + CSI (in app namespace, e.g. atlantis-1)
        ▼
SecretProviderClass + bw-auth-token-sync → creates bw-auth-token
        │
        ▼
BitwardenSecret (authToken: bw-auth-token)
        │
        │ sm-operator fetches via Bitwarden API
        ▼
Output K8s Secret (e.g. atlantis-1-vcs) in app namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flow (per app, e.g. atlantis-1):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Machine token stored in AWS Secrets Manager as &lt;code&gt;bitwarden/sm-operator/&amp;lt;app&amp;gt;/machine-token&lt;/code&gt; (JSON: &lt;code&gt;{"token":"&amp;lt;value&amp;gt;"}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;SecretProviderClass + &lt;code&gt;bw-auth-token-sync&lt;/code&gt; Deployment in the app namespace: CSI Driver mounts the token and creates K8s Secret &lt;code&gt;bw-auth-token&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;BitwardenSecret in the same namespace: &lt;code&gt;authToken.secretName: bw-auth-token&lt;/code&gt;. The sm-operator reads this token and calls the Bitwarden API.&lt;/li&gt;
&lt;li&gt;sm-operator creates the output K8s Secret (e.g. &lt;code&gt;atlantis-1-vcs&lt;/code&gt;) in the app’s namespace. Atlantis (or any app) uses it directly.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  4. Bitwarden Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Machine Account and token:&lt;/strong&gt; Bitwarden Admin → Machine Accounts → Create Access Token. Copy the token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-app machine token (optional):&lt;/strong&gt; For isolation, create a separate token per app and store in &lt;code&gt;bitwarden/sm-operator/&amp;lt;app&amp;gt;/machine-token&lt;/code&gt; in AWS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App secrets:&lt;/strong&gt; In Bitwarden Secrets Manager, create the secrets your apps need. For Atlantis (GitHub App): webhook secret, private key (&lt;code&gt;key.pem&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy IDs:&lt;/strong&gt; From Bitwarden Admin → Settings → Organization, copy &lt;code&gt;organizationId&lt;/code&gt;. For each secret, copy its &lt;code&gt;bwSecretId&lt;/code&gt; (UUID).&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  5. Terraform
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Requirement:&lt;/strong&gt; EKS module must enable Secrets Manager with Pod Identity. Add an association &lt;strong&gt;per app namespace&lt;/strong&gt; (e.g. &lt;code&gt;{ namespace = "atlantis-1", service_account = "awssm-sync" }&lt;/code&gt;) and prefix &lt;code&gt;bitwarden/sm-operator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create the AWS Secrets Manager secret per app. Pass the token via &lt;code&gt;-var&lt;/code&gt; or &lt;code&gt;TF_VAR_&lt;/code&gt;. Never commit it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden_sm_machine_token_atlantis"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bitwarden SM machine token for atlantis-1"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"REPLACE_WITH_REAL_TOKEN"&lt;/span&gt;
  &lt;span class="nx"&gt;sensitive&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_secretsmanager_secret"&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden_atlantis"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden/sm-operator/atlantis-1/machine-token"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bitwarden SM machine token for atlantis-1"&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_secretsmanager_secret_version"&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden_atlantis"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;secret_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_secretsmanager_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitwarden_atlantis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;secret_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitwarden_sm_machine_token_atlantis&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Per-App Manifests (Atlantis Example)
&lt;/h3&gt;

&lt;p&gt;Each app gets its own overlay with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SecretProviderClass&lt;/li&gt;
&lt;li&gt;ServiceAccount + &lt;code&gt;bw-auth-token-sync&lt;/code&gt; Deployment&lt;/li&gt;
&lt;li&gt;BitwardenSecret&lt;/li&gt;
&lt;li&gt;The app itself (e.g. Atlantis Helm chart)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  6.1 SecretProviderClass
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store.csi.x-k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecretProviderClass&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitwarden-sm-token&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-1"&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ap-southeast-2&lt;/span&gt;
    &lt;span class="na"&gt;usePodIdentity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
    &lt;span class="na"&gt;objects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;- objectName: "bitwarden/sm-operator/atlantis-1/machine-token"&lt;/span&gt;
        &lt;span class="s"&gt;objectType: "secretsmanager"&lt;/span&gt;
        &lt;span class="s"&gt;jmesPath:&lt;/span&gt;
          &lt;span class="s"&gt;- path: token&lt;/span&gt;
            &lt;span class="s"&gt;objectAlias: token&lt;/span&gt;
  &lt;span class="na"&gt;secretObjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;objectName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6.2 ServiceAccount + bw-auth-token-sync
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;awssm-sync&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-2"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-1"&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;awssm-sync&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pause&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.k8s.io/pause:3.9&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;4Mi&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/mnt/secrets-store"&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store&lt;/span&gt;
          &lt;span class="na"&gt;csi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store.csi.k8s.io&lt;/span&gt;
            &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;volumeAttributes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;secretProviderClass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitwarden-sm-token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6.3 BitwardenSecret
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8s.bitwarden.com/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BitwardenSecret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1-vcs&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0"&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;organizationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_ORG_ID"&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1-vcs&lt;/span&gt;
  &lt;span class="na"&gt;onlyMappedSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github_secret&lt;/span&gt;
      &lt;span class="na"&gt;bwSecretId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_WEBHOOK_SECRET_ID"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;key.pem&lt;/span&gt;
      &lt;span class="na"&gt;bwSecretId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_PRIVATE_KEY_ID"&lt;/span&gt;
  &lt;span class="na"&gt;authToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token&lt;/span&gt;
    &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6.4 Atlantis Helm values
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# application-patch.yaml&lt;/span&gt;
&lt;span class="na"&gt;vcsSecretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlantis-1-vcs&lt;/span&gt;
&lt;span class="na"&gt;githubApp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_GH_APP_ID"&lt;/span&gt;
  &lt;span class="na"&gt;installationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_GH_INSTALLATION_ID"&lt;/span&gt;
&lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;   &lt;span class="c1"&gt;# Enable when you have ingress + atlantisUrl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;argocd.argoproj.io/sync-wave: "5"&lt;/code&gt; on the Atlantis Application so it is created after the BitwardenSecret and &lt;code&gt;bw-auth-token-sync&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Sync Waves (Ordering)
&lt;/h3&gt;

&lt;p&gt;To avoid the app starting before secrets exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-2:&lt;/strong&gt; ServiceAccount &lt;code&gt;awssm-sync&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-1:&lt;/strong&gt; SecretProviderClass, &lt;code&gt;bw-auth-token-sync&lt;/code&gt; Deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0:&lt;/strong&gt; BitwardenSecret, ConfigMaps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5:&lt;/strong&gt; Atlantis Application (Helm)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. Validation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Verify secrets in app namespace&lt;/span&gt;
kubectl get secret atlantis-1-vcs bw-auth-token &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1

&lt;span class="c"&gt;# BitwardenSecret status&lt;/span&gt;
kubectl get bitwardensecret atlantis-1-vcs &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
kubectl get bitwardensecret atlantis-1-vcs &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.conditions[?(@.type=="SuccessfulSync")].status}'&lt;/span&gt;

&lt;span class="c"&gt;# Output secret keys (should show github_secret, key.pem)&lt;/span&gt;
kubectl get secret atlantis-1-vcs &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data}'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'keys[]'&lt;/span&gt;

&lt;span class="c"&gt;# Atlantis pod&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;atlantis &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  9. Local Access (Port-Forward)
&lt;/h3&gt;

&lt;p&gt;The Atlantis Service exposes port 80 (targetPort 4141):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/atlantis-1 &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 4141:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;a href="http://localhost:4141" rel="noopener noreferrer"&gt;http://localhost:4141&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. Force Sync (Token Refresh)
&lt;/h3&gt;

&lt;p&gt;When the machine token in AWS Secrets Manager changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Per-app namespace&lt;/span&gt;
kubectl delete secret bw-auth-token &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--grace-period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
kubectl rollout restart deployment/sm-operator-controller-manager &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl rollout restart statefulset atlantis-1 &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  11. Adding Another App
&lt;/h3&gt;

&lt;p&gt;For each new app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create app directory: &lt;code&gt;apps/&amp;lt;app&amp;gt;/overlays/&amp;lt;cluster&amp;gt;/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add SecretProviderClass (AWS path: &lt;code&gt;bitwarden/sm-operator/&amp;lt;app&amp;gt;/machine-token&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;bw-auth-token-sync&lt;/code&gt; (SA + Deployment)&lt;/li&gt;
&lt;li&gt;Add BitwardenSecret with the app’s secret mapping&lt;/li&gt;
&lt;li&gt;Add Terraform: &lt;code&gt;{ namespace = "&amp;lt;app&amp;gt;", service_account = "awssm-sync" }&lt;/code&gt; + AWS secret&lt;/li&gt;
&lt;li&gt;Deploy the app (Helm, etc.) with the created secret&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  12. Summary: Copy-Paste
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Validation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get secret atlantis-1-vcs bw-auth-token &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
kubectl get bitwardensecret atlantis-1-vcs &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.conditions[?(@.type=="SuccessfulSync")].status}'&lt;/span&gt;
kubectl get secret atlantis-1-vcs &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data}'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'keys[]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Port-forward:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/atlantis-1 &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 4141:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Force sync (token changed):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete secret bw-auth-token &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--grace-period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1 &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
kubectl rollout restart deployment/sm-operator-controller-manager &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl rollout restart statefulset atlantis-1 &lt;span class="nt"&gt;-n&lt;/span&gt; atlantis-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  13. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; &lt;code&gt;CreateContainerConfigError&lt;/code&gt; – Secret &lt;code&gt;atlantis-1-vcs&lt;/code&gt; missing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Wait for sm-operator to sync BitwardenSecret; or restart pod after secret exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Pod Identity / token association error&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Add &lt;code&gt;{ namespace = "atlantis-1", service_account = "awssm-sync" }&lt;/code&gt; to &lt;code&gt;secrets_manager_associations&lt;/code&gt; in Terraform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; &lt;code&gt;ResourceNotFoundException&lt;/code&gt; – AWS secret missing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Create &lt;code&gt;bitwarden/sm-operator/atlantis-1/machine-token&lt;/code&gt; in Secrets Manager (JSON: &lt;code&gt;{"token":"&amp;lt;value&amp;gt;"}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; &lt;code&gt;Error: --gh-app-id/--gh-app-key-file...&lt;/code&gt; – VCS secret not reaching container&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ensure &lt;code&gt;vcsSecretName&lt;/code&gt; and &lt;code&gt;githubApp.id&lt;/code&gt;/&lt;code&gt;installationId&lt;/code&gt; in Helm values; verify &lt;code&gt;atlantis-1-vcs&lt;/code&gt; exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Argo CD app stuck "Progressing"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ingress without controller. Set &lt;code&gt;ingress.enabled: false&lt;/code&gt; until ingress is configured.&lt;/p&gt;




&lt;h3&gt;
  
  
  14. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bitwarden.com/help/secrets-manager-kubernetes-operator/" rel="noopener noreferrer"&gt;Bitwarden SM Operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://secrets-store-csi-driver.sigs.k8s.io/" rel="noopener noreferrer"&gt;Secrets Store CSI Driver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/runatlantis/helm-charts" rel="noopener noreferrer"&gt;Atlantis Helm Chart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bitwarden</category>
      <category>secretsmanager</category>
      <category>eks</category>
      <category>atlantis</category>
    </item>
    <item>
      <title>Bitwarden Secrets Manager on EKS – End-to-End Integration</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sun, 01 Mar 2026 18:41:10 +0000</pubDate>
      <link>https://dev.to/jajera/bitwarden-secrets-manager-on-eks-end-to-end-integration-10d3</link>
      <guid>https://dev.to/jajera/bitwarden-secrets-manager-on-eks-end-to-end-integration-10d3</guid>
      <description>&lt;h2&gt;
  
  
  Bitwarden Secrets Manager on EKS – End-to-End Integration
&lt;/h2&gt;

&lt;p&gt;Sync secrets from Bitwarden Secrets Manager into Kubernetes on EKS using the sm-operator, AWS Secrets Manager for the machine token, and the Secrets Store CSI Driver. This guide walks through Terraform, manifests, Argo CD, validation, and force-sync procedures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use placeholder values for org IDs and secret IDs. Never commit real tokens. For production, follow least-privilege IAM and rotation practices.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this guide does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrates Bitwarden Secrets Manager with EKS via sm-operator, AWS Secrets Manager, and Secrets Store CSI Driver&lt;/li&gt;
&lt;li&gt;Stores machine token in AWS Secrets Manager; CSI Driver mounts it; sm-operator syncs Bitwarden secrets into K8s Secrets&lt;/li&gt;
&lt;li&gt;Walks through Terraform (EKS + secret), flat manifests, Argo CD Application, validation, and force-sync&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster with &lt;strong&gt;Secrets Store CSI Driver&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Argo CD&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;Terraform-managed EKS (e.g. terraform-aws-eks-basic or equivalent)&lt;/li&gt;
&lt;li&gt;Bitwarden Secrets Manager organization with Machine Account&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Architecture Overview
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bitwarden SM (Machine Account + App Secrets)
        │
        │ machine token
        ▼
AWS Secrets Manager (bitwarden/sm-operator/machine-token)
        │
        │ Pod Identity + CSI
        ▼
Secrets Store CSI Driver → creates bw-auth-token
        │
        ▼
sm-operator (reads BitwardenSecret CR, uses bw-auth-token)
        │
        │ Bitwarden API fetches secrets
        ▼
github-app-secrets (K8s Secret)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Machine token stored in AWS Secrets Manager as &lt;code&gt;{"token":"&amp;lt;value&amp;gt;"}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;CSI Driver mounts it into a pod; creates K8s Secret &lt;code&gt;bw-auth-token&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;sm-operator uses &lt;code&gt;bw-auth-token&lt;/code&gt; to auth to Bitwarden API and sync secrets into &lt;code&gt;github-app-secrets&lt;/code&gt; (or your chosen output secret)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Bitwarden Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Machine Account and token:&lt;/strong&gt; Bitwarden Admin → Machine Accounts → Create Access Token. Copy the token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App secrets:&lt;/strong&gt; In Bitwarden Secrets Manager, create the secrets your apps need (e.g. &lt;code&gt;github-app-id&lt;/code&gt;, &lt;code&gt;github-app-key&lt;/code&gt;, &lt;code&gt;github-app-webhook-secret&lt;/code&gt;, &lt;code&gt;github-app-installation-id&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy IDs:&lt;/strong&gt; From Bitwarden Admin → Settings → Organization, copy &lt;code&gt;organizationId&lt;/code&gt;. For each secret, copy its &lt;code&gt;bwSecretId&lt;/code&gt; (UUID).&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  5. Terraform
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Requirement:&lt;/strong&gt; EKS module must enable Secrets Manager with Pod Identity for &lt;code&gt;sm-operator-system&lt;/code&gt; / &lt;code&gt;awssm-sync&lt;/code&gt; and secret prefix &lt;code&gt;bitwarden/sm-operator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create the AWS Secrets Manager secret and pass the token via &lt;code&gt;-var&lt;/code&gt; or &lt;code&gt;TF_VAR_bitwarden_sm_machine_token&lt;/code&gt;. Never commit it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden_sm_machine_token"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bitwarden SM machine token from Machine Account → Create Access Token"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"REPLACE_WITH_REAL_TOKEN"&lt;/span&gt;
  &lt;span class="nx"&gt;sensitive&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_secretsmanager_secret"&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden_sm_token"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden/sm-operator/machine-token"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bitwarden Secrets Manager machine token for sm-operator"&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_secretsmanager_secret_version"&lt;/span&gt; &lt;span class="s2"&gt;"bitwarden_sm_token"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;secret_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_secretsmanager_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitwarden_sm_token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;secret_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitwarden_sm_machine_token&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Deploy sm-operator
&lt;/h3&gt;

&lt;p&gt;Save as &lt;code&gt;sm-operator.yaml&lt;/code&gt; and apply. Replace placeholders in BitwardenSecret; adjust &lt;code&gt;region&lt;/code&gt; if needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Namespace for sm-operator and CSI resources&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# ServiceAccount with Pod Identity for AWS Secrets Manager access&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;awssm-sync&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-2"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Fetches machine token from AWS SM and creates K8s Secret bw-auth-token&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store.csi.x-k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecretProviderClass&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitwarden-sm-token&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-1"&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ap-southeast-2&lt;/span&gt;
    &lt;span class="na"&gt;usePodIdentity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
    &lt;span class="na"&gt;objects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;- objectName: "bitwarden/sm-operator/machine-token"&lt;/span&gt;
        &lt;span class="s"&gt;objectType: "secretsmanager"&lt;/span&gt;
        &lt;span class="s"&gt;jmesPath:&lt;/span&gt;
          &lt;span class="s"&gt;- path: token&lt;/span&gt;
            &lt;span class="s"&gt;objectAlias: token&lt;/span&gt;
  &lt;span class="na"&gt;secretObjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;objectName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Pod that triggers CSI mount; creates bw-auth-token used by sm-operator&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/sync-wave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-1"&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token-sync&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;awssm-sync&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pause&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.k8s.io/pause:3.9&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;4Mi&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/mnt/secrets-store"&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store&lt;/span&gt;
          &lt;span class="na"&gt;csi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secrets-store.csi.k8s.io&lt;/span&gt;
            &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;volumeAttributes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;secretProviderClass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitwarden-sm-token&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Maps Bitwarden secrets to github-app-secrets K8s Secret&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8s.bitwarden.com/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BitwardenSecret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitwarden-secret&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;organizationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_ORG_ID"&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-app-secrets&lt;/span&gt;
  &lt;span class="na"&gt;onlyMappedSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-app-id&lt;/span&gt;
      &lt;span class="na"&gt;bwSecretId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_SECRET_ID_1"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-app-key&lt;/span&gt;
      &lt;span class="na"&gt;bwSecretId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_SECRET_ID_2"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-app-webhook-secret&lt;/span&gt;
      &lt;span class="na"&gt;bwSecretId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_SECRET_ID_3"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-app-installation-id&lt;/span&gt;
      &lt;span class="na"&gt;bwSecretId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPLACE_SECRET_ID_4"&lt;/span&gt;
  &lt;span class="na"&gt;authToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bw-auth-token&lt;/span&gt;
    &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Argo CD Application; deploys sm-operator Helm chart&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://charts.bitwarden.com/&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2.0.0&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;settings:&lt;/span&gt;
          &lt;span class="s"&gt;bwSecretsManagerRefreshInterval: 300&lt;/span&gt;
          &lt;span class="s"&gt;cloudRegion: US&lt;/span&gt;
          &lt;span class="s"&gt;replicas: 1&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sm-operator-system&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  7. Validation
&lt;/h3&gt;

&lt;p&gt;After Argo CD syncs the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# BitwardenSecret status&lt;/span&gt;
kubectl get bitwardensecret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl get bitwardensecret bitwarden-secret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.conditions[?(@.type=="SuccessfulSync")].status}'&lt;/span&gt;

&lt;span class="c"&gt;# Output secret keys&lt;/span&gt;
kubectl get secret github-app-secrets &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data}'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'keys[]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: &lt;code&gt;SuccessfulSync&lt;/code&gt; status &lt;code&gt;True&lt;/code&gt; and the mapped keys listed.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Force Sync (Token Refresh)
&lt;/h3&gt;

&lt;p&gt;When the machine token in AWS Secrets Manager changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete secret bw-auth-token &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--grace-period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
kubectl rollout restart deployment/sm-operator-controller-manager &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When only BitwardenSecret mapping changes (e.g. new secrets):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete bitwardensecret bitwarden-secret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
&lt;span class="c"&gt;# Argo CD recreates it; wait for sync&lt;/span&gt;
kubectl annotate bitwardensecret bitwarden-secret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="se"&gt;\&lt;/span&gt;
  force-reconcile&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  9. Summary: Copy-Paste
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Validation (after sync):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get bitwardensecret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl get bitwardensecret bitwarden-secret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.status.conditions[?(@.type=="SuccessfulSync")].status}'&lt;/span&gt;
kubectl get secret github-app-secrets &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data}'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'keys[]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Force sync (machine token changed):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete secret bw-auth-token &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--grace-period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bw-auth-token-sync &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system &lt;span class="nt"&gt;--timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s
kubectl rollout restart deployment/sm-operator-controller-manager &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Force sync (BitwardenSecret mapping changed):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete bitwardensecret bitwarden-secret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system
kubectl annotate bitwardensecret bitwarden-secret &lt;span class="nt"&gt;-n&lt;/span&gt; sm-operator-system force-reconcile&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  10. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Has an invalid identifier&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; One or more &lt;code&gt;bwSecretId&lt;/code&gt; UUIDs are wrong. Verify each ID in Bitwarden Secrets Manager.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; CSI secret not created&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Check Pod Identity for SA &lt;code&gt;awssm-sync&lt;/code&gt; in &lt;code&gt;sm-operator-system&lt;/code&gt;; ensure SecretProviderClass and &lt;code&gt;bw-auth-token-sync&lt;/code&gt; pod exist. Check CSI driver logs: &lt;code&gt;kubectl logs -n kube-system -l app=csi-secrets-store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No changes / Skipping sync&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Delete the BitwardenSecret; Argo recreates it and the operator performs a fresh reconcile.&lt;/p&gt;




&lt;h3&gt;
  
  
  11. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bitwarden.com/help/secrets-manager-kubernetes-operator/" rel="noopener noreferrer"&gt;Bitwarden SM Operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://secrets-store-csi-driver.sigs.k8s.io/" rel="noopener noreferrer"&gt;Secrets Store CSI Driver&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bitwarden</category>
      <category>secretsmanager</category>
      <category>eks</category>
      <category>argocd</category>
    </item>
    <item>
      <title>FastSchema on EKS – Install and Test</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sun, 01 Mar 2026 04:09:39 +0000</pubDate>
      <link>https://dev.to/jajera/fastschema-on-eks-install-and-test-10o3</link>
      <guid>https://dev.to/jajera/fastschema-on-eks-install-and-test-10o3</guid>
      <description>&lt;h2&gt;
  
  
  FastSchema on EKS – Install and Test
&lt;/h2&gt;

&lt;p&gt;Deploy FastSchema via Argo CD on EKS and access it locally with port-forward. Uses SQLite with EBS-backed PVC. First-run setup token from pod logs.&lt;/p&gt;

&lt;p&gt;FastSchema has &lt;strong&gt;no official Helm chart&lt;/strong&gt;. This guide uses a community chart at &lt;a href="https://github.com/k8sforge/fastschema-chart" rel="noopener noreferrer"&gt;k8sforge/fastschema-chart&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This setup is for evaluation, not production-ready. For production, use external database (MySQL/PostgreSQL), configure auth providers, and follow security best practices.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this guide does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploys FastSchema using the community Helm chart via an Argo CD Application&lt;/li&gt;
&lt;li&gt;Persists data with SQLite on EBS-backed PVC&lt;/li&gt;
&lt;li&gt;Uses port-forward for local access (no ingress required)&lt;/li&gt;
&lt;li&gt;Walks through first-run setup: token from pod logs, create admin account, verify storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kubectl configured for your EKS cluster&lt;/li&gt;
&lt;li&gt;Argo CD installed&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before starting, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;kubectl&lt;/strong&gt; configured for your EKS cluster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Argo CD&lt;/strong&gt; installed&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Install FastSchema
&lt;/h3&gt;

&lt;p&gt;Save the manifest below as &lt;code&gt;fastschema-application.yaml&lt;/code&gt; and apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; fastschema-application.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until the Application shows &lt;strong&gt;Synced&lt;/strong&gt; in the Argo CD UI or CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manifest:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AppProject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterResourceWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DevOps-managed applications&lt;/span&gt;
  &lt;span class="na"&gt;destinations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;namespaceResourceWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;sourceRepos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fastschema&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fastschema&lt;/span&gt;
    &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fastschema&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devops&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://k8sforge.github.io/fastschema-chart&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fastschema&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.4&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;service:&lt;/span&gt;
          &lt;span class="s"&gt;type: ClusterIP&lt;/span&gt;
        &lt;span class="s"&gt;persistence:&lt;/span&gt;
          &lt;span class="s"&gt;enabled: true&lt;/span&gt;
          &lt;span class="s"&gt;size: 10Gi&lt;/span&gt;
          &lt;span class="s"&gt;storageClassName: ebs-sc&lt;/span&gt;
          &lt;span class="s"&gt;accessModes:&lt;/span&gt;
            &lt;span class="s"&gt;- ReadWriteOnce&lt;/span&gt;
        &lt;span class="s"&gt;appBaseUrl: "http://localhost:8000"&lt;/span&gt;
        &lt;span class="s"&gt;appDashUrl: "http://localhost:8000/dash"&lt;/span&gt;
        &lt;span class="s"&gt;resources:&lt;/span&gt;
          &lt;span class="s"&gt;limits:&lt;/span&gt;
            &lt;span class="s"&gt;cpu: 500m&lt;/span&gt;
            &lt;span class="s"&gt;memory: 512Mi&lt;/span&gt;
          &lt;span class="s"&gt;requests:&lt;/span&gt;
            &lt;span class="s"&gt;cpu: 100m&lt;/span&gt;
            &lt;span class="s"&gt;memory: 256Mi&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fastschema&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Omit AppProject and Namespace if you already have them (e.g. via devops-apps ApplicationSet).&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Test Access
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Port-forward
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/fastschema &lt;span class="nt"&gt;-n&lt;/span&gt; fastschema 8000:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Get setup token (first run)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; fastschema &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;fastschema &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for: &lt;code&gt;Visit the following URL to setup the app: http://localhost:8000/dash/setup/?token=...&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup and login
&lt;/h4&gt;

&lt;p&gt;Open the URL from the logs. Complete setup to create admin account. Log in at &lt;a href="http://localhost:8000/dash" rel="noopener noreferrer"&gt;http://localhost:8000/dash&lt;/a&gt; with the credentials you created.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Verify EBS Storage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; fastschema deploy/fastschema &lt;span class="nt"&gt;--&lt;/span&gt; sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; /fastschema/data
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /fastschema/data
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"storage-test-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /fastschema/data/storage-test.txt
&lt;span class="nb"&gt;cat&lt;/span&gt; /fastschema/data/storage-test.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit, then from your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; fastschema &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;fastschema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait for the new pod to be ready, exec in again and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /fastschema/data/storage-test.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the file and content persist, the PVC is working.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Summary: Copy-Paste
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Apply manifest&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; fastschema-application.yaml

&lt;span class="c"&gt;# 2. Wait for sync (argocd app get fastschema)&lt;/span&gt;

&lt;span class="c"&gt;# 3. Port-forward and get token&lt;/span&gt;
kubectl port-forward svc/fastschema &lt;span class="nt"&gt;-n&lt;/span&gt; fastschema 8000:8000 &amp;amp;
kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; fastschema &lt;span class="nt"&gt;-l&lt;/span&gt; app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;fastschema &lt;span class="nt"&gt;--tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the setup URL from logs, create admin account, then log in at &lt;a href="http://localhost:8000/dash" rel="noopener noreferrer"&gt;http://localhost:8000/dash&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No setup token in logs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Wait for pod to be ready. Token prints once on startup. If setup already done, use login at /dash with your credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; PVC stuck Pending&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ensure &lt;code&gt;storageClassName: ebs-sc&lt;/code&gt; exists. Check EBS CSI driver is installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Service not found&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; &lt;code&gt;kubectl get svc -n fastschema&lt;/code&gt;. Ensure app is synced.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastSchema&lt;/strong&gt;: &lt;a href="https://fastschema.com" rel="noopener noreferrer"&gt;https://fastschema.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt;: &lt;a href="https://fastschema.com/docs/configuration.html" rel="noopener noreferrer"&gt;https://fastschema.com/docs/configuration.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chart&lt;/strong&gt;: &lt;a href="https://github.com/k8sforge/fastschema-chart" rel="noopener noreferrer"&gt;https://github.com/k8sforge/fastschema-chart&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>fastschema</category>
      <category>eks</category>
      <category>argocd</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Headlamp on EKS – Install and Test</title>
      <dc:creator>John  Ajera</dc:creator>
      <pubDate>Sat, 28 Feb 2026 22:21:50 +0000</pubDate>
      <link>https://dev.to/jajera/headlamp-on-eks-install-and-test-113b</link>
      <guid>https://dev.to/jajera/headlamp-on-eks-install-and-test-113b</guid>
      <description>&lt;h2&gt;
  
  
  Headlamp on EKS – Install and Test
&lt;/h2&gt;

&lt;p&gt;Need a lightweight Kubernetes UI without the overhead of kubectl or cloud consoles? &lt;strong&gt;Headlamp&lt;/strong&gt; runs in-cluster, gives you real-time visibility into workloads, logs, and events—and it's free and open source. This guide deploys it via Argo CD with &lt;strong&gt;Service Account token auth&lt;/strong&gt;: no OIDC setup, no manual secrets, and access via simple port-forward. Secure, easy to run, and GitOps-friendly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This setup uses &lt;code&gt;cluster-admin&lt;/code&gt; for simplicity—ideal for learning or individual use. For production, configure proper role-based access (RBAC) and restrict the Service Account to least-privilege roles.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  1. Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What this guide does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploys Headlamp using the official Helm chart via an Argo CD Application&lt;/li&gt;
&lt;li&gt;Creates a Service Account &lt;code&gt;headlamp&lt;/code&gt; with &lt;code&gt;cluster-admin&lt;/code&gt; for token-based login&lt;/li&gt;
&lt;li&gt;Persists data with EBS-backed PVC&lt;/li&gt;
&lt;li&gt;Uses port-forward for local access (no ingress required)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster running with &lt;strong&gt;kubectl&lt;/strong&gt; context set&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Argo CD&lt;/strong&gt; installed&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before starting, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;kubectl&lt;/strong&gt; configured with context set to your EKS cluster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Argo CD&lt;/strong&gt; installed and syncing Applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Install Headlamp
&lt;/h3&gt;

&lt;p&gt;Save the manifest below as &lt;code&gt;headlamp-application.yaml&lt;/code&gt; and apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; headlamp-application.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Argo CD will create the Application and sync Headlamp. Wait until the Application shows &lt;strong&gt;Synced&lt;/strong&gt; in the Argo CD UI or CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manifest:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AppProject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clusterResourceWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;destinations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;namespaceResourceWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;sourceRepos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headlamp&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headlamp&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headlamp&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes-sigs.github.io/headlamp/&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headlamp&lt;/span&gt;
    &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.40.0&lt;/span&gt;
    &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;service:&lt;/span&gt;
          &lt;span class="s"&gt;type: ClusterIP&lt;/span&gt;
        &lt;span class="s"&gt;config:&lt;/span&gt;
          &lt;span class="s"&gt;inCluster: true&lt;/span&gt;
          &lt;span class="s"&gt;oidc:&lt;/span&gt;
            &lt;span class="s"&gt;secret:&lt;/span&gt;
              &lt;span class="s"&gt;create: false&lt;/span&gt;
        &lt;span class="s"&gt;serviceAccount:&lt;/span&gt;
          &lt;span class="s"&gt;create: true&lt;/span&gt;
          &lt;span class="s"&gt;name: headlamp&lt;/span&gt;
        &lt;span class="s"&gt;clusterRoleBinding:&lt;/span&gt;
          &lt;span class="s"&gt;clusterRoleName: cluster-admin&lt;/span&gt;
        &lt;span class="s"&gt;persistentVolumeClaim:&lt;/span&gt;
          &lt;span class="s"&gt;enabled: true&lt;/span&gt;
          &lt;span class="s"&gt;size: 10Gi&lt;/span&gt;
          &lt;span class="s"&gt;storageClassName: ebs-sc&lt;/span&gt;
          &lt;span class="s"&gt;accessModes:&lt;/span&gt;
            &lt;span class="s"&gt;- ReadWriteOnce&lt;/span&gt;
        &lt;span class="s"&gt;resources:&lt;/span&gt;
          &lt;span class="s"&gt;limits:&lt;/span&gt;
            &lt;span class="s"&gt;cpu: 200m&lt;/span&gt;
            &lt;span class="s"&gt;memory: 256Mi&lt;/span&gt;
          &lt;span class="s"&gt;requests:&lt;/span&gt;
            &lt;span class="s"&gt;cpu: 100m&lt;/span&gt;
            &lt;span class="s"&gt;memory: 128Mi&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headlamp&lt;/span&gt;
  &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateNamespace=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;serviceAccount.create: true&lt;/code&gt; block creates the &lt;code&gt;headlamp&lt;/code&gt; Service Account—this is what &lt;code&gt;kubectl create token headlamp -n headlamp&lt;/code&gt; uses for login. Adjust &lt;code&gt;storageClassName&lt;/code&gt; if your EKS cluster uses a different EBS storage class. Omit the AppProject and Namespace if you already have them.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Test Access
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Port-forward
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/headlamp &lt;span class="nt"&gt;-n&lt;/span&gt; headlamp 8080:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Create token
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create token headlamp &lt;span class="nt"&gt;-n&lt;/span&gt; headlamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Login
&lt;/h4&gt;

&lt;p&gt;Open &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; and paste the token when Headlamp prompts for authentication.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Summary: Copy-Paste
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Apply manifest&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; headlamp-application.yaml

&lt;span class="c"&gt;# 2. Wait for sync (check Argo CD UI or: argocd app get headlamp)&lt;/span&gt;

&lt;span class="c"&gt;# 3. Port-forward and get token&lt;/span&gt;
kubectl port-forward svc/headlamp &lt;span class="nt"&gt;-n&lt;/span&gt; headlamp 8080:80 &amp;amp;
kubectl create token headlamp &lt;span class="nt"&gt;-n&lt;/span&gt; headlamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; and paste the token when prompted.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Application stuck in Syncing or OutOfSync&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Check Argo CD logs and the Application status. Ensure the Headlamp Helm repo is reachable and &lt;code&gt;storageClassName: ebs-sc&lt;/code&gt; exists in your cluster. If using a different storage class, update the manifest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Token invalid or login fails&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ensure the Service Account exists: &lt;code&gt;kubectl get sa headlamp -n headlamp&lt;/code&gt;. Re-run &lt;code&gt;kubectl create token headlamp -n headlamp&lt;/code&gt; to generate a fresh token (tokens expire).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Argo CD ingress stuck or inaccessible&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; See your cluster's Argo CD troubleshooting docs.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headlamp&lt;/strong&gt;: &lt;a href="https://headlamp.dev" rel="noopener noreferrer"&gt;https://headlamp.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installation (Service Account token)&lt;/strong&gt;: &lt;a href="https://headlamp.dev/docs/latest/installation/#create-a-service-account-token" rel="noopener noreferrer"&gt;https://headlamp.dev/docs/latest/installation/#create-a-service-account-token&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Argo CD&lt;/strong&gt;: &lt;a href="https://argo-cd.readthedocs.io/" rel="noopener noreferrer"&gt;https://argo-cd.readthedocs.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>headlamp</category>
      <category>eks</category>
      <category>argocd</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
