diff --git a/aigw/integrations/libraries/claude-code-bedrock.mdx b/aigw/integrations/libraries/claude-code-bedrock.mdx
index 7d2be14f2..8d3cbc20c 100644
--- a/aigw/integrations/libraries/claude-code-bedrock.mdx
+++ b/aigw/integrations/libraries/claude-code-bedrock.mdx
@@ -27,6 +27,10 @@ Enter your AWS credentials:
Create a slug like `bedrock-prod`.
+
+**IAM permissions:** the credentials (or assumed role) you use here need `bedrock:InvokeModel`, `bedrock:InvokeModelWithResponseStream` **and** `bedrock:CountTokens`. Claude Code calls the count-tokens API on every turn, so a role without it fails with `is not authorized to perform: bedrock:CountTokens`. Add `bedrock:GetInferenceProfile` if your model ID is an inference profile ARN. See [Connect Bedrock with Amazon Assumed Role](/aigw/product/model-catalog/connect-bedrock-with-amazon-assumed-role) for the full policy.
+
+
diff --git a/aigw/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx b/aigw/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
index a9222907a..73325c018 100644
--- a/aigw/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
+++ b/aigw/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
@@ -15,6 +15,8 @@ This role you create will be used by the AI Gateway to execute InvokeModel comma
### Create a permission policy in your AWS account using the following JSON
+These actions cover standard inference — chat completions, the Messages API, embeddings, image generation, and token counting:
+
```json
{
"Version": "2012-10-17",
@@ -24,7 +26,8 @@ This role you create will be used by the AI Gateway to execute InvokeModel comma
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
- "bedrock:InvokeModelWithResponseStream"
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens"
],
"Resource": "*"
}
@@ -32,6 +35,98 @@ This role you create will be used by the AI Gateway to execute InvokeModel comma
}
```
+
+`bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` also authorize the Converse and ConverseStream APIs, which the AI Gateway uses for most models.
+
+`bedrock:CountTokens` backs the `/v1/messages/count_tokens` endpoint. Clients such as Claude Code call it on every turn, so omitting it shows up as `is not authorized to perform: bedrock:CountTokens`. It is a recent addition to Bedrock — roles created before it existed need it added explicitly.
+
+
+### Additional permissions by feature
+
+Add these only if you use the corresponding feature — everything else works with the three actions above.
+
+| Feature | Additional actions |
+| :-- | :-- |
+| [Inference profiles](/aigw/integrations/llms/bedrock/aws-bedrock#inference-profiles) (the model ID is an inference profile ARN) | `bedrock:GetInferenceProfile` |
+| Model discovery (listing Bedrock models through the AI Gateway) | `bedrock:ListFoundationModels` |
+| [Bedrock Guardrails](/aigw/integrations/guardrails/bedrock-guardrails) | `bedrock:ApplyGuardrail` |
+| [Reranking](/aigw/integrations/llms/bedrock/rerank) | `bedrock:Rerank` |
+| [Batch inference](/aigw/integrations/llms/bedrock/batches) | `bedrock:CreateModelInvocationJob`, `bedrock:GetModelInvocationJob`, `bedrock:ListModelInvocationJobs`, `bedrock:StopModelInvocationJob`, plus S3 access to the input/output bucket and `iam:PassRole` for the Bedrock service role — see the [full batch policy](/aigw/integrations/llms/bedrock/batches#information-about-permissions-and-iam-roles) |
+| [Fine-tuning](/aigw/integrations/llms/bedrock/fine-tuning) | `bedrock:CreateModelCustomizationJob`, `bedrock:GetModelCustomizationJob`, `bedrock:ListModelCustomizationJobs`, `bedrock:StopModelCustomizationJob`, plus S3 access to the training-data bucket and `iam:PassRole` |
+| [Files](/aigw/integrations/llms/bedrock/files) | `s3:PutObject`, `s3:GetObject`, `s3:GetObjectAttributes`, `s3:AbortMultipartUpload`, `s3:ListBucket` on your bucket |
+
+
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "BedrockInference",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:InvokeModel",
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens",
+ "bedrock:ApplyGuardrail",
+ "bedrock:Rerank",
+ "bedrock:ListFoundationModels",
+ "bedrock:GetFoundationModel",
+ "bedrock:GetInferenceProfile"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "BedrockBatchAndFineTuning",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:CreateModelInvocationJob",
+ "bedrock:GetModelInvocationJob",
+ "bedrock:ListModelInvocationJobs",
+ "bedrock:StopModelInvocationJob",
+ "bedrock:CreateModelCustomizationJob",
+ "bedrock:GetModelCustomizationJob",
+ "bedrock:ListModelCustomizationJobs",
+ "bedrock:StopModelCustomizationJob",
+ "bedrock:TagResource",
+ "bedrock:UntagResource",
+ "bedrock:ListTagsForResource"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "S3ForFilesAndJobIO",
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:PutObject",
+ "s3:GetObject",
+ "s3:GetObjectAttributes",
+ "s3:AbortMultipartUpload"
+ ],
+ "Resource": [
+ "arn:aws:s3:::",
+ "arn:aws:s3:::/*"
+ ]
+ },
+ {
+ "Sid": "PassBedrockServiceRole",
+ "Effect": "Allow",
+ "Action": "iam:PassRole",
+ "Resource": "arn:aws:iam:::role/",
+ "Condition": {
+ "StringEquals": {
+ "iam:PassedToService": "bedrock.amazonaws.com"
+ }
+ }
+ }
+ ]
+}
+```
+
+Replace ``, `` and `` with your own values, and narrow each `Resource` to the model, inference profile and job ARNs you actually use.
+
+
### Create a new IAM role
Choose *AWS account* as the trusted entity type. If you set an external ID be sure to copy it, we will need it later.
diff --git a/aigw/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx b/aigw/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx
index 4ebf6e685..9da396f92 100644
--- a/aigw/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx
+++ b/aigw/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx
@@ -16,6 +16,8 @@ This role you create will be used by the AI Gateway to execute InvokeModel comma
### Create a permission policy in your AWS account using the following JSON
+These actions cover standard inference — chat completions, the Messages API, embeddings, image generation, and token counting:
+
```json
{
"Version": "2012-10-17",
@@ -25,7 +27,8 @@ This role you create will be used by the AI Gateway to execute InvokeModel comma
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
- "bedrock:InvokeModelWithResponseStream"
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens"
],
"Resource": "*"
}
@@ -33,6 +36,98 @@ This role you create will be used by the AI Gateway to execute InvokeModel comma
}
```
+
+`bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` also authorize the Converse and ConverseStream APIs, which the AI Gateway uses for most models.
+
+`bedrock:CountTokens` backs the `/v1/messages/count_tokens` endpoint. Clients such as Claude Code call it on every turn, so omitting it shows up as `is not authorized to perform: bedrock:CountTokens`. It is a recent addition to Bedrock — roles created before it existed need it added explicitly.
+
+
+### Additional permissions by feature
+
+Add these only if you use the corresponding feature — everything else works with the three actions above.
+
+| Feature | Additional actions |
+| :-- | :-- |
+| [Inference profiles](/aigw/integrations/llms/bedrock/aws-bedrock#inference-profiles) (the model ID is an inference profile ARN) | `bedrock:GetInferenceProfile` |
+| Model discovery (listing Bedrock models through the AI Gateway) | `bedrock:ListFoundationModels` |
+| [Bedrock Guardrails](/aigw/integrations/guardrails/bedrock-guardrails) | `bedrock:ApplyGuardrail` |
+| [Reranking](/aigw/integrations/llms/bedrock/rerank) | `bedrock:Rerank` |
+| [Batch inference](/aigw/integrations/llms/bedrock/batches) | `bedrock:CreateModelInvocationJob`, `bedrock:GetModelInvocationJob`, `bedrock:ListModelInvocationJobs`, `bedrock:StopModelInvocationJob`, plus S3 access to the input/output bucket and `iam:PassRole` for the Bedrock service role — see the [full batch policy](/aigw/integrations/llms/bedrock/batches#information-about-permissions-and-iam-roles) |
+| [Fine-tuning](/aigw/integrations/llms/bedrock/fine-tuning) | `bedrock:CreateModelCustomizationJob`, `bedrock:GetModelCustomizationJob`, `bedrock:ListModelCustomizationJobs`, `bedrock:StopModelCustomizationJob`, plus S3 access to the training-data bucket and `iam:PassRole` |
+| [Files](/aigw/integrations/llms/bedrock/files) | `s3:PutObject`, `s3:GetObject`, `s3:GetObjectAttributes`, `s3:AbortMultipartUpload`, `s3:ListBucket` on your bucket |
+
+
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "BedrockInference",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:InvokeModel",
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens",
+ "bedrock:ApplyGuardrail",
+ "bedrock:Rerank",
+ "bedrock:ListFoundationModels",
+ "bedrock:GetFoundationModel",
+ "bedrock:GetInferenceProfile"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "BedrockBatchAndFineTuning",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:CreateModelInvocationJob",
+ "bedrock:GetModelInvocationJob",
+ "bedrock:ListModelInvocationJobs",
+ "bedrock:StopModelInvocationJob",
+ "bedrock:CreateModelCustomizationJob",
+ "bedrock:GetModelCustomizationJob",
+ "bedrock:ListModelCustomizationJobs",
+ "bedrock:StopModelCustomizationJob",
+ "bedrock:TagResource",
+ "bedrock:UntagResource",
+ "bedrock:ListTagsForResource"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "S3ForFilesAndJobIO",
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:PutObject",
+ "s3:GetObject",
+ "s3:GetObjectAttributes",
+ "s3:AbortMultipartUpload"
+ ],
+ "Resource": [
+ "arn:aws:s3:::",
+ "arn:aws:s3:::/*"
+ ]
+ },
+ {
+ "Sid": "PassBedrockServiceRole",
+ "Effect": "Allow",
+ "Action": "iam:PassRole",
+ "Resource": "arn:aws:iam:::role/",
+ "Condition": {
+ "StringEquals": {
+ "iam:PassedToService": "bedrock.amazonaws.com"
+ }
+ }
+ }
+ ]
+}
+```
+
+Replace ``, `` and `` with your own values, and narrow each `Resource` to the model, inference profile and job ARNs you actually use.
+
+
### Create a new IAM role
Choose *AWS account* as the trusted entity type. If you set an external ID be sure to copy it, we will need it later.
diff --git a/aigw/self-hosting/hybrid-deployments/aws/eks.mdx b/aigw/self-hosting/hybrid-deployments/aws/eks.mdx
index 645d284cd..7612c25bc 100644
--- a/aigw/self-hosting/hybrid-deployments/aws/eks.mdx
+++ b/aigw/self-hosting/hybrid-deployments/aws/eks.mdx
@@ -584,7 +584,7 @@ cat >bedrock-access-policy.json <::foundation-model/",
"arn:aws:bedrock:::provisioned-model/"
diff --git a/integrations/libraries/claude-code-bedrock.mdx b/integrations/libraries/claude-code-bedrock.mdx
index 2393d32d1..87e698434 100644
--- a/integrations/libraries/claude-code-bedrock.mdx
+++ b/integrations/libraries/claude-code-bedrock.mdx
@@ -27,6 +27,10 @@ Enter your AWS credentials:
Create a slug like `bedrock-prod`.
+
+**IAM permissions:** the credentials (or assumed role) you use here need `bedrock:InvokeModel`, `bedrock:InvokeModelWithResponseStream` **and** `bedrock:CountTokens`. Claude Code calls the count-tokens API on every turn, so a role without it fails with `is not authorized to perform: bedrock:CountTokens`. Add `bedrock:GetInferenceProfile` if your model ID is an inference profile ARN. See [Connect Bedrock with Amazon Assumed Role](/product/model-catalog/connect-bedrock-with-amazon-assumed-role) for the full policy.
+
+
diff --git a/integrations/llms/bedrock/count-tokens.mdx b/integrations/llms/bedrock/count-tokens.mdx
index 5d0cbaa2b..a1283090c 100644
--- a/integrations/llms/bedrock/count-tokens.mdx
+++ b/integrations/llms/bedrock/count-tokens.mdx
@@ -7,6 +7,10 @@ Portkey supports the [AWS Bedrock CountTokens API](https://docs.aws.amazon.com/b
The token count returned by this operation matches the token count that would be charged if the same input were sent to the model in an `InvokeModel` or `Converse` request.
+
+Your Bedrock credentials need the `bedrock:CountTokens` IAM action on the foundation models you call. It is separate from `bedrock:InvokeModel`, so roles created before this action existed will fail with `is not authorized to perform: bedrock:CountTokens`. See [Connect Bedrock with Amazon Assumed Role](/product/model-catalog/connect-bedrock-with-amazon-assumed-role) for the full policy.
+
+
## Using Count Tokens with Portkey
Portkey supports Bedrock's CountTokens endpoint through the Anthropic-compatible format, allowing you to use the same API signature across Bedrock, Vertex AI, and Anthropic providers.
diff --git a/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx b/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
index 8b06c9099..6290e9cfa 100644
--- a/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
+++ b/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
@@ -25,6 +25,8 @@ This role you create will be used by Portkey to execute InvokeModel commands on
### Create a permission policy in your AWS account using the following JSON
+These actions cover standard inference — chat completions, the Messages API, embeddings, image generation, and token counting:
+
```json
{
"Version": "2012-10-17",
@@ -34,7 +36,8 @@ This role you create will be used by Portkey to execute InvokeModel commands on
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
- "bedrock:InvokeModelWithResponseStream"
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens"
],
"Resource": "*"
}
@@ -42,10 +45,102 @@ This role you create will be used by Portkey to execute InvokeModel commands on
}
```
+
+`bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` also authorize the Converse and ConverseStream APIs, which Portkey uses for most models.
+
+`bedrock:CountTokens` backs the `/v1/messages/count_tokens` endpoint. Clients such as Claude Code call it on every turn, so omitting it shows up as `is not authorized to perform: bedrock:CountTokens`. It is a recent addition to Bedrock — roles created before it existed need it added explicitly.
+
+
+### Additional permissions by feature
+
+Add these only if you use the corresponding feature — everything else works with the three actions above.
+
+| Feature | Additional actions |
+| :-- | :-- |
+| [Inference profiles](/integrations/llms/bedrock/aws-bedrock#inference-profiles) (the model ID is an inference profile ARN) | `bedrock:GetInferenceProfile` |
+| Model discovery (listing Bedrock models through Portkey) | `bedrock:ListFoundationModels` |
+| [Bedrock Guardrails](/integrations/guardrails/bedrock-guardrails) | `bedrock:ApplyGuardrail` |
+| [Reranking](/integrations/llms/bedrock/rerank) | `bedrock:Rerank` |
+| [Batch inference](/integrations/llms/bedrock/batches) | `bedrock:CreateModelInvocationJob`, `bedrock:GetModelInvocationJob`, `bedrock:ListModelInvocationJobs`, `bedrock:StopModelInvocationJob`, plus S3 access to the input/output bucket and `iam:PassRole` for the Bedrock service role — see the [full batch policy](/integrations/llms/bedrock/batches#information-about-permissions-and-iam-roles) |
+| [Fine-tuning](/integrations/llms/bedrock/fine-tuning) | `bedrock:CreateModelCustomizationJob`, `bedrock:GetModelCustomizationJob`, `bedrock:ListModelCustomizationJobs`, `bedrock:StopModelCustomizationJob`, plus S3 access to the training-data bucket and `iam:PassRole` |
+| [Files](/integrations/llms/bedrock/files) | `s3:PutObject`, `s3:GetObject`, `s3:GetObjectAttributes`, `s3:AbortMultipartUpload`, `s3:ListBucket` on your bucket |
+
+
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "BedrockInference",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:InvokeModel",
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens",
+ "bedrock:ApplyGuardrail",
+ "bedrock:Rerank",
+ "bedrock:ListFoundationModels",
+ "bedrock:GetFoundationModel",
+ "bedrock:GetInferenceProfile"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "BedrockBatchAndFineTuning",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:CreateModelInvocationJob",
+ "bedrock:GetModelInvocationJob",
+ "bedrock:ListModelInvocationJobs",
+ "bedrock:StopModelInvocationJob",
+ "bedrock:CreateModelCustomizationJob",
+ "bedrock:GetModelCustomizationJob",
+ "bedrock:ListModelCustomizationJobs",
+ "bedrock:StopModelCustomizationJob",
+ "bedrock:TagResource",
+ "bedrock:UntagResource",
+ "bedrock:ListTagsForResource"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "S3ForFilesAndJobIO",
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:PutObject",
+ "s3:GetObject",
+ "s3:GetObjectAttributes",
+ "s3:AbortMultipartUpload"
+ ],
+ "Resource": [
+ "arn:aws:s3:::",
+ "arn:aws:s3:::/*"
+ ]
+ },
+ {
+ "Sid": "PassBedrockServiceRole",
+ "Effect": "Allow",
+ "Action": "iam:PassRole",
+ "Resource": "arn:aws:iam:::role/",
+ "Condition": {
+ "StringEquals": {
+ "iam:PassedToService": "bedrock.amazonaws.com"
+ }
+ }
+ }
+ ]
+}
+```
+
+Replace ``, `` and `` with your own values, and narrow each `Resource` to the model, inference profile and job ARNs you actually use.
+
+
### Create a new IAM role
Choose *AWS account* as the trusted entity type. If you set an external ID be sure to copy it, we will need it later.
diff --git a/product/enterprise-offering/cloud-marketplace/aws.mdx b/product/enterprise-offering/cloud-marketplace/aws.mdx
index e93969437..1ddb965df 100644
--- a/product/enterprise-offering/cloud-marketplace/aws.mdx
+++ b/product/enterprise-offering/cloud-marketplace/aws.mdx
@@ -263,6 +263,7 @@ Resources:
Action:
- "bedrock:InvokeModel"
- "bedrock:InvokeModelWithResponseStream"
+ - "bedrock:CountTokens"
Resource: "*"
- Effect: Allow
Action:
diff --git a/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx b/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx
index 09e3dba0f..12121951d 100644
--- a/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx
+++ b/product/model-catalog/connect-bedrock-with-amazon-assumed-role.mdx
@@ -23,6 +23,8 @@ This role you create will be used by Porktey to execute InvokeModel commands on
### Create a permission policy in your AWS account using the following JSON
+These actions cover standard inference — chat completions, the Messages API, embeddings, image generation, and token counting:
+
```json
{
"Version": "2012-10-17",
@@ -32,7 +34,8 @@ This role you create will be used by Porktey to execute InvokeModel commands on
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
- "bedrock:InvokeModelWithResponseStream"
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens"
],
"Resource": "*"
}
@@ -40,10 +43,102 @@ This role you create will be used by Porktey to execute InvokeModel commands on
}
```
+
+`bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` also authorize the Converse and ConverseStream APIs, which Portkey uses for most models.
+
+`bedrock:CountTokens` backs the `/v1/messages/count_tokens` endpoint. Clients such as Claude Code call it on every turn, so omitting it shows up as `is not authorized to perform: bedrock:CountTokens`. It is a recent addition to Bedrock — roles created before it existed need it added explicitly.
+
+
+### Additional permissions by feature
+
+Add these only if you use the corresponding feature — everything else works with the three actions above.
+
+| Feature | Additional actions |
+| :-- | :-- |
+| [Inference profiles](/integrations/llms/bedrock/aws-bedrock#inference-profiles) (the model ID is an inference profile ARN) | `bedrock:GetInferenceProfile` |
+| Model discovery (listing Bedrock models through Portkey) | `bedrock:ListFoundationModels` |
+| [Bedrock Guardrails](/integrations/guardrails/bedrock-guardrails) | `bedrock:ApplyGuardrail` |
+| [Reranking](/integrations/llms/bedrock/rerank) | `bedrock:Rerank` |
+| [Batch inference](/integrations/llms/bedrock/batches) | `bedrock:CreateModelInvocationJob`, `bedrock:GetModelInvocationJob`, `bedrock:ListModelInvocationJobs`, `bedrock:StopModelInvocationJob`, plus S3 access to the input/output bucket and `iam:PassRole` for the Bedrock service role — see the [full batch policy](/integrations/llms/bedrock/batches#information-about-permissions-and-iam-roles) |
+| [Fine-tuning](/integrations/llms/bedrock/fine-tuning) | `bedrock:CreateModelCustomizationJob`, `bedrock:GetModelCustomizationJob`, `bedrock:ListModelCustomizationJobs`, `bedrock:StopModelCustomizationJob`, plus S3 access to the training-data bucket and `iam:PassRole` |
+| [Files](/integrations/llms/bedrock/files) | `s3:PutObject`, `s3:GetObject`, `s3:GetObjectAttributes`, `s3:AbortMultipartUpload`, `s3:ListBucket` on your bucket |
+
+
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "BedrockInference",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:InvokeModel",
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens",
+ "bedrock:ApplyGuardrail",
+ "bedrock:Rerank",
+ "bedrock:ListFoundationModels",
+ "bedrock:GetFoundationModel",
+ "bedrock:GetInferenceProfile"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "BedrockBatchAndFineTuning",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:CreateModelInvocationJob",
+ "bedrock:GetModelInvocationJob",
+ "bedrock:ListModelInvocationJobs",
+ "bedrock:StopModelInvocationJob",
+ "bedrock:CreateModelCustomizationJob",
+ "bedrock:GetModelCustomizationJob",
+ "bedrock:ListModelCustomizationJobs",
+ "bedrock:StopModelCustomizationJob",
+ "bedrock:TagResource",
+ "bedrock:UntagResource",
+ "bedrock:ListTagsForResource"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "S3ForFilesAndJobIO",
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:PutObject",
+ "s3:GetObject",
+ "s3:GetObjectAttributes",
+ "s3:AbortMultipartUpload"
+ ],
+ "Resource": [
+ "arn:aws:s3:::",
+ "arn:aws:s3:::/*"
+ ]
+ },
+ {
+ "Sid": "PassBedrockServiceRole",
+ "Effect": "Allow",
+ "Action": "iam:PassRole",
+ "Resource": "arn:aws:iam:::role/",
+ "Condition": {
+ "StringEquals": {
+ "iam:PassedToService": "bedrock.amazonaws.com"
+ }
+ }
+ }
+ ]
+}
+```
+
+Replace ``, `` and `` with your own values, and narrow each `Resource` to the model, inference profile and job ARNs you actually use.
+
+
### Create a new IAM role
Choose *AWS account* as the trusted entity type. If you set an external ID be sure to copy it, we will need it later.
diff --git a/self-hosting/hybrid-deployments/aws/eks.mdx b/self-hosting/hybrid-deployments/aws/eks.mdx
index d2a0654bf..dd1379efe 100644
--- a/self-hosting/hybrid-deployments/aws/eks.mdx
+++ b/self-hosting/hybrid-deployments/aws/eks.mdx
@@ -672,7 +672,7 @@ cat >bedrock-access-policy.json <::foundation-model/",
"arn:aws:bedrock:::provisioned-model/"
diff --git a/self-hosting/hybrid-deployments/aws/marketplace.mdx b/self-hosting/hybrid-deployments/aws/marketplace.mdx
index b05f9ed7d..641156bad 100644
--- a/self-hosting/hybrid-deployments/aws/marketplace.mdx
+++ b/self-hosting/hybrid-deployments/aws/marketplace.mdx
@@ -263,6 +263,7 @@ Resources:
Action:
- "bedrock:InvokeModel"
- "bedrock:InvokeModelWithResponseStream"
+ - "bedrock:CountTokens"
Resource: "*"
- Effect: Allow
Action:
diff --git a/virtual_key_old/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx b/virtual_key_old/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
index 973fc892f..0957d2486 100644
--- a/virtual_key_old/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
+++ b/virtual_key_old/product/ai-gateway/virtual-keys/bedrock-amazon-assumed-role.mdx
@@ -25,6 +25,8 @@ This role you create will be used by Porktey to execute InvokeModel commands on
### Create a permission policy in your AWS account using the following JSON
+These actions cover standard inference — chat completions, the Messages API, embeddings, image generation, and token counting:
+
```json
{
"Version": "2012-10-17",
@@ -34,7 +36,8 @@ This role you create will be used by Porktey to execute InvokeModel commands on
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
- "bedrock:InvokeModelWithResponseStream"
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens"
],
"Resource": "*"
}
@@ -42,10 +45,102 @@ This role you create will be used by Porktey to execute InvokeModel commands on
}
```
+
+`bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` also authorize the Converse and ConverseStream APIs, which Portkey uses for most models.
+
+`bedrock:CountTokens` backs the `/v1/messages/count_tokens` endpoint. Clients such as Claude Code call it on every turn, so omitting it shows up as `is not authorized to perform: bedrock:CountTokens`. It is a recent addition to Bedrock — roles created before it existed need it added explicitly.
+
+
+### Additional permissions by feature
+
+Add these only if you use the corresponding feature — everything else works with the three actions above.
+
+| Feature | Additional actions |
+| :-- | :-- |
+| [Inference profiles](/virtual_key_old/integrations/llms/bedrock/aws-bedrock) (the model ID is an inference profile ARN) | `bedrock:GetInferenceProfile` |
+| Model discovery (listing Bedrock models through Portkey) | `bedrock:ListFoundationModels` |
+| [Bedrock Guardrails](/virtual_key_old/integrations/guardrails/bedrock-guardrails) | `bedrock:ApplyGuardrail` |
+| Reranking | `bedrock:Rerank` |
+| [Batch inference](/virtual_key_old/integrations/llms/bedrock/batches) | `bedrock:CreateModelInvocationJob`, `bedrock:GetModelInvocationJob`, `bedrock:ListModelInvocationJobs`, `bedrock:StopModelInvocationJob`, plus S3 access to the input/output bucket and `iam:PassRole` for the Bedrock service role |
+| [Fine-tuning](/virtual_key_old/integrations/llms/bedrock/fine-tuning) | `bedrock:CreateModelCustomizationJob`, `bedrock:GetModelCustomizationJob`, `bedrock:ListModelCustomizationJobs`, `bedrock:StopModelCustomizationJob`, plus S3 access to the training-data bucket and `iam:PassRole` |
+| [Files](/virtual_key_old/integrations/llms/bedrock/files) | `s3:PutObject`, `s3:GetObject`, `s3:GetObjectAttributes`, `s3:AbortMultipartUpload`, `s3:ListBucket` on your bucket |
+
+
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "BedrockInference",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:InvokeModel",
+ "bedrock:InvokeModelWithResponseStream",
+ "bedrock:CountTokens",
+ "bedrock:ApplyGuardrail",
+ "bedrock:Rerank",
+ "bedrock:ListFoundationModels",
+ "bedrock:GetFoundationModel",
+ "bedrock:GetInferenceProfile"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "BedrockBatchAndFineTuning",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock:CreateModelInvocationJob",
+ "bedrock:GetModelInvocationJob",
+ "bedrock:ListModelInvocationJobs",
+ "bedrock:StopModelInvocationJob",
+ "bedrock:CreateModelCustomizationJob",
+ "bedrock:GetModelCustomizationJob",
+ "bedrock:ListModelCustomizationJobs",
+ "bedrock:StopModelCustomizationJob",
+ "bedrock:TagResource",
+ "bedrock:UntagResource",
+ "bedrock:ListTagsForResource"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "S3ForFilesAndJobIO",
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:PutObject",
+ "s3:GetObject",
+ "s3:GetObjectAttributes",
+ "s3:AbortMultipartUpload"
+ ],
+ "Resource": [
+ "arn:aws:s3:::",
+ "arn:aws:s3:::/*"
+ ]
+ },
+ {
+ "Sid": "PassBedrockServiceRole",
+ "Effect": "Allow",
+ "Action": "iam:PassRole",
+ "Resource": "arn:aws:iam:::role/",
+ "Condition": {
+ "StringEquals": {
+ "iam:PassedToService": "bedrock.amazonaws.com"
+ }
+ }
+ }
+ ]
+}
+```
+
+Replace ``, `` and `` with your own values, and narrow each `Resource` to the model, inference profile and job ARNs you actually use.
+
+
### Create a new IAM role
Choose *AWS account* as the trusted entity type. If you set an external ID be sure to copy it, we will need it later.
diff --git a/virtual_key_old/product/enterprise-offering/cloud-marketplace/aws.mdx b/virtual_key_old/product/enterprise-offering/cloud-marketplace/aws.mdx
index 6398b7c8b..aefc9adbe 100644
--- a/virtual_key_old/product/enterprise-offering/cloud-marketplace/aws.mdx
+++ b/virtual_key_old/product/enterprise-offering/cloud-marketplace/aws.mdx
@@ -263,6 +263,7 @@ Resources:
Action:
- "bedrock:InvokeModel"
- "bedrock:InvokeModelWithResponseStream"
+ - "bedrock:CountTokens"
Resource: "*"
- Effect: Allow
Action: