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 +10 -0
- package/README.md +43 -16
- package/package.json +1 -1
- package/src/compilers/runtime.js +25 -0
- package/src/index.js +54 -3
- package/src/validators/schema.js +51 -0
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
|
|
93
|
-
| ------------------------------------------------ |
|
|
94
|
-
| `type` | Yes
|
|
95
|
-
| `artifact.docker.path` | Yes\*
|
|
96
|
-
| `artifact.docker.file` | No
|
|
97
|
-
| `artifact.docker.repository` | No
|
|
98
|
-
| `artifact.containerImage` | Yes\*
|
|
99
|
-
| `protocol` | No
|
|
100
|
-
| `network.networkMode` | No
|
|
101
|
-
| `authorizer.customJwtAuthorizer` | No
|
|
102
|
-
| `authorizer.customJwtAuthorizer.discoveryUrl` | Yes\*\*
|
|
103
|
-
| `authorizer.customJwtAuthorizer.allowedAudience` | No
|
|
104
|
-
| `authorizer.customJwtAuthorizer.allowedClients` | No
|
|
105
|
-
| `requestHeaders.allowlist` | No
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
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
package/src/compilers/runtime.js
CHANGED
|
@@ -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': () =>
|
|
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
|
*/
|
package/src/validators/schema.js
CHANGED
|
@@ -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: {
|