<?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: Akhil Anil</title>
    <description>The latest articles on DEV Community by Akhil Anil (@akhil_anil).</description>
    <link>https://dev.to/akhil_anil</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4069654%2F9abe97f9-e379-4604-b48c-be500e97121c.jpg</url>
      <title>DEV Community: Akhil Anil</title>
      <link>https://dev.to/akhil_anil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akhil_anil"/>
    <language>en</language>
    <item>
      <title>How to Set Up Microsoft Entra ID SSO for AWS DevOps Agent</title>
      <dc:creator>Akhil Anil</dc:creator>
      <pubDate>Sun, 23 Aug 2026 09:55:11 +0000</pubDate>
      <link>https://dev.to/akhil_anil/how-to-set-up-microsoft-entra-id-sso-for-aws-devops-agent-2852</link>
      <guid>https://dev.to/akhil_anil/how-to-set-up-microsoft-entra-id-sso-for-aws-devops-agent-2852</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/akhil_anil/how-to-set-up-aws-devops-agent-agent-space-iam-and-multi-account-access-b11"&gt;previous post&lt;/a&gt; I set up AWS DevOps Agent across a couple of AWS accounts — Agent Space, IAM roles, the lot. The bit I left out was login.&lt;/p&gt;

&lt;p&gt;We already use Microsoft Entra ID for everything else, so putting the DevOps Agent web app behind the same SSO was the obvious next step. It took about twenty minutes. Here's the whole thing, start to finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you're actually setting up
&lt;/h2&gt;

&lt;p&gt;It's OIDC, not SAML. AWS DevOps Agent runs an authorization code flow with PKCE against Entra, and you give it four values: issuer, client ID, client secret, and a redirect URI that AWS generates for you.&lt;/p&gt;

&lt;p&gt;Two things stay separate, and it's worth being clear about which is which:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft Entra ID  →  decides WHO can open the web app
AWS IAM roles       →  decide WHAT the agent can read in your accounts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting up SSO changes the front door. It doesn't change anything about what the agent can reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An Agent Space that already exists — the IdP config lives on it&lt;/li&gt;
&lt;li&gt;Permission to create an App Registration and a client secret in Entra&lt;/li&gt;
&lt;li&gt;Admin access to the AWS DevOps Agent console&lt;/li&gt;
&lt;li&gt;The Region your Agent Space is in. I lost five minutes staring at an empty list because I was in the wrong one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need IAM Identity Center. This replaces it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Register an app in Entra
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Entra admin center → Entra ID → App registrations → New registration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three things on the form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; — I used &lt;code&gt;AWS DevOps Agent&lt;/code&gt;. It shows up on the consent screen, so pick something people will recognise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supported account types&lt;/strong&gt; — &lt;em&gt;Accounts in this organizational directory only&lt;/em&gt;. Single tenant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect URI&lt;/strong&gt; — leave it blank.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one feels wrong, but AWS won't give you the redirect URI until the IdP is connected, so you have to come back for it in Step 4.&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Register&lt;/strong&gt;, then grab two values off the Overview page: &lt;strong&gt;Application (client) ID&lt;/strong&gt; and &lt;strong&gt;Directory (tenant) ID&lt;/strong&gt;.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0p7vuzy6ig5he0m0rls.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0p7vuzy6ig5he0m0rls.png" alt="Microsoft Entra admin center, App registration Overview page for an app named AWS DevOps Agent. The Essentials panel shows Supported account types set to My organization only, Client credentials showing one secret, and Redirect URIs showing one web URI. The client ID, object ID and tenant ID are redacted." width="799" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Create a client secret
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Certificates &amp;amp; secrets → Client secrets → New client secret&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a description, pick an expiry, hit &lt;strong&gt;Add&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now the part that trips people up: the table shows a &lt;strong&gt;Value&lt;/strong&gt; and a &lt;strong&gt;Secret ID&lt;/strong&gt;. AWS wants the &lt;strong&gt;Value&lt;/strong&gt;. Copy it now — it's masked the moment you leave the page and there's no way to get it back.&lt;/p&gt;

&lt;p&gt;On expiry, Entra caps you at 24 months and &lt;a href="https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-credentials" rel="noopener noreferrer"&gt;recommends under 12&lt;/a&gt;. I went with the maximum, which I'd now do differently — AWS has a &lt;em&gt;Rotate client secret&lt;/em&gt; button that doesn't disconnect anything, so rotation is cheap. Whatever you pick, put the date in a calendar. When the secret expires, nobody can log in, and there's no warning anywhere in the AWS console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Connect it in AWS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DevOps Agent console → Agent Spaces → your space → Access tab → User access → External identity provider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Four fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What goes in it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Identity Provider&lt;/td&gt;
&lt;td&gt;Microsoft Entra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Issuer URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://login.microsoftonline.com/&amp;lt;TENANT_ID&amp;gt;/v2.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client ID&lt;/td&gt;
&lt;td&gt;Application (client) ID from Step 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client Secret&lt;/td&gt;
&lt;td&gt;the secret &lt;strong&gt;Value&lt;/strong&gt; from Step 2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The issuer has to be the tenant-specific v2.0 URL. Not &lt;code&gt;common&lt;/code&gt;, not without the &lt;code&gt;/v2.0&lt;/code&gt;, no trailing slash.&lt;/p&gt;

&lt;p&gt;There's also a role option below — auto-create, use existing, or from a template. Auto-create is fine here; this role is just for the web app and isn't the one reaching into your other accounts.&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Connect&lt;/strong&gt;. AWS immediately shows you two URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Callback URL:  https://&amp;lt;AGENT_SPACE_ID&amp;gt;.aidevops.global.app.aws/authorizer/idp/callback
Login URL:     https://&amp;lt;AGENT_SPACE_ID&amp;gt;.aidevops.global.app.aws/authorizer/idp/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the callback URL.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdqhb67tbjvrpiqpn4de.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdqhb67tbjvrpiqpn4de.png" alt="AWS DevOps Agent console, Access tab, showing the External Identity Provider Configuration panel. Provider is Microsoft Entra, with a Callback URL ending in /authorizer/idp/callback and a Login URL ending in /authorizer/idp/login, plus Rotate client secret and Disconnect buttons. The tenant ID, client ID, Agent Space hostnames and IAM role ARN are redacted." width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Paste the redirect URI back into Entra
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;App Registration → Authentication → Add a platform → Web&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Paste the callback URL. Platform type &lt;strong&gt;Web&lt;/strong&gt;, not SPA — the token exchange happens server-side with the client secret.&lt;/p&gt;

