fix(browser): grant ConnectBrowserLiveViewStream on *, as AWS requires - #1194
Merged
Merged
Conversation
This is why the sign-in viewer never streamed. AWS's own service reference lists the resource types for each action: GetBrowserSession -> ['browser', 'browser-custom'] UpdateBrowserStream -> ['browser', 'browser-custom'] ConnectBrowserLiveViewStream -> [] <- none An action with NO resource types never matches a resource-scoped statement, so granting all three on the browser ARN made the third an implicit deny. `iam simulate-principal-policy` confirms it: allowed for the first two and implicitDeny for the third, from the SAME statement on the SAME ARN. It failed silently and late. `generate_live_view_url` only signs locally and calls no API, so app-api minted a URL happily; the denial appeared only when the browser opened the socket and the service closed it, surfacing as DCV auth code 10, "Failed to communicate with server" — which reads as a service fault, not a missing permission. Proven by running the real SDK against a real session outside the browser: `dcv.authenticate` SUCCEEDS with admin credentials (returns sessionId and authToken, socket closes 1000) and fails from app-api. Same SDK, same service, same session — only the signing principal differs. `*` is as narrow as this action can be expressed. The statement is split so it carries that one action and nothing else, and the resource-typed actions stay scoped to the browser ARN. app-api still cannot start, stop or drive a browser. Mutation-checked: re-scoping the connect grant fails the new assertion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
This is why the sign-in viewer never streamed. AWS's machine-readable service reference lists resource types per action:
GetBrowserSessionbrowser,browser-customUpdateBrowserStreambrowser,browser-customConnectBrowserLiveViewStream[]— noneAn action with no resource types never matches a resource-scoped statement. Granting all three on the browser ARN made the third an implicit deny.
iam simulate-principal-policyconfirms it — from the same statement on the same ARN:Why it hid for so long
It fails silently and late.
generate_live_view_urlonly signs locally — it calls no API — so app-api minted a URL happily. The denial appeared only when the browser opened the socket and the service closed it, surfacing as DCV authcode: 10, "Failed to communicate with server". That reads as a service fault, not a missing permission, and it sent me down three wrong paths.How it was proven
By running the real DCV SDK against a real AgentCore session outside the browser (Node + jsdom + Node 22's native WebSocket):
dcv.authenticateSUCCEEDS — returnssessionId+authToken, socket closes cleanly with code 1000.Same SDK, same service, same session shape — only the signing principal differs. That isolated it to IAM after subprotocol, Origin,
take_control, doubled params, double-mount and CSP had each been ruled out by measurement.Security
*is as narrow as this action can be expressed; there is no browser-scoped form. So the statement is split, carrying that one action and nothing else, while the resource-typed actions stay scoped to the browser ARN.app-api still cannot start, stop or drive a browser. The existing "does NOT let app-api start, stop or drive" test now checks both statements, so the split can't become a side door.
Mutation-checked: re-scoping the connect grant fails the new assertion. Suite 876 pass,
tsc --noEmitclean.🤖 Generated with Claude Code