Bedrock GPT-5.5 を OpenAI SDK の Lambda レイヤーで動かしてみた

Bedrock GPT-5.5 を OpenAI SDK の Lambda レイヤーで動かしてみた

Amazon Bedrock の bedrock-mantle 用 IAM 管理ポリシーと OpenAI SDK を Lambda レイヤーにまとめ、CloudFormation 一発デプロイで GPT-5.5 を呼び出す Lambda を構築しました。
2026.06.02

はじめに

本日、Amazon Bedrock で OpenAI GPT-5.5 が利用可能になりました。

https://dev.classmethod.jp/articles/bedrock-openai-gpt55-gpt54-ga-responses-api/

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:InvokeModelAmazonBedrockFullAccess不要です。

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-generatorprovide_token は、内部で以下の処理を行っています。

  1. Lambda 実行ロールの認証情報を取得
  2. botocore の SigV4QueryAuthPOST https://bedrock.amazonaws.com/?Action=CallWithBearerToken に対する presigned URL を生成
  3. URL からスキーム(https://)を除去し、&Version=1 を付加
  4. 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 の実行ロールだけで認証が完結することを確認できました。

参考リンク


生成AI活用はクラスメソッドにお任せ

過去に支援してきた生成AIの支援実績100+を元にホワイトペーパーを作成しました。御社が抱えている課題のうち、どれが解決できて、どのようなサービスが受けられるのか?4つのフェーズに分けてまとめています。どうぞお気軽にご覧ください。

生成AI資料イメージ

無料でダウンロードする

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事