AWS アカウントの Amazon Bedrock モデルを呼び出すために、Python ランタイムでクロスアカウント AWS Lambda 関数の使用を試みたところ、エラーメッセージ "botocore.errorfactory.AccessDeniedException" が発生しました。
簡単な説明
クロスアカウント Lambda 関数を使用して Amazon Bedrock を呼び出す際、次のエラーメッセージが表示される場合があります。
"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."
このエラーを解決するには、次の手順を実行します。
- Amazon Bedrock モデルの所有者であるアカウント A に AWS Identity and Access Management (IAM) ロールを作成します。次に、このロールに AmazonBedrockFullAccess ポリシーをアタッチし、Lambda 関数の所有者であるアカウント B へのアクセスを付与します。
- アカウント B に IAM ロールを作成します。その IAM ロールを基本実行ポリシーに関連付けて、引き受けたロールがアカウント A の IAM ロールにアクセスできるようにします。
注: Amazon Bedrock 基盤モデルを使用する際は、販売者の価格条件を必ず確認してください。
アカウント A の Amazon Bedrock モデルに対するモデルアクセスをリクエストしたことを確認してください。アクセスステータスが Access granted に変更されたことを確認してください。
解決策
アカウント A を設定する
Amazon Bedrock モデルの所有者であるアカウントで次の手順を実行します。
- IAM コンソールを開きます。
- アカウント A に IAM ロールを作成します。
- この IAM ロールに AmazonBedrockFullAccess ポリシーをアタッチします。
- アカウント B 内の Lambda 関数のロールが、アカウント A 内のロールを引き受けられるようにする信頼関係ポリシーをアタッチします。
信頼関係ポリシーの例:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::Account_B_ID:role/my-lambda-execution-role"
},
"Action": "sts:AssumeRole"
}
]
}
注: Account_B_ID をアカウント B の ID に、my-lambda-execution-role を Lambda 関数実行ロールに置き換えてください。
アカウント B を設定する
Lambda 関数の所有者ロールにおいて、次の手順を実行します。
- IAM コンソールを開きます。
- アカウント内での Lambda 関数の実行に使用する IAM ロールを作成します。
- このロールに AWSLambdaBasicExecutionRole ポリシーをアタッチします。
- アカウント B 内の IAM ロールがアカウント A 内の IAM ロールを引き受けられるようにするポリシーをアタッチします。
ポリシー例:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::Account_A_ID:role/role-on-source-account"
}
}
注: Account_A_ID をアカウント A の ID に、role-on-source-account をアカウント A の IAM ロール名に置き換えてください。
クロスアカウントのベストプラクティスについては、「IAM でのセキュリティに関するベストプラクティス」を参照してください。
Lambda 関数を作成する
Lambda 関数を作成します。Lambda 関数は、Amazon Bedrock モデルにアクセスできるアカウント A の IAM ロールを引き受けます。次に、関数は引き受けたロールの認証情報を使用し、Amazon Bedrock 実行時クライアントを作成します。このクライアントが Amazon Bedrock モデルと連携します。
Lambda 関数は、次の Python 関数例に類似したものである必要があります。
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')
}