AWS Bedrock Marketplace
Subscribe through AWS Marketplace and launch one IAM role, so Chio admits each Bedrock Converse request before the model runs.
On this page
Amazon Bedrock traffic bought through the Chio listing on AWS Marketplace reaches the model only after Chio admits it. The listing puts the kernel between your agents and Bedrock without moving the control plane into your account.
The Chio control plane runs in the Chio seller account. For each Converse request it checks your Marketplace entitlement and the bound IAM principal, evaluates policy and guards, and signs a receipt, and only then calls Bedrock through one role in your account. Receipt volume above your base contract becomes Marketplace metering.
StartChio admits the request, then assumes your role
Agent traffic reaches the Chio control plane first. It checks the Marketplace entitlement and the bound IAM principal, evaluates policy and guards, signs the receipt, and only then calls Bedrock Converse through ChioBedrockIntegrationRole. The mediated call.
Your account holds one role and one SSM parameter; entitlement lookup and metering both run from the seller account. If entitlement lookup, principal binding, guard evaluation, receipt issuance, or metering preparation fails, Chio refuses the request before it assumes your role, and Bedrock access stays refused until entitlement or metering state is repaired.
1. Subscribe and collect your onboarding values
Accept the Chio listing's SaaS contract in AWS Marketplace, which creates your tenant entitlement in the seller account. Chio onboarding then issues four values for the Quick Launch template: the tenant ID, the control-plane endpoint, the external ID, and the seller principal ARN. Write them into parameters.json.
[
{
"ParameterKey": "ChioControlPlaneEndpoint",
"ParameterValue": "https://control.chio.computer/tenants/larkfield"
},
{
"ParameterKey": "ChioTenantId",
"ParameterValue": "larkfield"
},
{
"ParameterKey": "ExternalId",
"ParameterValue": "replace-with-tenant-external-id"
},
{
"ParameterKey": "ChioSellerAccountPrincipalArn",
"ParameterValue": "arn:aws:iam::444455556666:role/chio-control-plane"
}
]You should have four parameters. The template checks each one at launch: the endpoint must start with https://, the tenant ID is 1 to 32 characters, and the external ID is at least 16 characters and stored NoEcho.
2. Launch the integration role in us-east-1
From the root of the integration source, with the AWS CLI and the SAM CLI pointed at your account, validate the template and create the stack. The stack creates an IAM role, so the call needs CAPABILITY_IAM.
sam validate \
--template integrations/aws-bedrock/cloudformation/quick-launch.yaml \
--lint
aws cloudformation create-stack \
--region us-east-1 \
--stack-name chio-bedrock-larkfield \
--capabilities CAPABILITY_IAM \
--template-body file://integrations/aws-bedrock/cloudformation/quick-launch.yaml \
--parameters file://integrations/aws-bedrock/cloudformation/parameters.json{
"StackId": "arn:aws:cloudformation:us-east-1:111122223333:stack/chio-bedrock-larkfield/…"
}You should see a stack ID in us-east-1. The template's IsSupportedRegion condition creates nothing in any other region, so a stack launched elsewhere leaves Chio no role to assume. Inside us-east-1 it creates two resources: ChioBedrockIntegrationRole and an SSM parameter holding the control-plane endpoint at /chio/bedrock/{ChioTenantId}/control-plane-endpoint.
3. Hand Chio the role it may assume
Read the stack's three outputs and send IntegrationRoleArn to the Chio onboarding operator.
aws cloudformation describe-stacks \
--region us-east-1 \
--stack-name chio-bedrock-larkfield \
--query "Stacks[0].Outputs[].[OutputKey,OutputValue]" \
--output textSupportedRegion us-east-1 IntegrationRoleArn arn:aws:iam::111122223333:role/chio-bedrock-larkfield-… ControlPlaneEndpointParameter /chio/bedrock/larkfield/control-plane-endpoint
The role trusts only the seller principal, and only when the assume-role call carries your external ID. Its inline policy grants bedrock:InvokeModel and bedrock:InvokeModelWithResponseStream on us-east-1 foundation models, plus sts:GetCallerIdentity. With the ARN in hand, Chio calls sts:GetCallerIdentity through the role, binds the resolved IAM principal to your tenant, checks GetEntitlements, and enables governed Bedrock traffic. From then on every allow, deny, receipt, and overage decision is recorded.
4. Send a Converse request through Chio
The Python client chio-bedrock imports as chio_bedrock and wraps the Bedrock runtime client you inject: a boto3 bedrock-runtime client in production, or any object with a converse method in tests. This excerpt takes the runtime client and an enabled model ID from your deployment configuration.
from chio_bedrock import BedrockChioClient
client = BedrockChioClient(
bedrock_runtime=my_bedrock_runtime_client,
principal_arn="arn:aws:sts::111122223333:assumed-role/chio-bedrock/larkfield",
account_id="111122223333",
)
invocation = client.converse(
tenant_id="larkfield",
capability_id="cap-bedrock-a",
model_id=model_id,
messages=[{"role": "user", "content": [{"text": "hello"}]}],
)You should get a BedrockInvocation with three fields: response, the Bedrock reply; receipt, a Chio receipt-compatible mapping; and metering, the Marketplace metering callback payload. The client checks the receipt it issued and raises instead of returning one that fails verification. Inject a runtime that reaches Bedrock through the governed path; a runtime with its own direct credentials sits outside the mediation boundary.
5. Read the principal trail and meter the receipt
Each receipt carries the IAM principal trail: Chio assumed ChioBedrockIntegrationRole with your external ID, called sts:GetCallerIdentity before the request, and wrote the resolved principal ARN and AWS account ID into the receipt metadata. A principal that cannot be resolved, or that does not match the signed tenant binding, is refused before the adapter invokes Converse or ConverseStream.
client = BedrockChioClient(
bedrock_runtime=my_bedrock_runtime_client,
principal_arn="arn:aws:sts::111122223333:assumed-role/chio-bedrock/larkfield",
account_id="111122223333",
customer_identifier="customer-123",
product_code="prod-chio-bedrock",
trusted_kernel_keys=[kernel_public_key_hex],
)
payload = client.emit_metering(
receipt=mediated_receipt,
invocation_parameters={"modelId": model_id},
dimension="bedrock_receipt_overage",
quantity=1,
)You should get a metering payload only for an authoritative mediated receipt signed by a kernel whose public key the client trusts. A client without trusted_kernel_keys raises instead of metering, and a receipt that fails verification raises MeteringTrustError, so no caller can bill against a receipt it minted itself. The verifier holds public keys only. Overage metering references the receipt ID and the tenant identifier.
Two dimensions price the listing
The listing pairs a per-tenant annual base entitlement with a metered receipt-overage dimension. The customer's Marketplace agreement supplies the prices and billing terms.
| Dimension | Unit | Billing term | Covers |
|---|---|---|---|
tenant_base | tenant | annual | Governed Bedrock tenant base entitlement |
bedrock_receipt_overage | receipt | metered_overage | Receipts beyond the tenant base contract |
The seller aggregates receipt overage and submits AWS BatchMeterUsage from the seller account. AWS deduplicates SaaS usage by customer, dimension, and hour, so the hour's quantity is aggregated before submission. Overage is never reported for a tenant whose entitlement is inactive or expired.
Tool calls inside a Converse reply cross the same kernel
The listing wraps chio-bedrock-converse-adapter, which carries tool use in both directions. When a model reply asks for a tool, the adapter lifts the toolUse block into the shared ToolInvocation shape before anything runs.
κcapabilityσscopegguardsBbudget
Lift, admit, lower, with the same call ID
The adapter lifts the native call into a ToolInvocation that names the provider, the tool, the canonical-JSON argument bytes, and a provenance stamp. The kernel admits it and dispatches the registered tool, and the adapter lowers the output into a native reply with the same call ID. Govern Any Provider.
The invocation names the provider, the tool, the canonical-JSON argument bytes, and a provenance stamp. The kernel admits it and dispatches the registered tool, and the adapter lowers the output, or the refusal with its signed deny receipt, back into a toolResult block with the same call ID. On a stream, frames from contentBlockStart through contentBlockStop are buffered and the completed block is evaluated before any of its bytes are released: flushed on allow, dropped on deny.
Read more in Govern Any Provider Tool Calls.
Listing reference
Try ExternalId, MissingEntitlement, emit_metering, or BEDROCK_REGION.
Quick Launch parameters
| Parameter | Constraint | Purpose |
|---|---|---|
Chio | ^https://.+ | Tenant gateway URL supplied by Chio; stored in SSM Parameter Store |
ChioTenantId | 1 to 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 |
Chio | ^arn:aws:iam::[0-9]{12}:(root|role/.+)$ | Chio seller account root or control-plane role ARN, trusted to assume the integration role |
Stack outputs
SupportedRegion. The integration region,us-east-1.IntegrationRoleArn. ARN ofChioBedrockIntegrationRole, the role Chio assumes.ControlPlaneEndpointParameter. Name of the SSM parameter holding the control-plane endpoint.
Role trust and permissions
The trust policy pins the external-ID condition on the assume-role statement. The inline policy is the minimum for 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. The customer role holds no Marketplace entitlement or metering permissions.
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: !Ref ChioSellerAccountPrincipalArn
Action: "sts:AssumeRole"
Condition:
StringEquals:
"sts:ExternalId": !Ref ExternalId{
"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": "*"
}
]
}Entitlement contract
The chio-bedrock-control-plane crate holds the fail-closed entitlement and metering contract. Its public APIs are deterministic and testable without AWS credentials; the seller binds 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 receipt_id = "1faf4bc1566804062e145ef5cb2f95f8289ba448a2fe5b62a180c4381ff73007";
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: receipt_id.into(),
},
now_epoch_secs,
)?;
assert_eq!(event.api, MeteringApi::MeterUsage);Every failure 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.
MissingCustomerIdentifier. The customer identifier is empty or whitespace-padded.MissingProductCode. The product code is empty or whitespace-padded.MissingDimension. The dimension is empty or whitespace-padded.MissingEntitlement. No record matches the customer, product, and dimension triple.InactiveEntitlement. A record exists and is marked inactive.ExpiredEntitlement. The record's expiry is at or before the supplied epoch.
Metering helpers
meter_usage validates one MeteringUsage and checks the entitlement again before it emits a MeteringEvent tagged MeteringApi::MeterUsage. batch_meter_usage folds a MeteringBatch into events tagged MeteringApi::BatchMeterUsage. These tags are internal contract values; the AWS product's billing API is BatchMeterUsage, which the seller submits with the aggregated overage.
A quantity of zero fails with QuantityMustBePositive and an empty receipt ID with MissingReceiptId. An inactive or expired entitlement surfaces as MeteringError::Entitlement. When metering is refused, the customer receives a fail-closed error envelope carrying urn:chio:error:aws-bedrock:marketplace-entitlement-denied.
AWS identifies new SaaS customers by CustomerAWSAccountId and LicenseArn; the seller resolves the agreement identity at its edge before it submits usage. Follow the AWS SaaS metering contract and the BatchMeterUsage fields.
Python client options
converse. Keyword-only. Optionalinference_config,tool_config, andadditional_model_request_fieldspass through to the runtime request under their Bedrock names.- Construction. Rejects any region other than
us-east-1, and an emptyprincipal_arnoraccount_id. - Source.
sdks/python/packages/chio-bedrockin the Chio repository.
Adapter pins
chio-bedrock-converse-adapter is pinned to BEDROCK_REGION (us-east-1) and BEDROCK_CONVERSE_API_VERSION (bedrock.converse.v1), and rejects any construction that drifts from either pin. 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.