&lt;p&gt;Paste it, don't retype it. Entra matches the redirect URI exactly, the path is case-sensitive, and there's no trailing slash. Get it wrong and you'll get &lt;code&gt;AADSTS50011&lt;/code&gt; at login, which at least tells you what's broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 — Restrict who can log in
&lt;/h2&gt;

&lt;p&gt;Easy to skip, and worth thirty seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise applications → your app → Properties → Assignment required? → Yes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then &lt;strong&gt;Users and groups → Add user/group&lt;/strong&gt; and assign a group.&lt;/p&gt;

&lt;p&gt;Assigning people without flipping that toggle does nothing — it defaults to &lt;strong&gt;No&lt;/strong&gt;, and any account in your tenant can sign in. Since opening the web app &lt;em&gt;is&lt;/em&gt; the access control for a shared Agent Space, this is the setting that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 — Test it
&lt;/h2&gt;

&lt;p&gt;Open the &lt;strong&gt;Login URL&lt;/strong&gt; in a private window. Use private browsing — with an existing Microsoft session it all happens too fast to tell whether it actually worked.&lt;/p&gt;

&lt;p&gt;This is the AWS-hosted hand-off page, and the one your team will actually meet day to day once a session has lapsed. &lt;strong&gt;Log in with SSO&lt;/strong&gt; starts the flow:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyuxo9n2wn6xkfz8yz0ha.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyuxo9n2wn6xkfz8yz0ha.png" alt="The AWS DevOps Agent sign-in page, showing a shield icon, the heading Credentials expired, and a Log in with SSO button." width="799" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From a clean session the Login URL skips straight past it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Login URL
   ↓  straight to Microsoft, no AWS login page
Microsoft sign-in + your usual MFA
   ↓  consent prompt (first time only)
AWS DevOps Agent, logged in
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS never asks for a username or password of its own — credentials only ever get typed on Microsoft’s side. If anything other than Microsoft prompts you for one, something is wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it doesn't work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AADSTS50011&lt;/code&gt;&lt;/strong&gt; — redirect URI mismatch. Compare the two character by character, including case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login works, app then errors&lt;/strong&gt; — same thing. Recheck the redirect URI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"IdP configuration error"&lt;/strong&gt; — no refresh token came back. Add &lt;code&gt;offline_access&lt;/code&gt; as a delegated Microsoft Graph permission on the app registration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fails before Microsoft even loads&lt;/strong&gt; — issuer URL is wrong. And note you can't edit it: AWS only lets you change the client secret after connecting, everything else means disconnect and reconnect. Disconnecting also wipes chat and artifact history, so get it right the first time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worked yesterday, dead today&lt;/strong&gt; — check the client secret expiry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing works and the secret looks right&lt;/strong&gt; — make sure you pasted the Value and not the Secret ID. They sit next to each other and look identical.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocked by policy&lt;/strong&gt; — check the Enterprise Application's Sign-in logs before touching anything in AWS. Conditional Access failures show up there with a real error code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more: don't add a groups claim under Token configuration. AWS doesn't use group membership and it causes authentication failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus — a nicer URL
&lt;/h2&gt;

&lt;p&gt;The web app lives at &lt;code&gt;https://&amp;lt;AGENT_SPACE_ID&amp;gt;.aidevops.global.app.aws&lt;/code&gt;. Nobody is remembering that, and it looks like phishing when you paste it in Slack. So we put a small Nginx pod in front of it and gave the team &lt;code&gt;devops-agent.&amp;lt;YOUR_DOMAIN&amp;gt;&lt;/code&gt; instead. Convenience only — the real boundary is still Entra.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;devops-agent.&amp;lt;YOUR_DOMAIN&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# variable + resolver, so Nginx re-resolves DNS at runtime instead of&lt;/span&gt;
        &lt;span class="c1"&gt;# caching the CloudFront IPs forever at startup&lt;/span&gt;
        &lt;span class="kn"&gt;resolver&lt;/span&gt; &lt;span class="mf"&gt;8.8&lt;/span&gt;&lt;span class="s"&gt;.8.8&lt;/span&gt; &lt;span class="s"&gt;valid=30s&lt;/span&gt; &lt;span class="s"&gt;ipv6=off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;$upstream&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;AGENT_SPACE_ID&amp;gt;.aidevops.global.app.aws"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# upstream needs both SNI and Host set to its own name&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$upstream&lt;/span&gt;&lt;span class="n"&gt;/authorizer/idp/login&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_ssl_server_name&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$upstream&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;Note it points at the login path, not &lt;code&gt;/&lt;/code&gt;. This is a front door, not a proxy for the whole app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The one thing to know:&lt;/strong&gt; don’t add your custom domain as a redirect URI in Entra. AWS builds the &lt;code&gt;redirect_uri&lt;/code&gt; from the Agent Space ID, so the login always comes back to the AWS hostname whichever door you walked in through. Your domain never appears in the OAuth flow at all.&lt;/p&gt;

&lt;p&gt;A plain &lt;code&gt;return 302&lt;/code&gt; to the login URL does the same job in one line, if you would rather skip the proxy. You land on the AWS URL either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The whole thing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        devops-agent.&amp;lt;YOUR_DOMAIN&amp;gt;
                    │
                    ▼
              Nginx (EKS)
                    │
                    ▼
        AWS DevOps Agent Agent Space
           │                    │
           ▼                    ▼
    Microsoft Entra ID      IAM roles
      (who logs in)      (what it can read)
                              │
                        ┌─────┴─────┐
                        ▼           ▼
                       Dev         Prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Entra handles the login, IAM handles the access, and the team just bookmarks one short URL.&lt;/p&gt;

&lt;p&gt;If you want the IAM and multi-account half — trust policies, Terraform, connecting secondary accounts — that's all in the &lt;a href="https://dev.to/akhil_anil/how-to-set-up-aws-devops-agent-agent-space-iam-and-multi-account-access-b11"&gt;previous post&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awsdevopsagent</category>
      <category>authentication</category>
      <category>microsoftentraid</category>
    </item>
    <item>
      <title>How to Set Up AWS DevOps Agent: Agent Space, IAM, and Multi-Account Access</title>
      <dc:creator>Akhil Anil</dc:creator>
      <pubDate>Sun, 16 Aug 2026 09:29:51 +0000</pubDate>
      <link>https://dev.to/akhil_anil/how-to-set-up-aws-devops-agent-agent-space-iam-and-multi-account-access-b11</link>
      <guid>https://dev.to/akhil_anil/how-to-set-up-aws-devops-agent-agent-space-iam-and-multi-account-access-b11</guid>
      <description>&lt;p&gt;I set up AWS DevOps Agent a while back across our AWS Organizations environment — a central account running the Agent Space, with development and production connected to it — and did the IAM side in Terraform rather than clicking through the console.&lt;/p&gt;

