Bedrock GPT-5.5 を OpenAI SDK の Lambda レイヤーで動かしてみた
はじめに
本日、Amazon Bedrock で OpenAI GPT-5.5 が利用可能になりました。
Lambda から呼び出す際の IAM 権限まわりを確認しつつ、実際に動かしてみました。
| 観点 | bedrock-runtime | bedrock-mantle |
|---|---|---|
| API | InvokeModel, Converse | Responses, Chat Completions |
| IAM 名前空間 | bedrock: |
bedrock-mantle: |
| 管理ポリシー | AmazonBedrockFullAccess | AmazonBedrockMantleInferenceAccess |
| SDK | boto3 bedrock-runtime クライアント | OpenAI SDK |
Amazon Bedrock で OpenAI GPT-5.5 を利用する場合、従来の bedrock-runtime(InvokeModel / Converse API)ではなく bedrock-mantle という別のサービス名前空間を経由します。IAM 権限も bedrock:InvokeModel ではなく bedrock-mantle:* 系のアクションが必要です。
bedrock-mantle は OpenAI 互換のエンドポイントを提供するため、既存の OpenAI SDK コードをほぼそのまま流用できます。
前提条件
- リージョン: us-east-2(GPT-5.5 対応リージョン)
- モデル利用申請済み(Bedrock コンソールでモデルアクセスを有効化)
- Lambda ランタイム: python3.14 / arm64 (Graviton)
IAM 最小権限
GPT-5.5 を Lambda から呼び出すには、以下の 2 つの管理ポリシーを Lambda 実行ロールにアタッチします。
- AWSLambdaBasicExecutionRole — CloudWatch Logs への書き込み権限(Lambda 運用に必要)
- AmazonBedrockMantleInferenceAccess — bedrock-mantle エンドポイントへの推論権限
bedrock:InvokeModel や AmazonBedrockFullAccess は不要です。
AmazonBedrockMantleInferenceAccess の中身
ポリシー JSON(v4, 2026-04-09 時点)
{
"Statement": [
{
"Sid": "BedrockMantleInference",
"Effect": "Allow",
"Action": ["bedrock-mantle:Get*", "bedrock-mantle:List*", "bedrock-mantle:CreateInference"],
"Resource": "arn:aws:bedrock-mantle:*:*:project/*"
},
{
"Sid": "BedrockMantleCallWithBearerToken",
"Effect": "Allow",
"Action": ["bedrock-mantle:CallWithBearerToken"],
"Resource": "*"
},
{
"Sid": "MarketplaceOperationsFromBedrockMantleFor3pModels",
"Effect": "Allow",
"Action": ["aws-marketplace:Subscribe", "aws-marketplace:ViewSubscriptions"],
"Resource": "*",
"Condition": {"StringEquals": {"aws:CalledViaLast": "bedrock-mantle.amazonaws.com"}}
}
]
}
| Action | 用途 |
|---|---|
bedrock-mantle:CreateInference |
Responses API / Chat Completions での推論実行 |
bedrock-mantle:CallWithBearerToken |
Bearer token 認証(presigned URL ベース) |
bedrock-mantle:Get* / List* |
プロジェクト情報の読み取り |
aws-marketplace:Subscribe / ViewSubscriptions |
初回呼び出し時の自動サブスクリプション(CalledViaLast 条件付き) |
Marketplace 権限は bedrock-mantle 経由の呼び出し時のみ有効になる条件キーが付いているため、意図しないサブスクリプション操作は防止されています。
Lambda 構築(OpenAI SDK 版)
ビルド環境: Fedora Linux 43 (aarch64) / Python 3.14.4 / pip 25.1.1
Layer 作成
OpenAI SDK と aws-bedrock-token-generator を Lambda Layer にパッケージします。Docker 不要で、pip install のクロスプラットフォームオプションだけで arm64 用のバイナリを取得できます。
pip install "openai>=2.40.0" "aws-bedrock-token-generator>=1.1.0" \
-t python/ --platform manylinux2014_aarch64 --implementation cp \
--python-version 3.14 --only-binary=:all:
zip -r9 layer.zip python/
aws lambda publish-layer-version \
--layer-name bedrock-openai-sdk \
--compatible-runtimes python3.14 \
--compatible-architectures arm64 \
--zip-file fileb://layer.zip --region us-east-2
ポイント:
--platform manylinux2014_aarch64+--only-binary=:all:で wheel のみ取得するため、ローカルの Python バージョンや OS を問わずクロスビルドできます- Lambda arm64 (Graviton) に合わせたアーキテクチャ指定です
Layer 作成スクリプト全文(create-layer.sh)
#!/bin/bash
set -euo pipefail
LAYER_NAME="bedrock-openai-sdk"
RUNTIME="python3.14"
REGION="us-east-2"
WORK_DIR=$(mktemp -d)
echo "Working in: $WORK_DIR"
mkdir -p "$WORK_DIR/python"
pip install \
"openai>=2.40.0" \
"aws-bedrock-token-generator>=1.1.0" \
-t "$WORK_DIR/python" \
--platform manylinux2014_aarch64 \
--implementation cp \
--python-version 3.14 \
--only-binary=:all: \
--upgrade
cd "$WORK_DIR"
zip -r9 layer.zip python/
LAYER_ARN=$(aws lambda publish-layer-version \
--layer-name "$LAYER_NAME" \
--compatible-runtimes "$RUNTIME" \
--compatible-architectures arm64 \
--zip-file "fileb://layer.zip" \
--region "$REGION" \
--query 'LayerVersionArn' \
--output text)
echo ""
echo "=== Layer published ==="
echo "ARN: $LAYER_ARN"
rm -rf "$WORK_DIR"
CloudFormation テンプレート
Lambda 関数のコードは CloudFormation の ZipFile プロパティに直接埋め込んでいます。Layer ARN をパラメータとして受け取る構成です。
template.yaml 全文
AWSTemplateFormatVersion: "2010-09-09"
Description: "Bedrock GPT-5.5 Lambda (OpenAI SDK + Layer) - ZipFile inline"
Parameters:
BedrockRegion:
Type: String
Default: us-east-2
BedrockModel:
Type: String
Default: openai.gpt-5.5
LayerArn:
Type: String
Description: "ARN of Lambda Layer containing openai + aws-bedrock-token-generator"
Resources:
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AmazonBedrockMantleInferenceAccess
Function:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-fn"
Runtime: python3.14
Handler: index.handler
Architectures: [arm64]
Role: !GetAtt LambdaRole.Arn
Timeout: 120
MemorySize: 256
Layers:
- !Ref LayerArn
Environment:
Variables:
BEDROCK_REGION: !Ref BedrockRegion
BEDROCK_MODEL: !Ref BedrockModel
Code:
ZipFile: |
"""Bedrock GPT-5.5 via OpenAI SDK + aws-bedrock-token-generator (Layer)."""
import json
import os
from aws_bedrock_token_generator import provide_token
from openai import OpenAI
REGION = os.environ["BEDROCK_REGION"]
MODEL = os.environ["BEDROCK_MODEL"]
def handler(event, context):
body = event if isinstance(event, dict) else json.loads(event.get("body", "{}"))
prompt = body.get("prompt", "Hello, respond in one sentence.")
token = provide_token(region=REGION)
client = OpenAI(
base_url=f"https://bedrock-mantle.{REGION}.api.aws/openai/v1",
api_key=token,
)
response = client.responses.create(
model=MODEL,
input=[{"role": "user", "content": prompt}],
)
return {
"statusCode": 200,
"body": json.dumps({
"response": response.output_text,
"model": response.model,
"usage": {
"input_tokens": response.usage.input_tokens,
"output_tokens": response.usage.output_tokens,
},
}, ensure_ascii=False),
}
Outputs:
FunctionArn:
Value: !GetAtt Function.Arn
FunctionName:
Value: !Ref Function
Lambda コード本体は約 20 行です。provide_token で Bearer token を取得し、OpenAI SDK の base_url を bedrock-mantle エンドポイントに向けるだけで動作します。
デプロイと動作確認
aws cloudformation deploy \
--template-file template.yaml \
--stack-name bedrock-gpt55-layer \
--parameter-overrides LayerArn=<Layer作成で出力されたARN> \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-2
aws lambda invoke \
--function-name bedrock-gpt55-layer-fn \
--payload '{"prompt":"日本の首都は?"}' \
--region us-east-2 \
out.json && cat out.json | jq .
レスポンス:
{
"response": "日本の首都は東京です。",
"model": "openai.gpt-5.5",
"usage": {
"input_tokens": 17,
"output_tokens": 34
}
}
補足: Bearer token 生成の仕組み
OpenAI SDK 版で使った aws-bedrock-token-generator の provide_token は、内部で以下の処理を行っています。
- Lambda 実行ロールの認証情報を取得
- botocore の
SigV4QueryAuthでPOST https://bedrock.amazonaws.com/?Action=CallWithBearerTokenに対する presigned URL を生成 - URL からスキーム(
https://)を除去し、&Version=1を付加 - base64 エンコードして
bedrock-api-key-プレフィックスを付与
生成された文字列がそのまま Authorization: Bearer <token> ヘッダーの値になります。この仕組みを理解しておくと、Lambda ランタイム同梱の botocore だけでも外部依存ゼロで同等の処理を実装できます。token の有効期限は presign の expires パラメータで制御でき、下記の例では 3600 秒(1 時間)としています。token にはセッション情報が含まれるため、ログへの出力は避けてください。
botocore 版の CFn テンプレート全文(外部依存ゼロ)
AWSTemplateFormatVersion: "2010-09-09"
Description: "Bedrock GPT-5.5 Lambda (botocore only, no external deps) - ZipFile inline"
Parameters:
BedrockRegion:
Type: String
Default: us-east-2
BedrockModel:
Type: String
Default: openai.gpt-5.5
Resources:
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AmazonBedrockMantleInferenceAccess
Function:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-fn"
Runtime: python3.14
Handler: index.handler
Architectures: [arm64]
Role: !GetAtt LambdaRole.Arn
Timeout: 120
MemorySize: 256
Environment:
Variables:
BEDROCK_REGION: !Ref BedrockRegion
BEDROCK_MODEL: !Ref BedrockModel
Code:
ZipFile: |
"""Bedrock GPT-5.5 via bedrock-mantle — botocore only, zero external deps."""
import base64
import json
import os
import urllib.request
from botocore.auth import SigV4QueryAuth
from botocore.awsrequest import AWSRequest
from botocore.session import Session
REGION = os.environ["BEDROCK_REGION"]
MODEL = os.environ["BEDROCK_MODEL"]
ENDPOINT = f"https://bedrock-mantle.{REGION}.api.aws/openai/v1/responses"
def _get_token():
session = Session()
creds = session.get_credentials()
if creds is None:
raise RuntimeError("No AWS credentials found")
frozen = creds.get_frozen_credentials()
req = AWSRequest(
method="POST",
url="https://bedrock.amazonaws.com/",
headers={"host": "bedrock.amazonaws.com"},
params={"Action": "CallWithBearerToken"},
)
auth = SigV4QueryAuth(frozen, "bedrock", REGION, expires=3600)
auth.add_auth(req)
url_no_scheme = req.url.replace("https://", "") + "&Version=1"
token = "bedrock-api-key-" + base64.b64encode(url_no_scheme.encode()).decode()
return token
def handler(event, context):
body = event if isinstance(event, dict) else json.loads(event.get("body", "{}"))
prompt = body.get("prompt", "Hello, respond in one sentence.")
token = _get_token()
payload = json.dumps({
"model": MODEL,
"input": [{"role": "user", "content": prompt}],
}).encode()
req = urllib.request.Request(
ENDPOINT,
data=payload,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {token}",
},
)
with urllib.request.urlopen(req, timeout=90) as resp:
result = json.loads(resp.read())
output_text = ""
for item in result.get("output", []):
if item.get("type") == "message":
for c in item.get("content", []):
if c.get("type") == "output_text":
output_text += c.get("text", "")
return {
"statusCode": 200,
"body": json.dumps({
"response": output_text,
"model": result.get("model"),
"usage": result.get("usage"),
}, ensure_ascii=False),
}
Outputs:
FunctionArn:
Value: !GetAtt Function.Arn
FunctionName:
Value: !Ref Function
まとめ
bedrock-mantle は bedrock とは別の IAM 名前空間なので、管理ポリシー AmazonBedrockMantleInferenceAccess を使います。Bearer token は IAM ロールの認証情報から動的に生成されるため、OpenAI API を直接利用する場合のようにアクセスキーを環境変数に埋め込む必要がありません。Lambda の実行ロールだけで認証が完結することを確認できました。






