BuildEvent-drivennew
AWS Bedrock Marketplace
Use an AWS Marketplace SaaS listing to route Amazon Bedrock requests through Chio for entitlement, policy, guards, and receipts.
Runtime Boundary
Every Bedrock request must cross Chio first. Chio validates the tenant's Marketplace entitlement, evaluates policy, runs guards, signs the receipt, and only then invokes Bedrock through the customer role. If entitlement lookup, IAM principal binding, guard evaluation, receipt issuance, or metering preparation fails, Chio denies the request before any unmetered Bedrock traffic is released. The receipt records the security decision. Bedrock calls without a receipt or metering preparation are denied.
Single-region listing
us-east-1 only, matching the adapter's region pin. The template's IsSupportedRegion condition creates no resources outside us-east-1, so a stack launched in another region produces nothing to assume. Additional regions are recorded as future candidates and require a fresh fixture pass for IAM principal binding, receipt hashing, Bedrock model availability, and Marketplace review artifacts.Quick Launch
The customer deploys cloudformation/quick-launch.yaml in their own AWS account. The template creates two resources: the integration role Chio assumes, and an SSM parameter holding the Chio control-plane endpoint at /chio/bedrock/{ChioTenantId}/control-plane-endpoint. It does not grant Marketplace entitlement or metering permissions in the customer account; those APIs run from the Chio seller account.
| Parameter | Constraint | Purpose |
|---|---|---|
ChioControlPlaneEndpoint | ^https://.+ | Tenant gateway URL supplied by Chio; stored in SSM Parameter Store. |
ChioTenantId | 1–32 chars, ^[A-Za-z0-9+=,.@_-]+$ | Tenant identifier issued during onboarding; used for stack naming and SSM pathing. |
ExternalId | NoEcho, min 16 chars | Tenant-specific external ID gating cross-account sts:AssumeRole. |
ChioSellerAccountPrincipalArn | ^arn:aws:iam::[0-9]{12}:(root|role/.+)$ | Chio seller account root or control-plane role ARN, trusted to assume the integration role. |
Validate the template, then deploy it in us-east-1. The template creates an IAM role, so the deploy needs CAPABILITY_IAM.
# Validate against the CloudFormation lint rules
$ sam validate \
--template integrations/aws-bedrock/cloudformation/quick-launch.yaml \
--lint
# Deploy the integration role in the customer account
$ aws cloudformation create-stack \
--region us-east-1 \
--stack-name chio-bedrock-tenant-a \
--capabilities CAPABILITY_IAM \
--template-body file://integrations/aws-bedrock/cloudformation/quick-launch.yaml \
--parameters file://integrations/aws-bedrock/cloudformation/parameters.jsonThe stack exports three outputs. Send IntegrationRoleArn to the Chio onboarding operator.
| Output | Value |
|---|---|
SupportedRegion | The listing region, us-east-1. |
IntegrationRoleArn | ARN of ChioBedrockIntegrationRole, the role Chio assumes. |
ControlPlaneEndpointParameter | Name of the SSM parameter holding the control-plane endpoint. |
The Integration Role
The role trusts only the Chio seller principal, and only when the assume-role call carries the tenant-specific external ID. Its inline policy grants the minimum needed to run governed Bedrock traffic from us-east-1: the two runtime invoke actions pinned to the foundation-model ARN, plus sts:GetCallerIdentity so Chio can resolve and bind the caller before any request.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "InvokePinnedBedrockRuntime",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:us-east-1::foundation-model/*"
},
{
"Sid": "BindCallerIdentityForReceipts",
"Effect": "Allow",
"Action": "sts:GetCallerIdentity",
"Resource": "*"
}
]
}The trust policy pins the external-ID condition on the assume-role statement:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: !Ref ChioSellerAccountPrincipalArn
Action: "sts:AssumeRole"
Condition:
StringEquals:
"sts:ExternalId": !Ref ExternalIdOnboarding Flow
The customer-facing integration reduces to five auditable steps.
- Subscribe. Accept the AWS Marketplace SaaS contract so the tenant entitlement exists in the seller account.
- Launch. Deploy the Quick Launch template in
us-east-1with the Chio tenant ID, control-plane endpoint, external ID, and seller principal ARN. - Hand off. Send the output
IntegrationRoleArnto the Chio onboarding operator. - Bind. Chio verifies
sts:GetCallerIdentity, binds the resolved IAM principal to the tenant, and checksGetEntitlements. - Enable. Governed Bedrock traffic is turned on; every allow, deny, receipt, and overage decision is recorded from that point.
Entitlement Contract
The chio-bedrock-control-plane crate models the fail-closed entitlement and metering contract. Its public APIs are deterministic and testable without AWS credentials; production callers bind the decisions to aws-sdk-marketplaceentitlement and aws-sdk-marketplacemetering clients at the process edge. An EntitlementStore holds EntitlementRecord rows keyed by the (customer_identifier, product_code, dimension) triple, and check returns an EntitlementDecision only when a matching record is active and unexpired at the supplied epoch.
use chio_bedrock_control_plane::{
meter_usage, EntitlementRecord, EntitlementStore, MeteringApi, MeteringUsage,
};
// Seed the tenant entitlement resolved from GetEntitlements.
let mut store = EntitlementStore::default();
store.insert(EntitlementRecord {
customer_identifier: "customer-123".into(),
product_code: "prod-chio-bedrock".into(),
dimension: "bedrock_receipt_overage".into(),
expires_at_epoch_secs: 1_900_000_000,
active: true,
})?;
// Fail-closed check before onboarding the tenant.
let decision = store.check(
"customer-123",
"prod-chio-bedrock",
"bedrock_receipt_overage",
now_epoch_secs,
)?;
// Report one receipt of overage past the base contract.
let event = meter_usage(
&store,
MeteringUsage {
customer_identifier: decision.customer_identifier,
product_code: decision.product_code,
dimension: decision.dimension,
quantity: 1,
timestamp_epoch_secs: now_epoch_secs,
receipt_id: "rcpt-overage-0002".into(),
},
now_epoch_secs,
)?;
assert_eq!(event.api, MeteringApi::MeterUsage);Every failure path is a distinct EntitlementError variant, so onboarding and metering both fail closed with a precise reason. Leading or trailing whitespace on an identifier is rejected at insert and check time rather than silently normalized.
| Variant | Meaning |
|---|---|
MissingCustomerIdentifier | Customer identifier is empty or whitespace-padded. |
MissingProductCode | Product code is empty or whitespace-padded. |
MissingDimension | Dimension is empty or whitespace-padded. |
MissingEntitlement | No record matches the customer, product, and dimension triple. |
InactiveEntitlement | A record exists but is marked inactive. |
ExpiredEntitlement | The record's expiry is at or before the supplied epoch. |
Metering Overage
Receipt volume above the tenant base contract becomes Marketplace metering. meter_usage validates one MeteringUsage and re-checks the entitlement before emitting a MeteringEvent tagged MeteringApi::MeterUsage; batch_meter_usage folds a MeteringBatch into events tagged MeteringApi::BatchMeterUsage, which the process edge maps to the AWS MeterUsage and BatchMeterUsage APIs respectively. A quantity of zero fails with QuantityMustBePositive, and an empty receipt ID fails with MissingReceiptId; an inactive or expired entitlement surfaces as MeteringError::Entitlement, so overage can never be reported for a tenant that is not currently entitled. When metering is denied, the customer sees a fail-closed error envelope carrying urn:chio:error:aws-bedrock:marketplace-entitlement-denied.
Metering runs from the seller account
Pricing Dimensions
The listing is an AWS Marketplace SaaS contract with a locked shape: a per-tenant annual base entitlement plus a metered receipt-overage dimension. The exact price is managed in Partner Central; the shape is fixed for review.
| Dimension | Unit | Billing term | Description |
|---|---|---|---|
tenant_base | tenant | annual | Annual governed Bedrock tenant base entitlement. |
bedrock_receipt_overage | receipt | metered_overage | Metered receipt overage beyond the tenant base contract. |
IAM Principal Trail
The security-review package records the IAM principal trail for every Bedrock request. Chio assumes ChioBedrockIntegrationRole with the tenant-specific external ID, calls sts:GetCallerIdentity before the request, and writes the resolved IAM principal ARN and AWS account ID into the receipt metadata. Overage metering references the receipt ID and tenant identifier, while the Marketplace API calls run from the Chio seller account. The trail is fail-closed: if the principal cannot be resolved or does not match the signed tenant binding, Chio denies the request before the adapter invokes Converse or ConverseStream.
Under the hood, the listing wraps the chio-bedrock-converse-adapter, which is pinned to BEDROCK_REGION (us-east-1) and BEDROCK_CONVERSE_API_VERSION (bedrock.converse.v1). It lifts Bedrock toolUse blocks into the shared ToolInvocation shape, lowers kernel verdicts back into toolResult blocks, and resolves the caller into the shared Principal::BedrockIam shape. The adapter rejects any construction that drifts from the us-east-1 region and API pin.
Next Steps
- AWS Lambda · run the kernel as a Lambda Extension for serverless tool servers on the same account
- Metering spec · the usage-accounting model that receipt overage maps onto
- Export billing records · turn receipts into billing artifacts downstream of metering
- Receipt format · the canonical receipt shape whose metadata carries the IAM principal trail
- Trust model · where the entitlement, IAM binding, and receipt boundaries sit