&lt;p&gt;This is the walkthrough I wanted when I started: what the moving parts actually are, the order to do them in, and the four or five places where the documented happy path doesn't match what happens.&lt;/p&gt;

&lt;p&gt;If you just want the official steps, the AWS user guide is good and I'll link the relevant pages as I go. What follows is that path plus the friction.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AWS DevOps Agent is, briefly
&lt;/h2&gt;

&lt;p&gt;It went generally available at the end of March 2026. Two halves: &lt;strong&gt;release management&lt;/strong&gt; (still preview — code review, release readiness, autonomous testing) and &lt;strong&gt;production operations&lt;/strong&gt;, which is the part I actually use.&lt;/p&gt;

&lt;p&gt;Production operations does four things: investigates incidents when an alert arrives, produces mitigation plans, surfaces preventative recommendations from patterns across your incident history, and answers on-demand SRE questions conversationally.&lt;/p&gt;

&lt;p&gt;The useful mental model isn't "AI in the AWS console." It's a &lt;strong&gt;read-only correlation layer over infrastructure you already have instrumented&lt;/strong&gt;. During an incident I normally open CloudWatch, RDS metrics, EC2, the EKS console, load balancer health, Logs Insights, and deployment history — and only &lt;em&gt;then&lt;/em&gt; start thinking. The agent collapses the collecting part. It doesn't generate telemetry, and if your observability is thin it just gets you to an incomplete picture faster.&lt;/p&gt;

&lt;p&gt;Three concepts you need before any of the setup makes sense:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent Space&lt;/strong&gt; — the container and the access boundary. It defines which AWS accounts, which integrations, and which users the agent can reach. Investigation history and chat history are isolated per Agent Space. Agent Spaces are regional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Topology&lt;/strong&gt; — what the agent builds after you connect an account. It's a graph of your resources and their relationships, and it's what lets the agent reason about blast radius instead of just reading metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IAM roles&lt;/strong&gt; — how it reaches anything at all. The agent never uses your credentials. It assumes roles you create, using the service principal &lt;code&gt;aidevops.amazonaws.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One structural thing that confused me for the first ten minutes: &lt;strong&gt;there are two consoles.&lt;/strong&gt; Administrators configure Agent Spaces in the AWS Management Console. Operators run investigations in a separate &lt;strong&gt;web app&lt;/strong&gt;, with its own IAM role and its own auth flow. So you're creating two roles before you've connected a second account.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start clicking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A supported Region.&lt;/strong&gt; Six of them: N. Virginia, Oregon, Frankfurt, Ireland, Sydney, Tokyo. The Agent Space stores its data in the Region where you create it, so pick with data residency in mind — this isn't easily changed later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IAM permissions to create roles&lt;/strong&gt;, in every account you plan to connect. The console's auto-create option needs this in the primary account; secondary accounts need it wherever you create the cross-account role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;iam:PassRole&lt;/code&gt; in the primary account&lt;/strong&gt; — only needed if you're connecting secondary accounts, but get it in place early. More on why below, because this one produces a genuinely confusing error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A decision about console vs. infrastructure-as-code.&lt;/strong&gt; The console's auto-create path is the fastest way to a working Agent Space and it's what I'd use to evaluate the service. It's not what I'd want owning cross-account trust into production long-term. You can start with auto-create and move to IaC later; you can't easily reconstruct why a hand-clicked trust policy says what it says.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Awareness that this costs money.&lt;/strong&gt; Pay-per-second, no commitment, billing started April 10, 2026. AWS Support customers get monthly credits scaled to their support tier. Worth checking what your tier includes before you turn it loose on a large estate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — Create the Agent Space
&lt;/h2&gt;

&lt;p&gt;In the AWS DevOps Agent console, choose &lt;strong&gt;Create Agent Space&lt;/strong&gt;. You give it a name, an optional description, and an optional response language (it defaults to matching the language of your input).&lt;/p&gt;

&lt;p&gt;Then two sections that both create IAM roles, and this is the real decision point of the whole setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Give this Agent Space AWS resource access"&lt;/strong&gt; — the role the agent uses to investigate resources in the primary account. Three options: auto-create a role, assign an existing role, or build one from a policy template. Auto-create is the recommended default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Enable web app"&lt;/strong&gt; — the operator role, for the separate web app where investigations actually happen. Same three options.&lt;br&gt;
Then &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The moment the space exists, it starts scanning the account for resources and relationships. That takes a few minutes. Once it's done, &lt;strong&gt;Operator access&lt;/strong&gt; appears on the Agent Space details page and opens the web app in a new tab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd do differently on a second run:&lt;/strong&gt; use auto-create for the web app role and a pre-created role for resource access. The web app role is boring and account-local. The resource access role is the one that matters, the one you'll want to reason about later, and the one whose ARN you'll need again for anything you connect later.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 2 — Understand the IAM before you accept it
&lt;/h2&gt;

&lt;p&gt;Auto-create is convenient and I'd still recommend it for a first look, but you should know what it's building, because the same three components appear in every account you ever connect.&lt;/p&gt;
&lt;h3&gt;
  
  
  The trust policy
&lt;/h3&gt;

