{"id":12649,"date":"2026-08-03T20:55:32","date_gmt":"2026-08-04T01:55:32","guid":{"rendered":"https:\/\/www.rushworth.us\/lisa\/?p=12649"},"modified":"2026-11-02T10:04:53","modified_gmt":"2026-11-02T15:04:53","slug":"spire-stopping-an-agent-expiry-revocation-and-incident-containment","status":"publish","type":"post","link":"https:\/\/www.rushworth.us\/lisa\/?p=12649","title":{"rendered":"SPIFFE: Stopping an Agent: Expiry, Revocation, and Incident Containment"},"content":{"rendered":"<p>Disabling an agent is not one operation. The agent may possess an SVID, an OAuth token, an established connection, a queued job, and a refresh-capable authorization context. Incident containment must address each separately.<\/p>\n<h2>Credential lifecycle is not a revocation chain<\/h2>\n<p>Token exchange does not inherently consume the input credential. It also does not guarantee that revoking the subject or actor token invalidates every token previously issued from it. Build explicit relationships if downstream invalidation is required, and test them.<\/p>\n<p>Disabling future issuance differs from rejecting existing credentials. A resource server validating a self-contained token from cached public keys may not learn that XYZ was disabled until some separate policy update reaches it. Introspection can expose current authorization-server state, but cache duration and resource-server behavior still determine enforcement latency. Revocation endpoint behavior must be understood for the actual token type and deployment.<\/p>\n<h2>An illustrative containment timeline<\/h2>\n<table>\n<tbody>\n<tr>\n<td width=\"221\"><strong>Time<\/strong><\/td>\n<td width=\"221\"><strong>Action<\/strong><\/td>\n<td width=\"221\"><strong>What may remain usable<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>T+0<\/strong><\/td>\n<td width=\"221\">Disable agent deployment and isolate compromised runtime<\/td>\n<td width=\"221\">Stolen credentials elsewhere; active requests<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>T+1 minute<\/strong><\/td>\n<td width=\"221\">Deny XYZ at STS and stop relevant identity issuance<\/td>\n<td width=\"221\">Previously issued tokens and SVIDs<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>T+2 minutes<\/strong><\/td>\n<td width=\"221\">Push resource-server denial for actor\/delegation<\/td>\n<td width=\"221\">Caches and requests beyond authorization check<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>T+3 minutes<\/strong><\/td>\n<td width=\"221\">Cancel jobs and review active sessions\/connections<\/td>\n<td width=\"221\">Committed changes; remote services not yet updated<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>T+token lifetime<\/strong><\/td>\n<td width=\"221\">Remaining token expiry reached<\/td>\n<td width=\"221\">Long-lived sessions if independently authorized<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Times are examples, not product guarantees. A hypothetical five-minute access token with a one-minute cache does not imply six-minute universal containment: an already-authorized long-running operation or independently created session may last longer. Measure the actual behavior.<\/p>\n<h2>Containment runbook<\/h2>\n<ul>\n<li>Preserve relevant identities, token IDs, approvals, policy versions, and execution evidence; do not collect raw credentials into ordinary logs.<\/li>\n<li>Isolate the runtime and prevent replacement workloads from reacquiring the same identity.<\/li>\n<li>Deny further exchange for the affected actor and revoke appropriate approval\/refresh contexts.<\/li>\n<li>Apply API-level actor or delegation denial where supported; distribute it to every enforcement point.<\/li>\n<li>Suspend queued jobs and prevent a retry path from resurrecting authority.<\/li>\n<li>Determine whether active requests, sessions, or connections require termination.<\/li>\n<li>Review completed mutations and trigger business rollback or compensating actions where needed.<\/li>\n<li>Verify containment using previously issued credentials, not only new login attempts.<\/li>\n<\/ul>\n<h2>Avoid issuer-wide collateral damage<\/h2>\n<p>Removing an entire trust bundle or issuer can disrupt every workload under that authority and may still fail to stop cached or already-authorized activity immediately. Prefer a targeted actor\/delegation deny mechanism when the issuer itself is not compromised. If signing authority is compromised, broader trust removal and key replacement may be justified; that is a different incident class.<\/p>\n<p>An emergency deny-list is a proposed supplemental control. Define its authenticated distribution, cache lifetime, availability behavior, administrative ownership, and effect on already-running operations. A deny-list that is unavailable must not silently disappear from policy.<\/p>\n<h2>Recovery criteria<\/h2>\n<p>Recover the underlying workload and deployment authority before re-enabling issuance. Verify that the compromise cannot satisfy selectors again, clear unauthorized approvals, restore reviewed configuration, and rotate compromised keys where relevant. A new run identifier is not a remediation boundary if the same compromised workload can obtain the same identity.<\/p>\n<p>Takeaway: the practical containment window is determined by every credential and enforcement cache, not by the shortest advertised token lifetime.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disabling an agent is not one operation. The agent may possess an SVID, an OAuth token, an established connection, a queued job, and a refresh-capable authorization context. Incident containment must address each separately. Credential lifecycle is not a revocation chain Token exchange does not inherently consume the input credential. It also does not guarantee that &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2243],"tags":[2246,2244,2216,2245],"class_list":["post-12649","post","type-post","status-publish","format-standard","hentry","category-spiffe","tag-agent-identity","tag-spiffe","tag-spire","tag-workload-identity"],"_links":{"self":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/12649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12649"}],"version-history":[{"count":2,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/12649\/revisions"}],"predecessor-version":[{"id":12662,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/12649\/revisions\/12662"}],"wp:attachment":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}