serverless-bedrock-agentcore-plugin 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Resource-based policy support for AgentCore Runtime
13
+ - Enable cross-account access to agent runtimes
14
+ - Standard IAM policy document format
15
+ - Support for multiple principals and statements
16
+ - New example: `cross-account-access` demonstrating resource policy usage
17
+ - Schema validation for `resourcePolicy` configuration
18
+ - Test coverage for resource policy builder functions
19
+
10
20
  ## [0.2.0] - 2025-12-19
11
21
 
12
22
  ### Added
package/README.md CHANGED
@@ -87,29 +87,56 @@ agents:
87
87
  - X-User-Id
88
88
  - X-Session-Id
89
89
  - Authorization
90
+ # Optional: Resource-based policy for cross-account access
91
+ resourcePolicy:
92
+ Version: '2012-10-17'
93
+ Statement:
94
+ - Sid: AllowCrossAccountInvoke
95
+ Effect: Allow
96
+ Principal:
97
+ AWS: arn:aws:iam::123456789012:role/MyRole
98
+ Action:
99
+ - bedrock-agentcore:InvokeAgentRuntime
100
+ Resource: '*'
90
101
  ```
91
102
 
92
- | Property | Required | Description |
93
- | ------------------------------------------------ | -------- | ---------------------------------------- |
94
- | `type` | Yes | `runtime` |
95
- | `artifact.docker.path` | Yes\* | Docker build context path |
96
- | `artifact.docker.file` | No | Dockerfile name (default: Dockerfile) |
97
- | `artifact.docker.repository` | No | ECR repository name |
98
- | `artifact.containerImage` | Yes\* | Pre-built container image URI |
99
- | `protocol` | No | `HTTP`, `MCP`, or `A2A` |
100
- | `network.networkMode` | No | `PUBLIC` or `VPC` |
101
- | `authorizer.customJwtAuthorizer` | No | JWT authorizer config (omit for no auth) |
102
- | `authorizer.customJwtAuthorizer.discoveryUrl` | Yes\*\* | OIDC discovery URL |
103
- | `authorizer.customJwtAuthorizer.allowedAudience` | No | Array of allowed audience values |
104
- | `authorizer.customJwtAuthorizer.allowedClients` | No | Array of allowed client IDs |
105
- | `requestHeaders.allowlist` | No | Headers to pass to runtime (max 20) |
106
- | `description` | No | Runtime description |
107
- | `roleArn` | No | Custom IAM role ARN |
103
+ | Property | Required | Description |
104
+ | ------------------------------------------------ | --------- | ---------------------------------------- |
105
+ | `type` | Yes | `runtime` |
106
+ | `artifact.docker.path` | Yes\* | Docker build context path |
107
+ | `artifact.docker.file` | No | Dockerfile name (default: Dockerfile) |
108
+ | `artifact.docker.repository` | No | ECR repository name |
109
+ | `artifact.containerImage` | Yes\* | Pre-built container image URI |
110
+ | `protocol` | No | `HTTP`, `MCP`, or `A2A` |
111
+ | `network.networkMode` | No | `PUBLIC` or `VPC` |
112
+ | `authorizer.customJwtAuthorizer` | No | JWT authorizer config (omit for no auth) |
113
+ | `authorizer.customJwtAuthorizer.discoveryUrl` | Yes\*\* | OIDC discovery URL |
114
+ | `authorizer.customJwtAuthorizer.allowedAudience` | No | Array of allowed audience values |
115
+ | `authorizer.customJwtAuthorizer.allowedClients` | No | Array of allowed client IDs |
116
+ | `requestHeaders.allowlist` | No | Headers to pass to runtime (max 20) |
117
+ | `resourcePolicy` | No | Resource-based policy (IAM policy doc) |
118
+ | `resourcePolicy.Statement` | Yes\*\*\* | Array of policy statements |
119
+ | `description` | No | Runtime description |
120
+ | `roleArn` | No | Custom IAM role ARN |
108
121
 
109
122
  \*Either `artifact.docker` or `artifact.containerImage` is required
110
123
 
111
124
  \*\*Required when using `customJwtAuthorizer`
112
125
 
126
+ \*\*\*Required when using `resourcePolicy`
127
+
128
+ #### Resource-Based Policies
129
+
130
+ Resource-based policies allow you to grant cross-account or cross-principal access to invoke your AgentCore runtime. This is useful when you need to allow another AWS account or service to invoke your agent.
131
+
132
+ Example use cases:
133
+
134
+ - **Cross-account access**: Allow an ECS task in another account to invoke your agent
135
+ - **Service-to-service**: Grant specific IAM roles permission to invoke the runtime
136
+ - **Multi-tenant architectures**: Control access across different AWS accounts
137
+
138
+ The `resourcePolicy` follows standard IAM policy document format with `Version` (defaults to `2012-10-17`) and `Statement` array.
139
+
113
140
  ### Memory
114
141
 
115
142
  Store conversation history with semantic search and summarization.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serverless-bedrock-agentcore-plugin",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Serverless Framework plugin for AWS Bedrock AgentCore - deploy Runtime, Memory, and Gateway resources",
5
5
  "main": "src/index.js",
6
6
  "engines": {
@@ -182,6 +182,26 @@ function buildRequestHeaderConfiguration(requestHeaders) {
182
182
  };
183
183
  }
184
184
 
185
+ /**
186
+ * Build resource-based policy for the runtime
187
+ * Allows cross-account or cross-principal access to invoke the agent
188
+ *
189
+ * @param {Object} resourcePolicy - The resource policy configuration from serverless.yml
190
+ * @returns {Object|null} IAM policy document or null
191
+ */
192
+ function buildResourcePolicy(resourcePolicy) {
193
+ if (!resourcePolicy || !resourcePolicy.Statement || resourcePolicy.Statement.length === 0) {
194
+ return null;
195
+ }
196
+
197
+ // Return standard IAM policy document format
198
+ // Applied via bedrock-agentcore-control put-resource-policy API after deploy
199
+ return {
200
+ Version: resourcePolicy.Version || '2012-10-17',
201
+ Statement: resourcePolicy.Statement,
202
+ };
203
+ }
204
+
185
205
  /**
186
206
  * Compile a Runtime resource to CloudFormation
187
207
  *
@@ -204,6 +224,10 @@ function compileRuntime(name, config, context, tags) {
204
224
  const envVars = buildEnvironmentVariables(config.environment);
205
225
  const requestHeaderConfig = buildRequestHeaderConfiguration(config.requestHeaders);
206
226
 
227
+ // Note: resourcePolicy is NOT included in CFN properties.
228
+ // CloudFormation doesn't support ResourcePolicy on AWS::BedrockAgentCore::Runtime.
229
+ // It is applied via the bedrock-agentcore-control put-resource-policy API after deploy.
230
+
207
231
  return {
208
232
  Type: 'AWS::BedrockAgentCore::Runtime',
209
233
  Properties: {
@@ -231,4 +255,5 @@ module.exports = {
231
255
  buildProtocolConfiguration,
232
256
  buildEnvironmentVariables,
233
257
  buildRequestHeaderConfiguration,
258
+ buildResourcePolicy,
234
259
  };
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { compileRuntime } = require('./compilers/runtime');
3
+ const { compileRuntime, buildResourcePolicy } = require('./compilers/runtime');
4
4
  const { compileRuntimeEndpoint } = require('./compilers/runtimeEndpoint');
5
5
  const { compileMemory } = require('./compilers/memory');
6
6
  const { compileGateway } = require('./compilers/gateway');
@@ -137,8 +137,11 @@ class ServerlessBedrockAgentCore {
137
137
  'after:package:compileFunctions': () => this.compileAgentCoreResources(),
138
138
  'before:package:finalize': () => this.compileAgentCoreResources(),
139
139
 
140
- // Post-deploy info
141
- 'after:deploy:deploy': () => this.displayDeploymentInfo(),
140
+ // Post-deploy: apply resource policies, then display info
141
+ 'after:deploy:deploy': async () => {
142
+ await this.applyResourcePolicies();
143
+ await this.displayDeploymentInfo();
144
+ },
142
145
 
143
146
  // Custom commands
144
147
  'agentcore:info:info': () => this.showInfo(),
@@ -972,6 +975,54 @@ class ServerlessBedrockAgentCore {
972
975
  }
973
976
  }
974
977
 
978
+ /**
979
+ * Apply resource policies to runtimes after deployment.
980
+ * CloudFormation doesn't support ResourcePolicy on AWS::BedrockAgentCore::Runtime,
981
+ * so we apply it via the bedrock-agentcore-control put-resource-policy API after deploy.
982
+ */
983
+ async applyResourcePolicies() {
984
+ const agents = this.getAgentsConfig();
985
+
986
+ if (!agents || Object.keys(agents).length === 0) {
987
+ return;
988
+ }
989
+
990
+ const agentsWithPolicies = Object.entries(agents).filter(
991
+ ([, config]) => config.type === 'runtime' && config.resourcePolicy
992
+ );
993
+
994
+ if (agentsWithPolicies.length === 0) {
995
+ return;
996
+ }
997
+
998
+ this.log.info(`Applying resource policies for ${agentsWithPolicies.length} runtime(s)...`);
999
+
1000
+ for (const [name, config] of agentsWithPolicies) {
1001
+ try {
1002
+ this.log.info(` Applying resource policy for '${name}'...`);
1003
+
1004
+ const runtimeArn = await this.getRuntimeArn(name);
1005
+ const policyDocument = buildResourcePolicy(config.resourcePolicy);
1006
+
1007
+ if (!policyDocument) {
1008
+ this.log.warning(` Skipping '${name}': resource policy has no statements`);
1009
+ continue;
1010
+ }
1011
+
1012
+ await this.provider.request('BedrockAgentCoreControl', 'putResourcePolicy', {
1013
+ resourceArn: runtimeArn,
1014
+ policy: JSON.stringify(policyDocument),
1015
+ });
1016
+
1017
+ this.log.info(` Resource policy applied successfully for '${name}'`);
1018
+ } catch (error) {
1019
+ throw new this.serverless.classes.Error(
1020
+ `Failed to apply resource policy for '${name}': ${error.message}`
1021
+ );
1022
+ }
1023
+ }
1024
+ }
1025
+
975
1026
  /**
976
1027
  * Show information about AgentCore resources
977
1028
  */
@@ -101,6 +101,57 @@ function defineAgentsSchema(serverless) {
101
101
  maxConcurrency: { type: 'number' },
102
102
  },
103
103
  },
104
+ resourcePolicy: {
105
+ type: 'object',
106
+ properties: {
107
+ Version: { type: 'string' },
108
+ Statement: {
109
+ type: 'array',
110
+ items: {
111
+ type: 'object',
112
+ properties: {
113
+ Sid: { type: 'string' },
114
+ Effect: {
115
+ type: 'string',
116
+ enum: ['Allow', 'Deny'],
117
+ },
118
+ Principal: { type: 'object' },
119
+ Action: {
120
+ oneOf: [
121
+ { type: 'string' },
122
+ {
123
+ type: 'array',
124
+ items: { type: 'string' },
125
+ },
126
+ ],
127
+ },
128
+ Resource: {
129
+ oneOf: [
130
+ { type: 'string' },
131
+ {
132
+ type: 'array',
133
+ items: { type: 'string' },
134
+ },
135
+ ],
136
+ },
137
+ Condition: { type: 'object' },
138
+ },
139
+ required: ['Effect', 'Principal', 'Action'],
140
+ },
141
+ },
142
+ },
143
+ required: ['Statement'],
144
+ },
145
+ requestHeaders: {
146
+ type: 'object',
147
+ properties: {
148
+ allowlist: {
149
+ type: 'array',
150
+ items: { type: 'string' },
151
+ maxItems: 20,
152
+ },
153
+ },
154
+ },
104
155
  endpoints: {
105
156
  type: 'array',
106
157
  items: {