Chio/Docs

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.

rendering…
Traffic enters Chio first. The customer role is assumed only after entitlement and IAM principal binding pass. Marketplace metering runs from the Chio seller account, not the customer role.

Single-region listing

The listed region is 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.

ParameterConstraintPurpose
ChioControlPlaneEndpoint^https://.+Tenant gateway URL supplied by Chio; stored in SSM Parameter Store.
ChioTenantId1–32 chars, ^[A-Za-z0-9+=,.@_-]+$Tenant identifier issued during onboarding; used for stack naming and SSM pathing.
ExternalIdNoEcho, min 16 charsTenant-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.

bash
# 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.json

The stack exports three outputs. Send IntegrationRoleArn to the Chio onboarding operator.

OutputValue
SupportedRegionThe listing region, us-east-1.
IntegrationRoleArnARN of ChioBedrockIntegrationRole, the role Chio assumes.
ControlPlaneEndpointParameterName 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.

iam/customer-attach.json
{
  "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:

yaml
AssumeRolePolicyDocument:
  Version: "2012-10-17"
  Statement:
    - Effect: Allow
      Principal:
        AWS: !Ref ChioSellerAccountPrincipalArn
      Action: "sts:AssumeRole"
      Condition:
        StringEquals:
          "sts:ExternalId": !Ref ExternalId

Onboarding 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-1 with the Chio tenant ID, control-plane endpoint, external ID, and seller principal ARN.
  • Hand off. Send the output IntegrationRoleArn to the Chio onboarding operator.
  • Bind. Chio verifies sts:GetCallerIdentity, binds the resolved IAM principal to the tenant, and checks GetEntitlements.
  • 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.

rust
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.

VariantMeaning
MissingCustomerIdentifierCustomer identifier is empty or whitespace-padded.
MissingProductCodeProduct code is empty or whitespace-padded.
MissingDimensionDimension is empty or whitespace-padded.
MissingEntitlementNo record matches the customer, product, and dimension triple.
InactiveEntitlementA record exists but is marked inactive.
ExpiredEntitlementThe 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

The customer role holds no Marketplace permissions. Entitlement lookup and metering calls execute from the Chio seller account and are bound to the SaaS contract. A metering incident is treated as fail-closed: Chio denies unmetered Bedrock access until the entitlement or metering state is repaired.

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.

DimensionUnitBilling termDescription
tenant_basetenantannualAnnual governed Bedrock tenant base entitlement.
bedrock_receipt_overagereceiptmetered_overageMetered 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