I want to invoke my Amazon Bedrock models in my AWS account. I tried to use a cross-account AWS Lambda function with Python runtimes. However, I received a "botocore.errorfactory.AccessDeniedException" error message.
Short description
When you use a cross-account Lambda function to invoke Amazon Bedrock, you might receive the following error message:
"botocore.errorfactory.AccessDeniedException: An error occurred (AccessDeniedException) when calling the InvokeModel operation: You don't have access to the model with the specified model ID."
To resolve this error, take the following actions:
- Create an AWS Identity and Access Management (IAM) role in account A, the account that owns the Amazon Bedrock model. Then, attach the AmazonBedrockFullAccess policy to the role to allow it to access account B, the account that owns the Lambda function.
- Create an IAM role in account B. Then, associate the IAM role with a basic execution policy to allow its assumed role to access the IAM role in account A.
Note: When you use Amazon Bedrock foundation models, make sure to check the seller's pricing terms.
Make sure to request model access for your Amazon Bedrock model in account A. Confirm that the Access status changes to Access granted.
Resolution
Configure account A
Complete the following steps for the account that owns the Amazon Bedrock models:
- Open the IAM console.
- Create an IAM role for account A.
- Attach the AmazonBedrockFullAccess policy to the IAM role.
- Attach a trust relationship policy that allows the Lambda function's role in account B to assume the role in account A.
Example trust relationship policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::Account_B_ID:role/my-lambda-execution-role"
},
"Action": "sts:AssumeRole"
}
]
}
Note: Replace Account_B_ID with your account B ID and my-lambda-execution-role with your Lambda function execution role.
Configure account B
Complete the following steps for the role that owns the Lambda function:
- Open the IAM console.
- Create an IAM role that the Lambda function uses to run in the account.
- Attach the AWSLambdaBasicExecutionRole policy to the role.
- Attach a policy that allows the IAM role in account B to assume the IAM role in account A.
Example policy:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::Account_A_ID:role/role-on-source-account"
}
}
Note: Replace Account_A_ID with your account A ID and role-on-source-account with the name of the IAM role from account A.
For information about cross-account best practices, see Security best practices in IAM.
Create a Lambda function
Create a Lambda function. The Lambda function assumes the account A IAM role that has access to the Amazon Bedrock models. The function then uses the assumed role's credentials to create the Amazon Bedrock runtime clients that interact with the Amazon Bedrock models.
Your Lambda function must look similar to the following example Python function:
import boto3import botocore
import json
def lambda_handler(event, context):
bedrock_role="arn:aws:iam:::role/BedrockLambdaCrossAccount"
credentials =
boto3.client('sts').assume_role(RoleArn=bedrock_role,RoleSessionName='assume-role')
ACCESS_KEY = credentials['Credentials']['AccessKeyId']
SECRET_KEY = credentials['Credentials']['SecretAccessKey']
SESSION_TOKEN = credentials['Credentials']['SessionToken']
bedrock_session = boto3.session.Session(aws_access_key_id=ACCESS_KEY,aws_secret_access_key=SECRET_KEY,aws_session_token=SESSION_TOKEN)
bedrock = boto3.client(service_name='bedrock', region_name='us-east-1',aws_access_key_id=ACCESS_KEY,aws_secret_access_key=SECRET_KEY,aws_session_token=SESSION_TOKEN)
print(bedrock)
bedrock_runtime = boto3.client(service_name='bedrock-runtime', region_name='us-east-1',aws_access_key_id=ACCESS_KEY,aws_secret_access_key=SECRET_KEY,aws_session_token=SESSION_TOKEN)
foundation_models = bedrock.list_foundation_models()
print(foundation_models)
prompt = "Please list the 10 most popular movies from the 90's"
body = json.dumps({"inputText": "Please list the 10 most popular movies from the 90's"})
modelId = 'anthropic.claude-v2'
accept = 'application/json'
contentType = 'application/json'
response = bedrock_runtime.invoke_model(body=body, modelId=modelId,
accept=accept,contentType=contentType)
response_body = json.loads(response.get('body').read())
print(response_body.get('results')[0].get('outputText'))
output=response_body.get('results')[0].get('outputText')
print(output)
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
},
'body': response_body.get('results')[0].get('outputText')
}