&lt;p&gt;The role trusts the AWS DevOps Agent service principal directly:&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;"Principal"&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;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aidevops.amazonaws.com"&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;"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;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&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;"StringEquals"&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;"aws:SourceAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;PRIMARY_ACCOUNT_ID&amp;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;"ArnLike"&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;"aws:SourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:aidevops:&amp;lt;REGION&amp;gt;:&amp;lt;PRIMARY_ACCOUNT_ID&amp;gt;:agentspace/*"&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;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;Those two conditions are the entire security story. &lt;code&gt;aws:SourceAccount&lt;/code&gt; and &lt;code&gt;aws:SourceArn&lt;/code&gt; are &lt;strong&gt;confused deputy prevention&lt;/strong&gt; — without them, the service principal is a wide-open door, because &lt;code&gt;aidevops.amazonaws.com&lt;/code&gt; is the same principal in every AWS account on earth. The conditions are what say "only an Agent Space in &lt;em&gt;my&lt;/em&gt; account may use this role."&lt;/p&gt;

&lt;p&gt;The operator role's trust policy is nearly identical but needs &lt;code&gt;sts:TagSession&lt;/code&gt; alongside &lt;code&gt;sts:AssumeRole&lt;/code&gt;, because the web app scopes access using a session tag (&lt;code&gt;aws:PrincipalTag/AgentSpaceId&lt;/code&gt;). If you're hand-building that one and it fails, missing &lt;code&gt;TagSession&lt;/code&gt; is the reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  The permissions
&lt;/h3&gt;

&lt;p&gt;Attach the AWS-managed &lt;strong&gt;&lt;code&gt;AIDevOpsAgentAccessPolicy&lt;/code&gt;&lt;/strong&gt; for resource access — read-only permissions for discovery, configuration and metric reads, and log analysis. The operator role gets &lt;strong&gt;&lt;code&gt;AIDevOpsOperatorAppAccessPolicy&lt;/code&gt;&lt;/strong&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  The bit everyone forgets
&lt;/h3&gt;

&lt;p&gt;A small inline policy allowing &lt;code&gt;iam:CreateServiceLinkedRole&lt;/code&gt;, scoped to the Resource Explorer service-linked role:&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;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowCreateServiceLinkedRoles"&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="s2"&gt;"iam:CreateServiceLinkedRole"&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="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::&amp;lt;ACCOUNT_ID&amp;gt;:role/aws-service-role/resource-explorer-2.amazonaws.com/AWSServiceRoleForResourceExplorer"&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;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;This is what lets the agent bootstrap Resource Explorer in the account. Skip it and the setup still succeeds — you just get a much thinner topology and no obvious error telling you why. It goes on &lt;strong&gt;every&lt;/strong&gt; role, in every account, primary and secondary.&lt;/p&gt;

&lt;p&gt;Why it matters: the agent discovers resources two ways — by walking CloudFormation stacks, and via Resource Explorer for everything else. &lt;strong&gt;If you're a Terraform shop, that second path is doing nearly all the work&lt;/strong&gt;, because none of your infrastructure is in CloudFormation. Resource Explorer largely sets itself up once this policy is in place, and it indexes off &lt;strong&gt;tags&lt;/strong&gt;, so inconsistent tagging gives you an inconsistent topology. Give it time before you panic: tagged resources show up within minutes, untagged ones can take up to two hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Connect the primary AWS account
&lt;/h2&gt;

&lt;p&gt;If you used the console flow, this already happened — creating the Agent Space with a resource access role associates the primary account for you.&lt;/p&gt;

&lt;p&gt;If you're doing it via CLI or IaC, it's an explicit association, and the thing to notice is &lt;code&gt;accountType&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws devops-agent associate-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-space-id&lt;/span&gt; &amp;lt;AGENT_SPACE_ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-id&lt;/span&gt; aws &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--configuration&lt;/span&gt; &lt;span class="s1"&gt;'{
    "aws": {
      "assumableRoleArn": "arn:aws:iam::&amp;lt;PRIMARY_ACCOUNT_ID&amp;gt;:role/&amp;lt;AGENT_SPACE_ROLE&amp;gt;",
      "accountId": "&amp;lt;PRIMARY_ACCOUNT_ID&amp;gt;",
      "accountType": "monitor"
    }
  }'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;REGION&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;monitor&lt;/code&gt; is the primary account that hosts the Agent Space. &lt;code&gt;source&lt;/code&gt; is every additional account. You'll use &lt;code&gt;source&lt;/code&gt; in step 5.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 — Verify the primary account works
&lt;/h2&gt;

&lt;p&gt;Three checks, in increasing order of how much I trust them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One — the association exists:&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;aws devops-agent list-associations &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent-space-id&lt;/span&gt; &amp;lt;AGENT_SPACE_ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;REGION&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Two — the topology has something in it.&lt;/strong&gt; Open the web app via &lt;strong&gt;Operator access&lt;/strong&gt;, go to the Topology page, and switch to the &lt;strong&gt;System&lt;/strong&gt; view, which shows account and Region boundaries. Then &lt;strong&gt;All Resources&lt;/strong&gt; to see whether discovery actually found your estate. Empty here means Resource Explorer, tags, or patience — in that order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three — ask it something only a working connection can answer.&lt;/strong&gt; Not "what can you do," but something specific to a real resource: &lt;em&gt;"list the RDS instances in this account and their instance classes."&lt;/em&gt; If it answers with your actual inventory, the role works. This is the only check I fully trust, because the first two can pass while the agent still can't read anything useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — Connect additional AWS accounts
&lt;/h2&gt;

&lt;p&gt;This is where most real deployments end up, because applications rarely live in one account.&lt;/p&gt;

&lt;h3&gt;
  
  
  The trust model
&lt;/h3&gt;

&lt;p&gt;The important thing to understand — and it's not obvious from the console flow — is that &lt;strong&gt;the agent does not assume a role in the primary account and then chain into the second account.&lt;/strong&gt; The AWS DevOps Agent service principal assumes the role in the secondary account &lt;strong&gt;directly&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS DevOps Agent  (aidevops.amazonaws.com)
        │
        │ sts:AssumeRole
        ├──────────────► DevOpsAgentRole (Secondary Account A)
        │                     ├── AIDevOpsAgentAccessPolicy
        │                     └── inline: Resource Explorer SLR
        │
        └──────────────► DevOpsAgentRole (Secondary Account B)
                              ├── AIDevOpsAgentAccessPolicy
                              └── inline: Resource Explorer SLR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no role in the middle. What restricts it is the trust policy conditions — the same &lt;code&gt;aws:SourceAccount&lt;/code&gt; and &lt;code&gt;aws:SourceArn&lt;/code&gt; pair, pointing at the primary account and its Agent Space.&lt;/p&gt;

&lt;h3&gt;
  
  
  The console path
&lt;/h3&gt;

&lt;p&gt;Agent Space → &lt;strong&gt;Capabilities&lt;/strong&gt; tab → &lt;strong&gt;Cloud&lt;/strong&gt; section → &lt;strong&gt;Secondary sources&lt;/strong&gt; → &lt;strong&gt;Add&lt;/strong&gt;. You name the role, and the console hands you a trust policy and an inline policy. You take both to the IAM console in the target account, create a custom-trust-policy role, paste the trust policy, attach &lt;code&gt;AIDevOpsAgentAccessPolicy&lt;/code&gt;, name the role exactly what you told the console it would be called, create it, then add the inline policy. Back in the primary account, choose &lt;strong&gt;Next&lt;/strong&gt; and confirm the status shows &lt;strong&gt;Active&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It works. It's also a lot of clipboard for something that grants cross-account read access to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  The gotcha that will cost you twenty minutes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The principal adding a secondary account needs &lt;code&gt;iam:PassRole&lt;/code&gt; in the primary account.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This fails with an HTTP 403 &lt;code&gt;AccessDeniedException&lt;/code&gt; naming &lt;code&gt;iam:PassRole&lt;/code&gt; — &lt;em&gt;even if that principal already has full `aidevops:&lt;/em&gt;`*. And the fix has a trap in it:&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;"iam:PassRole"&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;"arn:aws:iam::&amp;lt;PRIMARY_ACCOUNT_ID&amp;gt;:role/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&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;"StringEquals"&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;"iam:PassedToService"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aidevops.amazonaws.com"&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;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;The &lt;code&gt;Resource&lt;/code&gt; must be the &lt;strong&gt;role wildcard&lt;/strong&gt;. A policy scoped to specific role ARNs does &lt;em&gt;not&lt;/em&gt; satisfy the check — the check itself is performed against the wildcard. This is counterintuitive if you've been trained to scope everything, and it's the kind of thing you'll spend a while assuming you got the ARN wrong.&lt;/p&gt;

&lt;p&gt;Also: &lt;strong&gt;the check re-runs every time you update a secondary account&lt;/strong&gt;, not just when you add one. Already-connected accounts keep working until the next update, so this can surface weeks later.&lt;/p&gt;




&lt;h2&gt;
  
  
  My setup: one Agent Space, Dev and Prod
&lt;/h2&gt;

&lt;p&gt;Here's how it looks in my environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Organization / Management Account
                       │
             AWS DevOps Agent Agent Space
                       │
              ┌────────┴────────┐
              │                 │
        Development         Production
          Account             Account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One Agent Space in a central account, with dev and prod connected as secondary sources. Each target account has &lt;strong&gt;its own&lt;/strong&gt; role — not a shared one — so permissions can diverge later, the two show up as distinct principals in CloudTrail, and revoking one environment means deleting one role.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why one Agent Space instead of one per environment
&lt;/h3&gt;

&lt;p&gt;I could have built two. AWS's documentation actually nudges you that way — it lists &lt;em&gt;"environment isolation: separate production from non-production"&lt;/em&gt; as a reason to create multiple Agent Spaces.&lt;/p&gt;

&lt;p&gt;I went with one because a lot of my real investigations don't respect the account boundary. &lt;em&gt;"This started after last night's deploy"&lt;/em&gt; begins in dev and lands in prod. &lt;em&gt;"Why is prod behaving differently under the same query pattern?"&lt;/em&gt; is inherently a comparison. Two Agent Spaces would put me back to being the integration layer between two tools that can't see each other — which is exactly the problem I was trying to reduce.&lt;/p&gt;

&lt;p&gt;Secondary benefits: one place to look, one topology, integrations configured once instead of per environment, and adding the next account is three Terraform resources rather than a new setup project. Account separation is completely untouched — dev and prod are still separate AWS accounts with separate roles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The trade you're making, stated plainly:&lt;/strong&gt; operator access and investigation data are both scoped per Agent Space, not per connected account. Anyone who can open the web app can ask about every account in that space. There's no "dev-only operator" tier inside a space. Concurrency is shared too — the defaults are 3 concurrent investigations and 10 concurrent chat invocations per space, both adjustable.&lt;/p&gt;

&lt;p&gt;For me that's fine, because &lt;strong&gt;web app access is restricted to the DevOps team and that team already holds production authority.&lt;/strong&gt; Developers don't get an operator login. When the set of people allowed to investigate dev is identical to the set allowed to investigate prod, per-environment isolation is guarding a boundary that doesn't exist in the org chart.&lt;/p&gt;

&lt;p&gt;So the decision rule isn't "always separate prod." It's &lt;strong&gt;"do the same humans investigate both?"&lt;/strong&gt; If developers self-serve investigations in dev while a separate group owns prod, split the spaces — the isolation is doing real work there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I did the IAM in Terraform
&lt;/h3&gt;

&lt;p&gt;Cross-account trust into production, created by hand from a clipboard, with no diff and no review, is the kind of thing that's correct on day one and mysterious on day ninety.&lt;/p&gt;

&lt;p&gt;The shape is one aliased provider per target account and three resources in each:&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;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;alias&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-central-1"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::&amp;lt;DEV_ACCOUNT_ID&amp;gt;:role/&amp;lt;DEPLOY_ROLE&amp;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;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;alias&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"prod"&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-central-1"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::&amp;lt;PROD_ACCOUNT_ID&amp;gt;:role/&amp;lt;DEPLOY_ROLE&amp;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;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;agent_space_account&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;MANAGEMENT_ACCOUNT_ID&amp;gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;agent_space_arn&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:aidevops:eu-central-1:&amp;lt;MANAGEMENT_ACCOUNT_ID&amp;gt;:agentspace/&amp;lt;AGENT_SPACE_ID&amp;gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alias &lt;em&gt;every&lt;/em&gt; provider and leave no default. An unaliased default provider in a config that touches production IAM means any resource where someone forgets the &lt;code&gt;provider&lt;/code&gt; argument silently lands wherever the default points.&lt;/p&gt;

&lt;p&gt;Then, per account:&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;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_caller_identity"&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev&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"&lt;/span&gt; &lt;span class="s2"&gt;"devops_agent_access_dev"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev&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;"AIDevOpsAgentAccessPolicy"&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"&lt;/span&gt; &lt;span class="s2"&gt;"devops_agent_dev"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev&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;"DevOpsAgentRole-AgentSpace-dev"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_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;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aidevops.amazonaws.com"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;Action&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;
      &lt;span class="nx"&gt;Condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;StringEquals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"aws:SourceAccount"&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;agent_space_account&lt;/span&gt;
          &lt;span class="s2"&gt;"aws:SourceArn"&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;agent_space_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="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_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"devops_agent_access_dev"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev&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;devops_agent_dev&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;devops_agent_access_dev&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="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy"&lt;/span&gt; &lt;span class="s2"&gt;"devops_agent_dev_slr"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dev&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;"AllowCreateResourceExplorerServiceLinkedRole"&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;devops_agent_dev&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&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;Sid&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AllowCreateServiceLinkedRoles"&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;"iam:CreateServiceLinkedRole"&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="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"arn:aws:iam::${data.aws_caller_identity.dev.account_id}:role/aws-service-role/resource-explorer-2.amazonaws.com/AWSServiceRoleForResourceExplorer"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details worth copying:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;StringEquals&lt;/code&gt; on &lt;code&gt;aws:SourceArn&lt;/code&gt;, not &lt;code&gt;ArnLike&lt;/code&gt; with &lt;code&gt;agentspace/*&lt;/code&gt;.&lt;/strong&gt; The docs use the wildcard because on the &lt;em&gt;primary&lt;/em&gt; role you have a chicken-and-egg problem — the space doesn't exist yet. For secondary accounts it already does, so pin the exact ARN. It costs nothing, and it means a second Agent Space created in that account tomorrow, by someone else, cannot reach production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;data.aws_caller_identity&lt;/code&gt; instead of a hardcoded account ID&lt;/strong&gt; in the service-linked-role ARN. It has to resolve to the account the role lives in. Paste the number by hand and a future provider change gives you a policy pointing at the wrong account and an SLR failure with an unhelpful error.&lt;/p&gt;

&lt;p&gt;The prod block is the same three resources against &lt;code&gt;aws.prod&lt;/code&gt;. Right now that's literal duplication; the module refactor happens when the third account arrives. Two copies didn't justify the indirection.&lt;/p&gt;

&lt;p&gt;What this buys: the trust relationship is reviewable in a pull request, drift is visible, and there's a git history explaining why production trusts one specific Agent Space ARN. The associations can be code too — there are &lt;code&gt;awscc&lt;/code&gt; provider resources for the agent space and its associations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running a first real investigation
&lt;/h2&gt;

&lt;p&gt;Once both accounts were connected, the test I used was a question I've genuinely asked during incidents: &lt;strong&gt;"Why did database connections drop around 14:30 yesterday?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The manual version of that investigation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CloudWatch alarm history
        ↓
RDS connection + CPU metrics for the window
        ↓
application logs in CloudWatch Logs Insights
        ↓
deployment history — did anything ship?
        ↓
security groups / subnets / NAT — did networking change?
        ↓
CloudTrail — did anyone change a config?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six places, each requiring me to hold the previous answer in my head while navigating to the next. Roughly twenty minutes before I have a hypothesis.&lt;/p&gt;

&lt;p&gt;The agent-assisted version is the same investigation with the fetching collapsed. I describe the symptom and the window; it pulls the metrics, checks the topology for what's connected to that database, looks at deployment data if a pipeline is connected, and returns a correlated picture with its reasoning trail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get is a starting hypothesis and the evidence behind it&lt;/strong&gt; — not a verdict. Sometimes it lands on the cause. Sometimes it surfaces a correlation that turns out to be coincidental, and I only catch that because I know the system. It has never removed the need for me to understand what a connection pool is.&lt;/p&gt;

&lt;p&gt;Every reasoning step lands in an immutable agent journal, and API calls land in CloudTrail. That matters practically, not just for compliance: an answer you can't audit is an answer you can't act on at 3am.&lt;/p&gt;

&lt;p&gt;Where it's earned the most in my day-to-day:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RDS&lt;/strong&gt; — CPU spikes, connection swings, memory pressure, whether utilisation matches the instance class. The win isn't that it knows something I don't; it's that "pull these five metrics over this window and tell me what's unusual" is one sentence instead of five console navigations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EKS&lt;/strong&gt; — because Kubernetes incidents so often aren't Kubernetes incidents. A pod that can't reach a database has a problem living in RDS, a security group, a route table, or an IAM policy. Asking about the pod and the AWS-side dependency in one conversation removes a real context switch. One caveat if you're following along: EKS needs an extra step beyond the IAM role above — an access entry on the cluster for the agent's role — which I'll cover in a separate post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource sizing, carefully.&lt;/strong&gt; AWS documents preventative recommendations spanning observability, infrastructure optimisation, pipelines, and resilience. I use the agent as &lt;em&gt;one input&lt;/em&gt; when asking whether something looks oversized — it assembles the utilisation picture fast. It is not a rightsizing engine, and I still cross-check against Compute Optimizer, Cost Explorer, and actual knowledge of the workload's traffic shape.&lt;/p&gt;




&lt;h2&gt;
  
  
  Things I learned, and things to watch
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Nothing in my stack got turned off.&lt;/strong&gt; Prometheus and Grafana still hold my dashboards. CloudWatch still holds the AWS-native signal. Alerting still fires, logs and traces are where they were, Terraform still owns the infrastructure, &lt;code&gt;kubectl&lt;/code&gt; is still open in a terminal. The agent reads what already exists — it's a correlation layer over your observability, not a replacement for it. Getting that ordering backwards is the most reliable way to be disappointed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Onboard dev first and live with it.&lt;/strong&gt; Same reason you don't test a restore for the first time during an outage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decide who can open the web app before you connect production, not after.&lt;/strong&gt; In a shared Agent Space this is &lt;em&gt;the&lt;/em&gt; control, because operator access is per-space. I wired the operator app to our corporate identity provider through the external IdP flow — Microsoft Entra ID — so access follows the same directory groups and MFA policy as everything else, and offboarding someone removes their agent access with their email. IAM Identity Center is the other first-class option; raw IAM authentication links with their 10-minute sessions are the fallback. That setup has enough moving parts that it deserves its own post, which I'll write separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PII in logs is your problem.&lt;/strong&gt; AWS states PII is not automatically filtered and recommends redaction. If your application logs contain customer data, the agent can read it during log analysis. For anyone in a regulated industry, that's a conversation to have before onboarding, not after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think about where the Agent Space lives.&lt;/strong&gt; Mine sits in the central org account, which is convenient and which I'd revisit. AWS's own guidance leans toward a &lt;em&gt;dedicated&lt;/em&gt; account as primary with application accounts attached as secondaries, and general Organizations practice keeps workloads out of the management account. Designing from scratch, I'd put it in a dedicated tooling account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Removing a secondary account does not delete the IAM role.&lt;/strong&gt; Cleanup is on you — or on Terraform, which is one more argument for managing it as code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the quotas against your reality.&lt;/strong&gt; 3 concurrent investigations and 10 concurrent chat invocations per Agent Space by default, both adjustable. 100 Agent Spaces per account per Region. Fine for most teams, worth a look if you're planning something large.&lt;/p&gt;




&lt;h2&gt;
  
  
  Worth it?
&lt;/h2&gt;

&lt;p&gt;Setup is genuinely about an hour for a single account, and maybe a couple of hours for a multi-account setup done properly in Terraform with the IAM reviewed rather than clicked.&lt;/p&gt;

&lt;p&gt;What I'd tell someone evaluating it: the value shows up in the &lt;strong&gt;first ten minutes&lt;/strong&gt; of an investigation, and drops off sharply after that. The mechanical phase — open the consoles, pull the metrics, line up timestamps, check the deploys — compresses. The reasoning phase doesn't, and shouldn't.&lt;/p&gt;

&lt;p&gt;I don't think AI agents reduce how much AWS, Kubernetes, networking, or database internals you need to know. If anything they raise it, because the new skill is judging whether the agent's reasoning holds up. A confident, wrong correlation is only dangerous to someone who can't tell.&lt;/p&gt;

&lt;p&gt;But the evidence-gathering phase was always the least valuable part of the job, and it's the first part that's turned out to be automatable. That's a smaller claim than the marketing makes, and it's the one I'd actually stand behind.&lt;/p&gt;




</description>
      <category>aws</category>
      <category>devops</category>
      <category>ai</category>
      <category>awsdevopsagent</category>
    </item>
    <item>
      <title>AI Didn't Replace My DevOps Workflow. It Shortened the Path to a Hypothesis.</title>
      <dc:creator>Akhil Anil</dc:creator>
      <pubDate>Sun, 09 Aug 2026 09:49:21 +0000</pubDate>
      <link>https://dev.to/akhil_anil/ai-didnt-replace-my-devops-workflow-it-shortened-the-path-to-a-hypothesis-47b9</link>
      <guid>https://dev.to/akhil_anil/ai-didnt-replace-my-devops-workflow-it-shortened-the-path-to-a-hypothesis-47b9</guid>
      <description>&lt;p&gt;&lt;em&gt;How an alert, ten browser tabs, and a Slack ping actually get resolved when AI is in the loop — and where I still don't trust it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An alert fires.&lt;/p&gt;

&lt;p&gt;I open Grafana. Then CloudWatch. Then the logs. Then &lt;code&gt;kubectl describe&lt;/code&gt; on the pod that's misbehaving. Then GitHub, to see what merged. Then Argo CD, to see what actually rolled out.&lt;/p&gt;

&lt;p&gt;Ten tabs in, trying to hold six timelines in my head at once, someone drops into the channel:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do we know what happened yet?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That moment is the real job. Not the syntax. Not remembering the exact &lt;code&gt;kubectl&lt;/code&gt; flag. The job is correlating scattered signals fast enough to form a hypothesis worth testing. That's the part where AI has changed how I work. It didn't take the troubleshooting away from me. I'm still doing all of it. It just shortened the gap between "something is wrong" and "this is probably where I should look."&lt;/p&gt;

&lt;p&gt;I don't use AI as a replacement for understanding Kubernetes, AWS, Terraform, Linux, networking, databases, or CI/CD. I use it as another tool in the workflow, one that helps me get from a problem to a testable hypothesis faster.&lt;/p&gt;

&lt;p&gt;My AI usage today broadly splits across three areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ChatGPT&lt;/strong&gt; — communication, research, reasoning, and technical analysis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude and Claude Code&lt;/strong&gt; — coding, Kubernetes, scripts, configurations, and troubleshooting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS DevOps Agent&lt;/strong&gt; — AWS infrastructure investigation, resource analysis, troubleshooting, and optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each tool has a slightly different role. The part that actually matters isn't having access to AI. It's knowing where it's useful, what context to give it, and when its output needs to be challenged. None of them makes a production decision for me.&lt;/p&gt;

&lt;p&gt;One habit before I get into the tools: I'm careful about what I paste into any of them. Config with real hostnames, account IDs, or anything secret-shaped stays out.&lt;/p&gt;

&lt;h2&gt;
  
  
  ChatGPT: the part of DevOps nobody warns you about
&lt;/h2&gt;

&lt;p&gt;People underestimate how much of this job is communication.&lt;/p&gt;

&lt;p&gt;I'll finish a technical investigation and then have to explain it — to a developer, a manager, a vendor, or the wider team — without either dumping raw metrics on someone who doesn't need them or oversimplifying to the point of being wrong.&lt;/p&gt;

&lt;p&gt;A recent example: I was looking at EKS control-plane logging. I'd already done the actual work — figured out that &lt;code&gt;api&lt;/code&gt;, &lt;code&gt;audit&lt;/code&gt;, and &lt;code&gt;authenticator&lt;/code&gt; logs were adding up to roughly 20–25 GB of ingestion per cluster per month, that ingestion was the real cost driver rather than storage, and that the sensible levers were trimming which log types we actually needed and dropping retention from 90 days to 30.&lt;/p&gt;

&lt;p&gt;That investigation was mine. What I didn't want to spend twenty minutes on was rewriting the summary three times until it read cleanly for a Slack thread.&lt;/p&gt;

&lt;p&gt;So I hand ChatGPT the findings and let it tighten the explanation. It isn't helping with the investigation. It's helping with the communication overhead &lt;em&gt;after&lt;/em&gt; the investigation.&lt;/p&gt;

&lt;p&gt;The second way I use it is more interesting: as a second pair of eyes on my own reasoning.&lt;/p&gt;

&lt;p&gt;Say I've got a &lt;code&gt;c7i.2xlarge&lt;/code&gt; sitting mostly idle and I'm thinking of dropping it to &lt;code&gt;c7i.xlarge&lt;/code&gt;. The weak version of the question is "should I downsize this?" — because it just tells me what I already decided.&lt;/p&gt;

&lt;p&gt;The version I actually get value from is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What am I missing before I make this change?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it'll nudge me toward network throughput, EBS bandwidth, short-lived peaks that a 30-day average hides, workload patterns, rollback path. Half of those I'd check anyway. But every so often it names the one I would've skipped, and that's the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I stopped asking AI to make the call and started asking it to find the hole in mine.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude and Claude Code: reducing the search space
&lt;/h2&gt;

&lt;p&gt;I use Claude for the code-shaped work — Kubernetes manifests, Bash and Python scripts, CI/CD config. That part's useful but not that interesting; generating a Deployment YAML was never the hard part.&lt;/p&gt;

&lt;p&gt;Claude Code is where it gets useful, because a Kubernetes problem almost never lives in one file.&lt;/p&gt;

&lt;p&gt;The behavior I'm chasing is usually smeared across Helm templates, &lt;code&gt;values.yaml&lt;/code&gt;, &lt;code&gt;values-prod.yaml&lt;/code&gt;, a ConfigMap, a Secret, a GitHub Actions workflow, and whatever Argo CD is actually syncing. Previously I'd grep my way through all of it by hand, holding the thread in my head the whole time.&lt;/p&gt;

&lt;p&gt;Now I can ask, against the real repo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find where DATABASE_HOST is defined and explain how it reaches the production Deployment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare dev and prod and show me anything that affects memory limits or scheduling.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's a concrete one. A pod keeps restarting. I run the usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod &amp;lt;pod&amp;gt;
kubectl logs &amp;lt;pod&amp;gt;
kubectl logs &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--previous&lt;/span&gt;
kubectl get events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I find:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Last State: OOMKilled
Exit Code: 137
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I already know the direction — this is memory. What used to eat my time wasn't forming that hypothesis; it was the file-hopping to test it. Where's the current limit set? Is a prod override quietly bumping it down? Did a recent change touch the Helm values? Claude Code walks that trail with me instead of me opening eight files to reconstruct it.&lt;/p&gt;

&lt;p&gt;It's also confidently wrong sometimes. Once it pointed me at a limit in &lt;code&gt;values.yaml&lt;/code&gt; and told me that was the effective value in prod — except Argo CD was syncing that service from a &lt;em&gt;different&lt;/em&gt; repo, so the file it was reading never applied. The answer looked right. It just didn't know about the source it couldn't see. That's exactly why the output is a lead, not a verdict: it reduces the search space, and then I confirm what actually applies.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS DevOps Agent: correlating telemetry I'd otherwise eyeball
&lt;/h2&gt;

&lt;p&gt;This is the most infrastructure-facing part of how I work.&lt;/p&gt;

&lt;p&gt;Worth being precise here, because it's a capable product and it's easy to undersell. AWS DevOps Agent can go a long way on its own: it investigates incidents autonomously, correlates telemetry with code and deployment data, and produces root-cause analysis and mitigation plans without me driving each step. I read those as a strong lead, not a verdict. The part I lean on most is the correlation, because that's where it saves me the tab-juggling. The root-cause call and anything that touches production, I still confirm and own myself.&lt;/p&gt;

&lt;p&gt;AWS already collects an enormous amount of operational data. Finding the graphs was never the problem. The problem is figuring out what changed &lt;em&gt;at the same time&lt;/em&gt; as the thing that's on fire.&lt;/p&gt;

&lt;p&gt;RDS is the clearest example. A CPU spike shows up, and normally I'd be pulling up &lt;code&gt;CPUUtilization&lt;/code&gt;, &lt;code&gt;DatabaseConnections&lt;/code&gt;, &lt;code&gt;FreeableMemory&lt;/code&gt;, read/write IOPS, latency, &lt;code&gt;DiskQueueDepth&lt;/code&gt;, Performance Insights, and the RDS events feed — one tab at a time.&lt;/p&gt;

&lt;p&gt;Say the picture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00   CPU: 20%   Connections: 100
10:05   CPU: 85%   Connections: 450
10:10   CPU: 95%   Connections: 700
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useful observation isn't "CPU hit 95%." Anyone can read that off a graph. The useful observation is that CPU and connections climbed &lt;em&gt;together&lt;/em&gt;, and that turns a symptom into a hypothesis. Maybe replicas scaled up. Maybe connection pooling fell over. Maybe a scheduled job kicked in, or queries got slower, or a retry loop started hammering the database.&lt;/p&gt;

&lt;p&gt;Correlation isn't proof. I still have to confirm which of those it actually was — and this is where Performance Insights earns its place: top SQL by load told me the time was going into a single unindexed query, which ruled out the retry-loop and pooling theories fast. But having the correlation surfaced for me is the difference between starting an investigation and starting it fifteen minutes late.&lt;/p&gt;

&lt;p&gt;The same correlation habit feeds straight into cost work. Picture a &lt;code&gt;c7i.2xlarge&lt;/code&gt; running at ~5% average CPU, ~15% peak, memory under 15%. The lazy move is to downsize on CPU alone. Instead I want CPU, memory, network, EBS/disk, and the peak-workload periods considered &lt;em&gt;together&lt;/em&gt;, because low CPU with high memory is a completely different story.&lt;/p&gt;

&lt;p&gt;One catch that's easy to miss: halving the instance size also halves the network and EBS bandwidth ceilings, so that 15% peak has to be re-checked against the &lt;em&gt;smaller&lt;/em&gt; instance's limits, not the current one's. When the signals genuinely agree that &lt;code&gt;c7i.2xlarge → c7i.xlarge&lt;/code&gt; is safe, and I've validated it, AI has directly helped me cut spend while keeping real headroom. That's more honest than saying "AI helps with cost optimization." It helped me confidently run the workload smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing all three have in common
&lt;/h2&gt;

&lt;p&gt;Strip away the tools and here's what actually changed.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alert → metrics → logs → docs → repo search → config comparison → hypothesis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alert → collect evidence → AI helps correlate/search → hypothesis → validate → fix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The steps didn't disappear. The evidence still has to be collected, the hypothesis still has to be validated, the fix is still mine to ship. What compressed is the messy middle: the correlating, the searching, the file-hopping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the human stays in the loop
&lt;/h2&gt;

&lt;p&gt;I don't hand production to any of this.&lt;/p&gt;

&lt;p&gt;If a right-sizing analysis says an instance can shrink, I don't just run &lt;code&gt;terraform apply&lt;/code&gt;. If Claude generates a manifest, I read every line of it. If the AWS agent points at a root cause, I still go confirm the metrics say what it thinks they say.&lt;/p&gt;

&lt;p&gt;My loop is boring on purpose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI suggestion → understand it → validate it → make the change → monitor → roll back if needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trap is easy to fall into: create Kubernetes Deployment, copy the YAML, ship it. But if you can't explain your own &lt;code&gt;resources.requests&lt;/code&gt;, your probes, or your affinity rules, AI just made you faster at deploying things you don't understand. That's more dangerous, not less.&lt;/p&gt;

&lt;p&gt;AI makes syntax, searching, and retrieval cheap. If the syntax is cheap now, the judgment about whether to run it is the part that's actually worth paying an engineer for.&lt;/p&gt;

&lt;p&gt;What moved is how long I spend getting from "something is wrong" to "this is probably where I should look." That gap used to be most of the incident. Now it's a smaller part of it, and I'd rather spend my time on the part that actually needs an engineer.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;One question for the DevOps, SRE, cloud, and platform folks: where has AI actually created&lt;/em&gt; more &lt;em&gt;work for you than it saved — a wrong root cause you chased, a confident answer that was subtly off, a place you still don't trust it? (And if you've got a genuine win, I'll take that too.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
