<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[João Penteado]]></title><description><![CDATA[Security engineer by trade, curious about most everything else. Based in Japan. I write about digital security, tech, and where it intersects with society. Technical deep dives, industry commentary, and the occasional strong take. Views are my own.]]></description><link>https://www.joaopenteado.com</link><image><url>https://substackcdn.com/image/fetch/$s_!oJEN!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85cfbb9f-8e0a-491f-a503-032a33eeb654_336x336.png</url><title>João Penteado</title><link>https://www.joaopenteado.com</link></image><generator>Substack</generator><lastBuildDate>Sat, 02 May 2026 22:07:05 GMT</lastBuildDate><atom:link href="https://www.joaopenteado.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[João Penteado]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[joaopenteado@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[joaopenteado@substack.com]]></itunes:email><itunes:name><![CDATA[João Penteado]]></itunes:name></itunes:owner><itunes:author><![CDATA[João Penteado]]></itunes:author><googleplay:owner><![CDATA[joaopenteado@substack.com]]></googleplay:owner><googleplay:email><![CDATA[joaopenteado@substack.com]]></googleplay:email><googleplay:author><![CDATA[João Penteado]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[“Who has access?” is a trick question]]></title><description><![CDATA[And why most access reviews fail to answer it]]></description><link>https://www.joaopenteado.com/p/who-has-access-is-a-trick-question</link><guid isPermaLink="false">https://www.joaopenteado.com/p/who-has-access-is-a-trick-question</guid><dc:creator><![CDATA[João Penteado]]></dc:creator><pubDate>Tue, 14 Apr 2026 11:13:46 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8d9a8e7d-b1d3-4cd6-8ca0-5f67b11bd9a4_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every security team has been asked this question. An auditor walks in, a compliance framework demands it, an incident responder needs it urgently: <em>who has access to this resource?</em></p><p>It sounds like simple question any team should have an immediate answer to. </p><p>However, this question is underspecified in ways that most organizations never bother to articulate, and the result is that access reviews produce answers that range from incomplete to meaningless. Not because the teams doing them are necessarily incompetent, but because the industry lacks a shared understanding for what &#8220;access&#8221; actually means in practice.</p><h2>The problem with &#8220;access&#8221;</h2><p>Suppose you&#8217;re asked: who can edit DNS records in Cloud DNS on Google Cloud Platform?</p><p>Your first instinct might be to check who has the <code>dns.changes.create</code> permission on the DNS zone. You look at any predefined and custom IAM roles containing that permission, IAM bindings for that resource, find the employees with matching roles, and hand over a list.</p><p>Except that list is incomplete in ways you (or your auditor) haven&#8217;t scoped.</p><p>Maybe a user doesn&#8217;t have the permission directly, but they&#8217;re in a group that does. Maybe the binding isn&#8217;t on the zone itself, but on the project that contains it, or the folder above that project, or the organization above that folder. Maybe the user has no binding anywhere, but they can impersonate a service account that does. Maybe they can impersonate a service account that can impersonate <em>another</em> service account that has access through a group membership inherited from a folder three levels up. Maybe the user has no current access at all, but they possess the power to grant it to themselves at any time: a permission that only wakes up when they decide to edit an IAM policy or role somewhere else.</p><p>All of these are real and all of them answer &#8220;who has access&#8221; differently. However, most access reviews stop looking at the first or second layer.</p><p>The root issue is that we&#8217;re conflating fundamentally different things under a single word. To have a useful conversation about access, I believe it&#8217;s necessary to distinguish between three broad categories: <strong>effective access</strong>, <strong>assumable access</strong>, and <strong>escalatable access</strong>.</p><p>The examples throughout this article use Google Cloud Platform because that&#8217;s where I work the most daily, but nothing here is GCP-specific. AWS has an arguably more complex IAM system, with largely the same patterns involving IAM roles, SCPs, resource policies, and cross-account role assumption. Azure has management group inheritance, managed identities, and service principal impersonation. Hence, the underlying problem is structural: any system with hierarchical resource organization, group-based policy resolution, and delegated identity mechanisms will produce the same complexity.</p><h2>Effective access</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BblO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BblO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 424w, https://substackcdn.com/image/fetch/$s_!BblO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 848w, https://substackcdn.com/image/fetch/$s_!BblO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 1272w, https://substackcdn.com/image/fetch/$s_!BblO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BblO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png" width="1240" height="906" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:906,&quot;width&quot;:1240,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:127265,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.joaopenteado.com/i/193027028?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BblO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 424w, https://substackcdn.com/image/fetch/$s_!BblO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 848w, https://substackcdn.com/image/fetch/$s_!BblO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 1272w, https://substackcdn.com/image/fetch/$s_!BblO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71141d7c-5040-4344-9b07-ee99040ab06a_1240x906.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">All three users have effective access: different paths, same result.</figcaption></figure></div><p>Effective access is the set of permissions a principal can exercise <em>right now</em>, without performing any intermediate action. The principal navigates to the resource, performs the operation, and it works. No impersonation, no credential exchange, no role modification needed.</p><p>This is what most people picture when they hear &#8220;access,&#8221; but even this category is more complex than it first appears. The principal might hold the permission through any of several mechanisms:</p><p>The simplest is a direct binding: the user is bound to a role containing the permission on the resource itself. Then there&#8217;s group-mediated access: the user is a member of a group (or a complex nested chain of groups) that holds the binding. On top of this, there&#8217;s hierarchy inheritance: the binding exists on an ancestor resource, such as a project, folder, or organization, and propagates down.</p><p>These mechanisms are orthogonal and composable: a user might be a member of a group that is a member of another group that has a role binding on a folder, and that binding propagates to a project, which contains the resource. The result is an access path of length four or five, but the access is still <em>effective</em>, meaning the user can exercise the permission immediately, right now, without doing anything first.</p><p>The length of the access path matters, but not for whether the access exists. It matters for auditability. A direct binding on a resource is visible, easy to review and more likely to be intentional, while a nested group membership inherited through three layers of resource hierarchy is harder to discover, and more likely to be accidental or ungoverned. <strong>Access path length can be a useful proxy to determine how likely the access is unintentional.</strong></p><h2>Assumable access</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zg_N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zg_N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 424w, https://substackcdn.com/image/fetch/$s_!zg_N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 848w, https://substackcdn.com/image/fetch/$s_!zg_N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!zg_N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zg_N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png" width="1456" height="1099" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1099,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:366562,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.joaopenteado.com/i/193027028?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zg_N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 424w, https://substackcdn.com/image/fetch/$s_!zg_N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 848w, https://substackcdn.com/image/fetch/$s_!zg_N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!zg_N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12ad2cdd-8dc7-41a7-8b2b-7424b024e2bf_2119x1600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The principal needs to go through one or more intermediaries who have effective access. </figcaption></figure></div><p>Assumable access is when a principal does not have effective access to a resource, but can obtain it by assuming a different identity. The defining operation here is identity impersonation: the principal temporarily becomes another principal and inherits that principal&#8217;s effective access in whole or in part.</p><p>The most obvious example in GCP is service account impersonation. A user with the <code>iam.serviceAccounts.getAccessToken</code> permission on a service account can mint tokens as that service account. If the service account has effective access to the resource, the user can reach it through impersonation. And just like effective access, the service account&#8217;s path to the resource itself might be mediated through groups, inheritance, or both.</p><p>This creates two independent path dimensions. The <em>assumable path</em> is the chain of identity assumptions: how does the user reach the target identity? The <em>effective path</em> is the chain from that identity to the resource. The composition of both results in the total access path.</p><p>Service account impersonation can also chain. A user impersonates service account A, which can impersonate service account B, which has the role binding. Each hop adds a layer of indirection and, more often than not, a layer of unintentionality.</p><p>But impersonation through the IAM API isn&#8217;t the only way to assume an identity. Consider a user who can SSH into a VM, or deploy code to a Cloud Run service, or trigger a Cloud Build pipeline. Each of these workloads runs with an attached service account. If the user can execute arbitrary code in a workload&#8217;s context, they effectively have access to its credentials. This is identity assumption through compute access rather than through the IAM impersonation API, but the end result is the same: the user acts as the service account.</p><p>These paths are harder to enumerate because they cross the boundary between IAM analysis and infrastructure or application analysis. IAM tooling can tell you who can impersonate a service account. Understanding that a user can push code to a Cloud Run service which runs as that service account requires understanding the deployment pipeline, repository permissions, and CI/CD configuration. The access path exists, but because it lives in a different system it&#8217;s easy to overlook it.</p><h3>Where federated identities fit</h3><p>Identity federation adds another dimension to assumable access. In workload identity federation, an external identity, such as a GitHub Actions runner, an AWS role, or a CI/CD pipeline in another platform, can exchange its native credentials for short-lived GCP credentials. The federation configuration defines which external identities map to which GCP principals.</p><p>This means the question of &#8220;who has access&#8221; can extend outside your cloud boundary entirely. If a GitHub Actions workflow for a specific repository has federated access to a GCP service account, then anyone who can create or modify workflows in that repository effectively has assumable access to whatever that service account can reach. The user&#8217;s credential never touches GCP directly: they push a commit to a repository, a workflow runs, it federates into a GCP identity, and that principal has effective access to your resources.</p><p>Federated identity is particularly challenging for access reviews because the trust boundary is defined in configuration of the workload identity pool and in an external system&#8217;s permission model. You won&#8217;t find these paths by examining role bindings just in the resource&#8217;s platform alone. You need to trace the federation configuration, understand the external identity provider&#8217;s authorization model, and map backward from &#8220;who can assume this external identity&#8221; all the way to &#8220;which principals are able to grant or influence access along that path.&#8221;</p><h3>The AI agent identity problem</h3><p>This is about to get even more complicated. Cloud providers are introducing first-class identity types for AI agents, and these create entirely new assumable access paths.</p><p>Google Cloud&#8217;s Vertex AI Agent Engine now supports <a href="https://docs.cloud.google.com/agent-builder/agent-engine/agent-identity">agent identity</a> as an IAM principal type. Agents get their own principal identifiers in the format <code>principal://TRUST_DOMAIN/NAMESPACE/AGENT_NAME</code>, and you can bind IAM roles to these identities just like you would for users or service accounts. From an access review perspective, this means agents are principals that can hold effective access to resources.</p><p>Where they differ from traditional service accounts is in their constraints. Agent identities cannot be directly impersonated by another principal through the IAM API. There are also no downloadable keys to create, rotate, or leak. The credentials are cryptographically bound to the agent's runtime environment on Vertex AI through certificate-bound tokens and mTLS, which means stolen credentials are not replayable outside that context. In practice, they are more restricted service accounts: scoped to a specific workload, tied to its lifecycle, and stripped of the portability that makes service accounts both useful and dangerous. This matters for access analysis because the assumable access path to an agent's permissions doesn't run through impersonation or credential theft. It only runs through the ability to invoke the agent itself, which is a fundamentally different trust boundary.</p><p>The assumable access question then becomes: who can invoke the agent? If a user can send requests to an agent, and that agent has IAM permissions to perform actions on resources, the user has indirect access to those resources through the agent. The agent is an intermediary identity, similar in structure to a service account, but with a critical difference: the agent&#8217;s behavior is driven by a language model that interprets natural language instructions, not by deterministic code. The blast radius of &#8220;access through the agent&#8221; is harder to scope because it depends not just on what permissions the agent holds, but on what the agent can be instructed to do.</p><p>Agent identity also composes with everything else. An agent might use a service account for some operations, federate into external services for others, and hold direct IAM bindings on GCP resources. Mapping the full access surface of &#8220;user can talk to agent&#8221; requires tracing through all of these paths.</p><p>We are early in understanding what governance looks like for agent identities. But one thing is already clear: any access taxonomy that doesn&#8217;t account for non-human, non-deterministic intermediaries is very likely to age poorly.</p><h2>Escalatable access</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vBlh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vBlh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 424w, https://substackcdn.com/image/fetch/$s_!vBlh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 848w, https://substackcdn.com/image/fetch/$s_!vBlh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 1272w, https://substackcdn.com/image/fetch/$s_!vBlh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vBlh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png" width="1456" height="793" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:793,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:293716,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.joaopenteado.com/i/193027028?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vBlh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 424w, https://substackcdn.com/image/fetch/$s_!vBlh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 848w, https://substackcdn.com/image/fetch/$s_!vBlh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 1272w, https://substackcdn.com/image/fetch/$s_!vBlh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d1fedbd-1057-474e-a6b8-67a24ddd0a85_2180x1188.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The principal can create access paths that don&#8217;t exist yet.</figcaption></figure></div><p>The third category is fundamentally different from the first two. Effective access and assumable access describe paths that <em>exist</em>. Escalatable access describes the ability to <em>create</em> paths that don&#8217;t exist yet.</p><p>A user with <code>resourcemanager.projects.setIamPolicy</code> on a project can add any role binding they want to that project. They might not have <code>dns.changes.create</code> right now, but they can grant it to themselves at any time. For example, a user who can impersonate a service account that has <code>setIamPolicy</code> on a folder can modify IAM bindings on that folder and everything below it. More subtly, a user might be able to modify their own roles: impersonate a service account that has the ability to edit the role definition or IAM policy that applies to the user&#8217;s own principal.</p><p>This is where I&#8217;d argue that access review becomes vulnerability analysis. The access path doesn&#8217;t exist yet. The user has to construct it. But if they <em>can</em> construct it, the access is effectively attainable from a security perspective.</p><p>Tools like <a href="https://github.com/nccgroup/pmapper">PMapper</a> exist specifically for this kind of analysis. They model IAM as a directed graph and traverse it to find escalation paths: edges that don&#8217;t represent current access, but the ability to create it. This is computationally expensive and, in the worst case, the graph of potential escalation paths grows combinatorially.</p><p>For most access review purposes, escalatable access is where you draw the line and say &#8220;this is a different exercise.&#8221; Certifying effective access is a governance activity. Reviewing assumable access is a more sophisticated governance activity. Finding and closing escalatable access paths is a security engineering problem. The vocabulary matters because it lets you be explicit about which problem you&#8217;re solving and where the boundary is.</p><p>The one exception is privileged access management. PAM and JIT access systems are, by design, sanctioned escalation: a user requests elevated permissions, approval is granted (by a human or a policy), and temporary bindings are created. This is escalatable access that&#8217;s been formalized into a workflow with controls around it. When an auditor asks about access, whether PAM grants count depends entirely on whether they&#8217;re asking about &#8220;access right now&#8221; or &#8220;access that could exist.&#8221;</p><h2>In conclusion</h2><p>Without shared vocabulary, every access review is a negotiation. The auditor asks &#8220;who has access,&#8221; the security team counters with &#8220;what do you mean by access,&#8221; and both parties waste time arriving at an <em>ad hoc</em> definition that won&#8217;t be consistent with the next review or third-party&#8217;s interpretation.</p><p>With a taxonomy, you can scope the question precisely. &#8220;Show me all principals with effective access to production DNS zones&#8221; is tractable and well-defined. &#8220;Show me all principals with assumable access, including compute-mediated impersonation&#8221; is harder but still scoped. &#8220;Show me all escalation paths to DNS write access&#8221; is a different project entirely.</p><p>This vocabulary also gives you a framework for evaluating tooling. Most cloud IAM analysis tools, including the built-in policy analyzers, primarily cover effective access. Some are specifically designed for escalatable access. Almost none handle compute-mediated assumable access or federated identity paths. Knowing which category you&#8217;re trying to cover tells you which tools are fit for purpose and where you have gaps.</p><p>More importantly, it lets you be honest about what you don&#8217;t know. Most organizations think they govern effective access reasonably well, some might even partially cover assumable access through service account reviews, but very few touch escalatable access. That is defensible, as long as it is known, understood, and stated explicitly. Issues arise when partial coverage is treated as a complete picture of access.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.joaopenteado.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Stop asking your team for updates]]></title><description><![CDATA[On removing the interrogation loop from engineering check-ins]]></description><link>https://www.joaopenteado.com/p/stop-asking-your-team-for-updates</link><guid isPermaLink="false">https://www.joaopenteado.com/p/stop-asking-your-team-for-updates</guid><dc:creator><![CDATA[João Penteado]]></dc:creator><pubDate>Thu, 19 Mar 2026 17:47:46 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3118d0ea-0f2c-4b14-91f7-42d6bca26a82_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most standups are a polite form of interrogation.</p><p>You ask what someone is working on. They tell you mostly things you already knew. You then ask if there are blockers. They say no, or mention one, and it gets noted somewhere and the meeting moves on. This happens every morning, or three times a week, or whatever cadence the team has settled on. Everyone is present, but almost no one is really listening.</p><p>The problem isn&#8217;t the frequency or the length. It&#8217;s the structure. It puts the team on the hook for producing information that, in many cases, everyone in the room already has, or that no one in the room actually needs at that moment.</p><p>The worst version of this is when someone has to repeatedly announce that nothing has happened on a six-month project that was never going to move this week. That&#8217;s not information. That&#8217;s management theater at best and a slow tax on morale at worst. But the ritual demands it, so someone performs it.</p><h3>The setup</h3><p>I&#8217;ve been running my security team&#8217;s check-ins differently for the past year or so, and I want to describe the part that I think matters most.</p><p>We meet on Mondays, Wednesdays, and Fridays. Wednesdays and Fridays are short syncs, usually under fifteen minutes. Monday is the main meeting and runs for about an hour. </p><p>The gap between meetings is intentional: enough time for things to actually move, not so long that anything slips through.</p><p>The Monday structure is straightforward: I open with announcements, urgent or unplanned work, kudos where they&#8217;re due, and what&#8217;s top of mind for me on both the security and business side. Then each person goes through what they&#8217;re working on, what they need help with, what they&#8217;re stuck on.</p><p>None of that is unusual. The part that&#8217;s different happens roughly every two weeks, at the end of one of those Monday meetings, after everyone has had their turn.</p><p>I go through every project on our pipeline and I state my understanding of its current status. Not as a question. As a statement. I say what I think is happening, what I think the blockers are, what I think the next steps are. The team corrects me where I&#8217;m wrong. Mostly, I&#8217;m right.</p><p>We also run a monthly retrospective focused on team health and process improvements, but it&#8217;s separate from this mechanism.</p><h3>Shifting the burden</h3><p>The reason it works, I think, comes down to who carries the tracking burden.</p><p>In a traditional standup, that burden sits with the team. They&#8217;re responsible for surfacing progress, flagging issues, and producing updates on demand. The manager is the receiver. The implicit contract is: I ask, you report, and I follow up if something seems off.</p><p>This model inverts the contract. I absorb whatever surfaces naturally in normal conversation or check-ins over the course of two weeks. I don&#8217;t prompt for project-level status. <strong>I don&#8217;t ask &#8220;where are we on X?&#8221; in sync meetings, ever.</strong> Long-running work that hasn&#8217;t moved doesn&#8217;t need to be announced as unmoved. It surfaces when there&#8217;s something worth saying about it.</p><p>Then, at the biweekly recap, I carry the synthesis myself. I&#8217;m the one who has to demonstrate that I&#8217;ve been paying attention. If my understanding is wrong or outdated, that&#8217;s on me to correct, not on someone else to have proactively flagged.</p><p>The effect on the team is real, even if it&#8217;s subtle. Nobody has to say &#8220;no progress this week&#8221; on a project they haven&#8217;t touched, because I&#8217;m the one stating the status. The pressure to produce the update disappears. What remains is just the conversation. The team can instead focus exclusively on producing high-value signals.</p><p>There&#8217;s a flattening effect too. When the manager is the one producing the update rather than extracting it, the dynamic stops feeling like a reporting line and starts feeling more like a team that shares context.</p><h3>The catch</h3><p>There&#8217;s a prerequisite worth being honest about: <strong>this only works if the manager is actually engaged.</strong> The biweekly recap isn&#8217;t a technique for reducing your own involvement. It&#8217;s a forcing function for maintaining it. You have to be absorbing what people say in normal conversation accurately enough to reconstruct the state of the entire project pipeline every two weeks. If you&#8217;re not doing that, the recap falls apart immediately and you&#8217;ve just created a new awkward meeting format.</p><p>I would argue that engagement is the job anyway. Knowing the current state of your team&#8217;s work, understanding why things are moving or not, and being able to communicate that clearly to stakeholders is not a bonus feature of good management. It&#8217;s the baseline. This mechanic just makes it visible and creates a regular moment where you have to prove it to yourself and your team.</p><h3>The upstream benefit</h3><p>One more thing worth naming: it helps me upstream as much as it helps the team. I&#8217;m regularly synthesizing project status in a form that&#8217;s ready to communicate to stakeholders. The biweekly recap isn&#8217;t just a check-in tool. It&#8217;s also how I keep my own model current and accurate enough to answer questions quickly when someone above me asks.</p><p>I&#8217;m not claiming this is novel or scientifically validated. My sample size is one and every team is different. Other people have almost certainly arrived at versions of this and built better systems around it. But it has worked well enough that the mechanism is worth describing: Don&#8217;t ask. Absorb. Carry. Read it back<strong>.</strong> Let your team correct you.</p><p>The correction is the update. <strong>The absence of interrogation is the point.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.joaopenteado.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>