Skip to content

Commit b127f8b

Browse files
authored
feat(aws): real SigV4 signing for the 8 AWS-family connectors (#118)
Self-contained AWS4-HMAC-SHA256 signer (node:crypto, no SDK) wired into the declarative-REST path via credentialPlacement 'aws-sigv4'. Credentials = JSON bundle {accessKeyId,secretAccessKey,region[,sessionToken,endpoint]} in the api-key field; region drives the {region} host template. KAT-pinned (IAM ListUsers + S3 GetObject). Follow-ups: #120, #121, #122. Closes #113.
1 parent 5392ed0 commit b127f8b

16 files changed

Lines changed: 832 additions & 60 deletions

src/connectors/adapters/amazon-bedrock.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,27 @@ import { declarativeRestConnector } from './declarative-rest.js'
1010
// per-prompt action wrappers) because that's what an agent needs to compose
1111
// arbitrary generation flows on top of.
1212
//
13-
// Region is supplied through connection metadata (metadata.region, e.g. us-east-1)
14-
// so the same connector can target any AWS region without rebuilding the manifest.
13+
// Region comes from the credential bundle in the api-key field (falling back to
14+
// metadata.region, then us-east-1) and is substituted into the {region} host
15+
// templates below, so the same connector targets any AWS region. Each request is
16+
// signed with AWS Signature V4 (`credentialPlacement: aws-sigv4`, service
17+
// `bedrock`).
1518

1619
export const amazonBedrockConnector = declarativeRestConnector({
1720
kind: 'amazon-bedrock',
1821
displayName: 'Amazon Bedrock',
1922
description: 'Invoke AWS Bedrock foundation models for text generation, image analysis, image generation, and embeddings; list available foundation models.',
20-
auth: { kind: 'api-key', hint: 'AWS access key id / secret access key pair (the connection should also carry metadata.region; requests are signed with AWS Signature V4 at the gateway).' },
23+
auth: { kind: 'api-key', hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"}. Optional "sessionToken" and "endpoint". Requests are signed with AWS Signature V4; the region selects the bedrock-runtime.<region>.amazonaws.com endpoint.' },
2124
category: 'other',
2225
// Bedrock model invocations are non-idempotent generative calls; the manifest
2326
// surfaces are advisory (best-effort), not authoritative state.
2427
defaultConsistencyModel: 'advisory',
2528
// bedrock-runtime is the workhorse endpoint for invoke/converse. Control-plane
2629
// listing operations override the host on a per-capability basis below.
27-
baseUrl: { metadataKey: 'runtimeEndpoint', fallback: 'https://bedrock-runtime.us-east-1.amazonaws.com' },
30+
credentialPlacement: { kind: 'aws-sigv4', service: 'bedrock' },
31+
baseUrl: { metadataKey: 'runtimeEndpoint', fallback: 'https://bedrock-runtime.{region}.amazonaws.com' },
2832
defaultHeaders: { 'content-type': 'application/json', accept: 'application/json' },
29-
test: { method: 'GET', path: '/foundation-models', headers: { host: 'bedrock.us-east-1.amazonaws.com' } },
33+
test: { method: 'GET', path: '/foundation-models', headers: { host: 'bedrock.{region}.amazonaws.com' } },
3034
capabilities: [
3135
{
3236
name: 'models.list',
@@ -48,9 +52,10 @@ export const amazonBedrockConnector = declarativeRestConnector({
4852
byOutputModality: '{byOutputModality}',
4953
byInferenceType: '{byInferenceType}',
5054
},
51-
// Control-plane host override; declarative-rest forwards the header to
52-
// the gateway, which rewrites the upstream Host for SigV4.
53-
headers: { host: 'bedrock.us-east-1.amazonaws.com' },
55+
// Control-plane host override: the runtime folds this `host` header into
56+
// the request URL (region substituted) so SigV4 signs the bedrock.<region>
57+
// control-plane host, not the bedrock-runtime base host.
58+
headers: { host: 'bedrock.{region}.amazonaws.com' },
5459
},
5560
},
5661
{
@@ -67,7 +72,7 @@ export const amazonBedrockConnector = declarativeRestConnector({
6772
request: {
6873
method: 'GET',
6974
path: '/foundation-models/{modelIdentifier}',
70-
headers: { host: 'bedrock.us-east-1.amazonaws.com' },
75+
headers: { host: 'bedrock.{region}.amazonaws.com' },
7176
},
7277
},
7378
{

src/connectors/adapters/amazon-s3.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ export const amazonS3Connector = declarativeRestConnector({
66
description: 'Scalable storage in the cloud. Read, upload, delete, and manage files in S3 buckets.',
77
auth: {
88
kind: 'api-key',
9-
hint: 'AWS Access Key ID and Secret Access Key. Provide credentials for IAM user with S3 permissions.',
9+
hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"} for an IAM principal with S3 permissions. Optional "sessionToken" and "endpoint" (S3-compatible stores). Requests are signed with AWS Signature V4; the region selects the s3.<region>.amazonaws.com endpoint.',
1010
},
1111
category: 'storage',
1212
defaultConsistencyModel: 'authoritative',
13-
baseUrl: 'https://s3.amazonaws.com',
13+
// S3 REST API, path-style. Each request is signed with AWS Signature V4
14+
// (service `s3`, which signs the request path verbatim); the bundle's region
15+
// is substituted into the `{region}` host template.
16+
credentialPlacement: { kind: 'aws-sigv4', service: 's3' },
17+
baseUrl: 'https://s3.{region}.amazonaws.com',
1418
test: { method: 'GET', path: '/' },
1519
capabilities: [
1620
{

src/connectors/adapters/amazon-secrets-manager.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import { declarativeRestConnector } from './declarative-rest.js'
22

3-
// AWS Secrets Manager Query Protocol endpoint. Region is bound into the
4-
// host at credential-mint time; the metadataKey indirection lets callers
5-
// override per-tenant without touching the manifest.
3+
// AWS Secrets Manager JSON 1.1 protocol endpoint. Each request is signed with
4+
// AWS Signature V4 (`credentialPlacement: aws-sigv4`) from the credential
5+
// bundle in the api-key field; the bundle's region is substituted into the
6+
// `{region}` host template, and the metadataKey indirection still lets callers
7+
// override the host per-tenant without touching the manifest.
68
export const amazonSecretsManagerConnector = declarativeRestConnector({
79
kind: 'amazon-secrets-manager',
810
displayName: 'AWS Secrets Manager',
911
description:
1012
'Create, read, update, find, and delete secrets in AWS Secrets Manager, or generate a random password.',
1113
auth: {
1214
kind: 'api-key',
13-
hint: 'AWS access key id + secret access key + region (api-key field carries the SigV4 credential bundle).',
15+
hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"}. Optional "sessionToken" and "endpoint". Requests are signed with AWS Signature V4; the region selects the secretsmanager.<region>.amazonaws.com endpoint.',
1416
},
1517
category: 'other',
1618
defaultConsistencyModel: 'authoritative',
19+
credentialPlacement: { kind: 'aws-sigv4', service: 'secretsmanager' },
1720
baseUrl: {
1821
metadataKey: 'endpoint',
19-
fallback: 'https://secretsmanager.us-east-1.amazonaws.com',
22+
fallback: 'https://secretsmanager.{region}.amazonaws.com',
2023
},
2124
defaultHeaders: {
2225
'Content-Type': 'application/x-amz-json-1.1',

src/connectors/adapters/amazon-ses.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ export const amazonSesConnector = declarativeRestConnector({
2020
description: 'Send transactional and templated email and manage SES email templates via the Amazon SES v2 REST API.',
2121
auth: {
2222
kind: 'api-key',
23-
hint: 'AWS access key ID + secret access key with ses:SendEmail / ses:SendTemplatedEmail / template-management permissions. The region selects the SES endpoint (e.g. us-east-1).',
23+
hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"} (the key needs ses:SendEmail / ses:SendTemplatedEmail / template-management permissions). Optional "sessionToken" and "endpoint". Requests are signed with AWS Signature V4; the region selects the email.<region>.amazonaws.com (SES v2) endpoint.',
2424
},
2525
category: 'comms',
2626
defaultConsistencyModel: 'authoritative',
27-
baseUrl: { metadataKey: 'endpoint' },
27+
// SES v2 REST API: the SigV4 signing name is `ses`, but the regional host is
28+
// the `email.` subdomain. metadata.endpoint still overrides when a tenant
29+
// pins a host.
30+
credentialPlacement: { kind: 'aws-sigv4', service: 'ses' },
31+
baseUrl: { metadataKey: 'endpoint', fallback: 'https://email.{region}.amazonaws.com' },
2832
test: { method: 'GET', path: '/v2/email/identities' },
2933
capabilities: [
3034
{

src/connectors/adapters/amazon-sns.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
import { declarativeRestConnector } from './declarative-rest.js'
22

33
// Amazon SNS uses the AWS Query Protocol (form/query string parameters with
4-
// Action=<Op>&Version=2010-03-31). Region is bound into the host at
5-
// credential-mint time; the `metadataKey: 'endpoint'` indirection lets a
6-
// caller pin region per tenant without rewriting the manifest. SigV4 is
7-
// performed by the credential layer; the api-key field carries the
8-
// SigV4 credential bundle (accessKeyId + secretAccessKey + region).
4+
// Action=<Op>&Version=2010-03-31). Each request is signed with AWS Signature V4
5+
// (`credentialPlacement: aws-sigv4`) from the credential bundle in the api-key
6+
// field; the bundle's region is substituted into the `{region}` host template,
7+
// and the `metadataKey: 'endpoint'` indirection still lets a caller pin a host
8+
// per tenant without rewriting the manifest.
99
export const amazonSnsConnector = declarativeRestConnector({
1010
kind: 'amazon-sns',
1111
displayName: 'Amazon SNS',
1212
description:
1313
'Publish messages to Amazon Simple Notification Service topics, manage topics, and manage subscriptions.',
1414
auth: {
1515
kind: 'api-key',
16-
hint: 'AWS access key id + secret access key + region (api-key field carries the SigV4 credential bundle).',
16+
hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"}. Optional "sessionToken" and "endpoint". Requests are signed with AWS Signature V4; the region selects the sns.<region>.amazonaws.com endpoint.',
1717
},
1818
category: 'comms',
1919
defaultConsistencyModel: 'authoritative',
20+
credentialPlacement: { kind: 'aws-sigv4', service: 'sns' },
2021
baseUrl: {
2122
metadataKey: 'endpoint',
22-
fallback: 'https://sns.us-east-1.amazonaws.com',
23+
fallback: 'https://sns.{region}.amazonaws.com',
2324
},
2425
defaultHeaders: {
2526
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',

src/connectors/adapters/amazon-sqs.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { declarativeRestConnector } from './declarative-rest.js'
22

33
// AWS SQS JSON protocol (sqs.<region>.amazonaws.com). All actions are POST to
4-
// the service root with X-Amz-Target: AmazonSQS.<Action> and JSON body; the
5-
// gateway signs requests with SigV4 using the credential bundle in the api-key
6-
// field. Region is bound into the host via metadata.endpoint at credential-mint
7-
// time so the same manifest targets any AWS region.
4+
// the service root with X-Amz-Target: AmazonSQS.<Action> and a JSON body. Each
5+
// request is signed with AWS Signature V4 (`credentialPlacement: aws-sigv4`)
6+
// from the credential bundle in the api-key field; the bundle's region is
7+
// substituted into the `{region}` host template so one manifest targets any
8+
// AWS region.
89
//
910
// The activepieces catalog surfaces only send.message, but a usable SQS adapter
1011
// for an agent must cover the full messaging primitive: send / receive / delete
@@ -19,16 +20,17 @@ export const amazonSqsConnector = declarativeRestConnector({
1920
'Send, receive, and delete messages on AWS SQS queues, and discover queue URLs and attributes.',
2021
auth: {
2122
kind: 'api-key',
22-
hint: 'AWS access key id + secret access key + region (api-key field carries the SigV4 credential bundle; metadata.endpoint may override the regional host).',
23+
hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"}. Optional "sessionToken" (STS temp creds) and "endpoint" (override host). Requests are signed with AWS Signature V4; the region selects the sqs.<region>.amazonaws.com endpoint.',
2324
},
2425
category: 'other',
2526
// SQS is an at-least-once durable queue: sends, deletes, and queue-attribute
2627
// reads are authoritative against the service. Receive returns a transient
2728
// visibility-locked view, but the queue state itself is authoritative.
2829
defaultConsistencyModel: 'authoritative',
30+
credentialPlacement: { kind: 'aws-sigv4', service: 'sqs' },
2931
baseUrl: {
3032
metadataKey: 'endpoint',
31-
fallback: 'https://sqs.us-east-1.amazonaws.com',
33+
fallback: 'https://sqs.{region}.amazonaws.com',
3234
},
3335
defaultHeaders: {
3436
'Content-Type': 'application/x-amz-json-1.0',

src/connectors/adapters/amazon-textract.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { declarativeRestConnector } from './declarative-rest.js'
22

33
// AWS Textract is exposed via the JSON 1.1 query protocol: a single POST to /
44
// with the X-Amz-Target header naming the operation
5-
// (Textract.AnalyzeDocument, Textract.DetectDocumentText, etc.). Region binds
6-
// into the host at credential-mint time; metadataKey 'endpoint' allows
7-
// per-tenant override (textract.<region>.amazonaws.com).
5+
// (Textract.AnalyzeDocument, Textract.DetectDocumentText, etc.). Each request is
6+
// signed with AWS Signature V4 (`credentialPlacement: aws-sigv4`) from the
7+
// credential bundle in the api-key field; the bundle's region is substituted
8+
// into the `{region}` host template, and metadataKey 'endpoint' still allows a
9+
// per-tenant host override (textract.<region>.amazonaws.com).
810
//
911
// The catalog enumerates 5 actions (AnalyzeDocument, DetectDocumentText,
1012
// AnalyzeExpense, AnalyzeId, AnalyzeDocumentAsync). The async path returns a
@@ -24,13 +26,14 @@ export const amazonTextractConnector = declarativeRestConnector({
2426
'Extract text, forms, tables, signatures, and structured data (expense, identity) from documents using AWS Textract.',
2527
auth: {
2628
kind: 'api-key',
27-
hint: 'AWS access key id + secret access key + region (api-key field carries the SigV4 credential bundle; the gateway signs each request).',
29+
hint: 'AWS credentials as JSON: {"accessKeyId":"AKIA…","secretAccessKey":"…","region":"us-east-1"}. Optional "sessionToken" and "endpoint". Requests are signed with AWS Signature V4; the region selects the textract.<region>.amazonaws.com endpoint.',
2830
},
2931
category: 'other',
3032
defaultConsistencyModel: 'authoritative',
33+
credentialPlacement: { kind: 'aws-sigv4', service: 'textract' },
3134
baseUrl: {
3235
metadataKey: 'endpoint',
33-
fallback: 'https://textract.us-east-1.amazonaws.com',
36+
fallback: 'https://textract.{region}.amazonaws.com',
3437
},
3538
defaultHeaders: {
3639
'Content-Type': 'application/x-amz-json-1.1',

0 commit comments

Comments
 (0)