From f799300ddffccd158cd58e418f03a7f49dc94abd Mon Sep 17 00:00:00 2001 From: Yuki Matsuda <13781813+mazyu36@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:40:01 +0900 Subject: [PATCH 1/3] feat(bedrock-agentcore): add grantInvokeWithWebSocketStream method to Runtime Add `grantInvokeWithWebSocketStream` to `IBedrockAgentRuntime` and `RuntimeBase` to grant `bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream` permission, enabling WebSocket stream invocation of AgentCore Runtimes. Closes #37495 --- .../lib/runtime/perms.ts | 6 ++ .../lib/runtime/runtime-base.ts | 25 +++++- .../test/agentcore/runtime/runtime.test.ts | 76 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts index 0ad21f011ccfd..482556e337a46 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts @@ -12,6 +12,12 @@ export const RUNTIME_INVOKE_PERMS = ['bedrock-agentcore:InvokeAgentRuntime']; */ export const RUNTIME_INVOKE_USER_PERMS = ['bedrock-agentcore:InvokeAgentRuntimeForUser']; +/** + * Permissions to invoke the agent runtime via WebSocket stream + * Required when signing WebSocket connection requests to the agent runtime + */ +export const RUNTIME_INVOKE_WEBSOCKET_STREAM_PERMS = ['bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream']; + /****************************************************************************** * Control Plane Permissions *****************************************************************************/ diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts index 94c419631723f..8547d794cf47f 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts @@ -28,7 +28,7 @@ import * as iam from 'aws-cdk-lib/aws-iam'; import { ValidationError } from 'aws-cdk-lib/core/lib/errors'; import { lit } from 'aws-cdk-lib/core/lib/helpers-internal'; import type { Construct } from 'constructs'; -import { RUNTIME_INVOKE_PERMS, RUNTIME_INVOKE_USER_PERMS } from './perms'; +import { RUNTIME_INVOKE_PERMS, RUNTIME_INVOKE_USER_PERMS, RUNTIME_INVOKE_WEBSOCKET_STREAM_PERMS } from './perms'; /****************************************************************************** * Interface @@ -185,6 +185,13 @@ export interface IBedrockAgentRuntime extends IResource, iam.IGrantable, ec2.ICo * @param grantee The principal to grant access to */ grantInvoke(grantee: iam.IGrantable): iam.Grant; + + /** + * Permits an IAM principal to invoke this runtime via WebSocket stream + * Grants the bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream permission + * @param grantee The principal to grant access to + */ + grantInvokeWithWebSocketStream(grantee: iam.IGrantable): iam.Grant; } /****************************************************************************** @@ -315,6 +322,22 @@ export abstract class RuntimeBase extends Resource implements IBedrockAgentRunti }); } + /** + * Permits an IAM principal to invoke this runtime via WebSocket stream + * Grants the bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream permission + * + * [disable-awslint:no-grants] + * + * @param grantee The principal to grant access to + */ + public grantInvokeWithWebSocketStream(grantee: iam.IGrantable): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee, + actions: RUNTIME_INVOKE_WEBSOCKET_STREAM_PERMS, + resourceArns: [this.runtimeRef.agentRuntimeArn, `${this.runtimeRef.agentRuntimeArn}/*`], + }); + } + // ------------------------------------------------------ // Metrics // ------------------------------------------------------ diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts index a6218211bec3d..f883772e681c7 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts @@ -2088,6 +2088,82 @@ describe('Runtime grantInvokeRuntime permission tests', () => { ], }); }); + + test('Should grant InvokeAgentRuntimeWithWebSocketStream permission with grantInvokeWithWebSocketStream', () => { + runtime.grantInvokeWithWebSocketStream(granteeRole); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + Match.objectLike({ + Action: 'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream', + Effect: 'Allow', + Resource: [ + { + 'Fn::GetAtt': [ + Match.stringLikeRegexp('testruntime.*'), + 'AgentRuntimeArn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + Match.stringLikeRegexp('testruntime.*'), + 'AgentRuntimeArn', + ], + }, + '/*', + ], + ], + }, + ], + }), + ]), + }, + }); + }); + + test('Should grant WebSocket stream permission on imported runtime', () => { + const importedRuntime = Runtime.fromAgentRuntimeAttributes(stack, 'ImportedRuntimeWs', { + agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime-id', + agentRuntimeId: 'test-runtime-id', + agentRuntimeName: 'test-runtime', + roleArn: 'arn:aws:iam::123456789012:role/test-role', + agentRuntimeVersion: '1', + }); + + importedRuntime.grantInvokeWithWebSocketStream(granteeRole); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + Match.objectLike({ + Action: 'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream', + Effect: 'Allow', + Resource: [ + 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime-id', + 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime-id/*', + ], + }), + ]), + }, + }); + }); + + test('Should return Grant object with success for grantInvokeWithWebSocketStream', () => { + const grant = runtime.grantInvokeWithWebSocketStream(granteeRole); + + expect(grant).toBeDefined(); + expect(grant.success).toBe(true); + expect(grant.principalStatement).toBeDefined(); + }); }); describe('Runtime role validation tests', () => { From 7a1e8b694a78cf4ec6294868443327fc3c403615 Mon Sep 17 00:00:00 2001 From: Yuki Matsuda <13781813+mazyu36@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:42:55 +0900 Subject: [PATCH 2/3] docs(bedrock-agentcore): add grantInvokeWithWebSocketStream to README --- packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md index be41167d0beee..2fb6d8d2d8c64 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md @@ -738,6 +738,9 @@ runtime.grantInvokeRuntimeForUser(invokerFunction); // Grant both invoke permissions (most common use case) runtime.grantInvoke(invokerFunction); +// Grant permission to invoke the runtime via WebSocket stream +runtime.grantInvokeWithWebSocketStream(invokerFunction); + // Grant specific custom permissions to the runtime's execution role runtime.grant(['bedrock:InvokeModel'], ['arn:aws:bedrock:*:*:*']); From 49028e85d3d9073e95d665fdf711d3707f31ec05 Mon Sep 17 00:00:00 2001 From: Yuki Matsuda <13781813+mazyu36@users.noreply.github.com> Date: Thu, 2 Apr 2026 22:01:50 +0900 Subject: [PATCH 3/3] feat(bedrock-agentcore): add grantInvokeWithWebSocketStreamForUser method to Runtime --- .../aws-bedrock-agentcore-alpha/README.md | 4 + .../lib/runtime/perms.ts | 6 ++ .../lib/runtime/runtime-base.ts | 27 ++++++- .../test/agentcore/runtime/runtime.test.ts | 76 +++++++++++++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md index 2fb6d8d2d8c64..34e38fb6da0b4 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/README.md @@ -741,6 +741,10 @@ runtime.grantInvoke(invokerFunction); // Grant permission to invoke the runtime via WebSocket stream runtime.grantInvokeWithWebSocketStream(invokerFunction); +// Grant permission to invoke the runtime via WebSocket stream on behalf of a user +// (requires X-Amzn-Bedrock-AgentCore-Runtime-User-Id header) +runtime.grantInvokeWithWebSocketStreamForUser(invokerFunction); + // Grant specific custom permissions to the runtime's execution role runtime.grant(['bedrock:InvokeModel'], ['arn:aws:bedrock:*:*:*']); diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts index 482556e337a46..4ecb4c38332ca 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/perms.ts @@ -18,6 +18,12 @@ export const RUNTIME_INVOKE_USER_PERMS = ['bedrock-agentcore:InvokeAgentRuntimeF */ export const RUNTIME_INVOKE_WEBSOCKET_STREAM_PERMS = ['bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream']; +/** + * Permissions to invoke the agent runtime via WebSocket stream on behalf of a user + * Required when signing WebSocket connection requests with the X-Amzn-Bedrock-AgentCore-Runtime-User-Id header + */ +export const RUNTIME_INVOKE_WEBSOCKET_STREAM_USER_PERMS = ['bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStreamForUser']; + /****************************************************************************** * Control Plane Permissions *****************************************************************************/ diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts index 8547d794cf47f..51df7d4a01cc3 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/lib/runtime/runtime-base.ts @@ -28,7 +28,7 @@ import * as iam from 'aws-cdk-lib/aws-iam'; import { ValidationError } from 'aws-cdk-lib/core/lib/errors'; import { lit } from 'aws-cdk-lib/core/lib/helpers-internal'; import type { Construct } from 'constructs'; -import { RUNTIME_INVOKE_PERMS, RUNTIME_INVOKE_USER_PERMS, RUNTIME_INVOKE_WEBSOCKET_STREAM_PERMS } from './perms'; +import { RUNTIME_INVOKE_PERMS, RUNTIME_INVOKE_USER_PERMS, RUNTIME_INVOKE_WEBSOCKET_STREAM_PERMS, RUNTIME_INVOKE_WEBSOCKET_STREAM_USER_PERMS } from './perms'; /****************************************************************************** * Interface @@ -192,6 +192,14 @@ export interface IBedrockAgentRuntime extends IResource, iam.IGrantable, ec2.ICo * @param grantee The principal to grant access to */ grantInvokeWithWebSocketStream(grantee: iam.IGrantable): iam.Grant; + + /** + * Permits an IAM principal to invoke this runtime via WebSocket stream on behalf of a user + * Grants the bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStreamForUser permission + * Required when using the X-Amzn-Bedrock-AgentCore-Runtime-User-Id header with WebSocket stream + * @param grantee The principal to grant access to + */ + grantInvokeWithWebSocketStreamForUser(grantee: iam.IGrantable): iam.Grant; } /****************************************************************************** @@ -338,6 +346,23 @@ export abstract class RuntimeBase extends Resource implements IBedrockAgentRunti }); } + /** + * Permits an IAM principal to invoke this runtime via WebSocket stream on behalf of a user + * Grants the bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStreamForUser permission + * Required when using the X-Amzn-Bedrock-AgentCore-Runtime-User-Id header with WebSocket stream + * + * [disable-awslint:no-grants] + * + * @param grantee The principal to grant access to + */ + public grantInvokeWithWebSocketStreamForUser(grantee: iam.IGrantable): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee, + actions: RUNTIME_INVOKE_WEBSOCKET_STREAM_USER_PERMS, + resourceArns: [this.runtimeRef.agentRuntimeArn, `${this.runtimeRef.agentRuntimeArn}/*`], + }); + } + // ------------------------------------------------------ // Metrics // ------------------------------------------------------ diff --git a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts index f883772e681c7..bc88ac254951d 100644 --- a/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts +++ b/packages/@aws-cdk/aws-bedrock-agentcore-alpha/test/agentcore/runtime/runtime.test.ts @@ -2164,6 +2164,82 @@ describe('Runtime grantInvokeRuntime permission tests', () => { expect(grant.success).toBe(true); expect(grant.principalStatement).toBeDefined(); }); + + test('Should grant InvokeAgentRuntimeWithWebSocketStreamForUser permission with grantInvokeWithWebSocketStreamForUser', () => { + runtime.grantInvokeWithWebSocketStreamForUser(granteeRole); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + Match.objectLike({ + Action: 'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStreamForUser', + Effect: 'Allow', + Resource: [ + { + 'Fn::GetAtt': [ + Match.stringLikeRegexp('testruntime.*'), + 'AgentRuntimeArn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + Match.stringLikeRegexp('testruntime.*'), + 'AgentRuntimeArn', + ], + }, + '/*', + ], + ], + }, + ], + }), + ]), + }, + }); + }); + + test('Should grant WebSocket stream for user permission on imported runtime', () => { + const importedRuntime = Runtime.fromAgentRuntimeAttributes(stack, 'ImportedRuntimeWsUser', { + agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime-id', + agentRuntimeId: 'test-runtime-id', + agentRuntimeName: 'test-runtime', + roleArn: 'arn:aws:iam::123456789012:role/test-role', + agentRuntimeVersion: '1', + }); + + importedRuntime.grantInvokeWithWebSocketStreamForUser(granteeRole); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([ + Match.objectLike({ + Action: 'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStreamForUser', + Effect: 'Allow', + Resource: [ + 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime-id', + 'arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime-id/*', + ], + }), + ]), + }, + }); + }); + + test('Should return Grant object with success for grantInvokeWithWebSocketStreamForUser', () => { + const grant = runtime.grantInvokeWithWebSocketStreamForUser(granteeRole); + + expect(grant).toBeDefined(); + expect(grant.success).toBe(true); + expect(grant.principalStatement).toBeDefined(); + }); }); describe('Runtime role validation tests', () => {