今北產業

  • 呼叫 Bedrock Mantle 時的驗證方式
  • 其實不用 API Key 也能呼叫
  • 實作時的各種注意事項

Bedrock Mantle 是什麼

請參考下列文章。本文不會對 Bedrock Mantle 做基本說明。

Mantle 端點的呼叫方式

文件上寫著,對 Mantle 的請求要先發行 Bedrock 的短期/長期 API Key 才能進行。

欸,還得特地發 Key 啊……

client = OpenAI(
    api_key="<your Amazon Bedrock API key>",
    base_url="https://bedrock-mantle.us-west-2.api.aws/v1",
)

不過另一邊又寫著 Mantle 的驗證有兩種方式。

Authentication – Depends on the endpoint:
bedrock-mantle – Use a Amazon Bedrock API key (see API keys) or AWS SigV4 credentials.

AWS 的機器學習部落格也有提到。

For the bedrock-mantle endpoint, you need an Amazon Bedrock API key or AWS credentials configured for SigV4.

也就是說,不用每次都發 API Key、也不用煩惱那種繁瑣的管理了,對吧?

Mantle 的驗證有兩種方式

整理文件後,Mantle 的驗證方式如下。服務端接受兩種驗證方式。

方式|使用的東西|需要的 IAM 動作
---|---|---
SigV4|用 AWS 憑證對請求簽章|bedrock-mantle:CreateInference / Get* / List*
Bearer Token|Bedrock API Key|上述加上 bedrock-mantle:CallWithBearerToken

值得注意的是,沒有「依模型區分」的動作。只要 bedrock-mantle:CreateInference 一個動作就能涵蓋所有模型。IAM 資源也是 arn:aws:bedrock-mantle:...:project/*,是以專案為單位,而不是以模型為單位。

也就是說,不需要在「呼叫 Claude」和「呼叫 GPT-OSS」之間切換驗證流程。即使更換模型,驗證程式碼也一行都不用改。

直接用原生 SigV4 試看看

先試最簡單的形式。用 botocore 的 SigV4Auth 進行簽章,再用 requests 發送。服務名稱是 bedrock-mantle

import json

import boto3
import requests
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest

REGION = "ap-northeast-1"
SERVICE = "bedrock-mantle"
URL = f"https://{SERVICE}.{REGION}.api.aws/v1/chat/completions"

payload = {
    "model": "google.gemma-3-4b-it",
    "messages": [{"role": "user", "content": "Reply with exactly: OK"}],
    "max_tokens": 5,
}
body = json.dumps(payload)

creds = boto3.Session().get_credentials().get_frozen_credentials()
req = AWSRequest(method="POST", url=URL, data=body,
                 headers={"Content-Type": "application/json"})
SigV4Auth(creds, SERVICE, REGION).add_auth(req)

resp = requests.post(URL, data=body, headers=dict(req.headers), timeout=60)
print(resp.status_code, resp.json()["choices"][0]["message"]["content"])

這樣就會回傳 200 OK。沒有送出 Authorization: Bearer,也沒有送 x-api-key。IAM 權限也在沒有 CallWithBearerToken 的情況下通過了。正如前面 MiniMax 的文章所說,純 SigV4 的話可以省略第二個 statement。

用了 OpenAI SDK,情況就不同了

Mantle 是 OpenAI 相容端點,所以很想直接用 OpenAI SDK,但 OpenAI SDK 無法做 SigV4 簽章。AWS 的部落格也有寫:

When using the OpenAI SDK, you need an Amazon Bedrock API key.

咦,那不就還是需要 Key?但其實不是。可以使用這個 aws-bedrock-token-generator,從既有的 AWS 憑證即時產生短期 Bearer Token。

from aws_bedrock_token_generator import provide_token
from openai import OpenAI

client = OpenAI(
    api_key=provide_token(region="ap-northeast-1"),
    base_url="https://bedrock-mantle.ap-northeast-1.api.aws/v1",
)

這個 token 最長 12 小時後會自動失效,並且直接繼承發行者 IAM Role 的權限。不管是 SSO 設定檔還是執行角色,都會從標準憑證鏈中取得。整個過程不會產生任何需要保存的密鑰。

關於驗證路徑

咦?OpenAI SDK 不是不能做 SigV4 簽章嗎?
AWS 也說需要 API Key。那為什麼完全沒建立任何 Key 卻還能運作?
其實是因為 provide_token() 裡面做了漂亮的處理,並把結果當作 api_key 傳入了。

image.png

實際上做的事情,就是先送出一個使用 SigV4 的假請求來產生短期 token,接著把它當成類似 API Key 的東西來使用。

不過重點在於,AWS 的憑證並沒有傳到 OpenAI SDK 那一側。

最後是在真正抵達 Mantle 端點時,才會把資訊合併並核對 AWS 憑證。

看看 token 內容

實際負責產生 token 的流程如下。

token_generator.py

request = AWSRequest(
    method="POST",
    url="https://bedrock.amazonaws.com/",
    params={"Action": "CallWithBearerToken"},
)
auth = SigV4QueryAuth(credentials, "bedrock", region, expires=43200)
auth.add_auth(request)

presigned_url = request.url.replace("https://", "") + "&Version=1"
encoded_token = base64.b64encode(presigned_url.encode()).decode()
return f"bedrock-api-key-{encoded_token}"

也就是說,只是把一個假請求做 presign,然後把產生出來的 URL 整個 base64 編碼,再前面加上 bedrock-api-key- 而已。

把實際發行的 token 從 base64 還原後,內容會像這樣。簽章與憑證值已遮蔽。

bedrock.amazonaws.com/?Action=CallWithBearerToken
  &X-Amz-Algorithm=AWS4-HMAC-SHA256
  &X-Amz-Credential=<redacted>
  &X-Amz-Date=<redacted>
  &X-Amz-Expires=43200
  &X-Amz-SignedHeaders=host
  &X-Amz-Signature=<redacted>
  &Version=1

整理到這裡:

  • X-Amz-Expires=43200 就是「最長 12 小時後失效」的原因,也就是 presign 的有效期限
  • 因為內嵌了 Action=CallWithBearerToken,所以 IAM 才需要 bedrock-mantle:CallWithBearerToken
  • 簽章時使用的服務名稱是 bedrock,不是 bedrock-mantle,所以這個 token 似乎是 Bedrock 共用的,不是 Mantle 專用

而最清楚的一點是:雖然它被稱為「API Key」,但它不是新產生的秘密,而是從手上的 AWS 憑證導出的簽章本身。因此不需要另外保存。

Strands Agents

如果是使用 Strands Agents,這套設定在函式庫內部已經處理好了。只要在 bedrock_mantle_config 裡傳入 region 即可。

from strands import Agent
from strands.models.openai import OpenAIModel

model = OpenAIModel(
    model_id="openai.gpt-oss-120b",
    bedrock_mantle_config={"region": "ap-northeast-1"},  # 不傳 api_key
)
agent = Agent(model=model, tools=[get_weather])

可接受的鍵有 region / boto_session / credentials_provider / expiry 這 4 個。全部都可以省略,若完全不傳,會使用標準憑證鏈。

也可以放到 AgentCore Runtime 上

AgentCore Runtime 也完全沒問題。在容器內可以取得執行角色的暫時性憑證,因此不用在環境變數或 Secret Store 裡放任何東西,就能呼叫 Mantle。

CDK 大概會像這樣。

const runtime = new agentcore.Runtime(this, 'MantleAgentRuntime', {
  runtimeName: 'mantle_agent',
  agentRuntimeArtifact: artifact,
  environmentVariables: {
    MANTLE_REGION: this.region,
    MANTLE_MODEL_ID: 'openai.gpt-oss-120b',
  },
  tracingEnabled: true,
});

runtime.role.addManagedPolicy(
  iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonBedrockMantleInferenceAccess'),
);

AmazonBedrockMantleInferenceAccess 同時涵蓋 SigV4 路徑與 Bearer Token 路徑,所以先加這個就能動。其內容如下。

{
  "Sid": "BedrockMantleInference",
  "Action": ["bedrock-mantle:Get*", "bedrock-mantle:List*", "bedrock-mantle:CreateInference"],
  "Resource": "arn:aws:bedrock-mantle:*:*:project/*"
}

部署並實際呼叫後,確實可以正常運作。

$ python scripts/invoke_runtime.py "現在幾點?"
[tool: get_current_time]
現在的時間是 2026 年 8 月 8 日 21 時 24 分 37 秒(JST)。

沒有長期 API Key。.env 和 Secrets Manager 裡也都沒有放任何東西。

API Key 方式不好嗎?

如果能不發 Key 就不發,安全性更高,也更方便——
乍看之下確實如此。

但如前所述,短期 API Key 其實是內部用 SigV4 驗證的。
那麼特地發長期 API Key 的優點是什麼呢……

這只能說是視情況而定了……笑

例如,呼叫端無法持有 AWS 憑證的情境,像是合作廠商的系統、公司外部人員的筆電。短期 token 在發行時就需要 AWS 憑證,所以根本不能用。在這種情況下,直接給一把長期 Key,會比建立 IAM User 再分發整套憑證來得容易管理。

管理 Key 本身也是成本,所以要好好考慮究竟該用哪種方式呼叫。

可是文件和範例不都是 API Key 方式嗎?

我想這和 Mantle 的概念有關,因為它本來就是 OpenAI 相容的。應該是想把「只要替換既有程式碼中的 base_url 和 api_key 就能用」這種體驗,簡潔地呈現出來吧,笑。

最後

官方執行範例幾乎都是以 API Key 為前提,所以我在重新讀過之前,完全沒注意到其實可以不用 Key 也能用。

參考


原文出處:https://qiita.com/yakumo_09/items/210e60518b5bb7dbc4e0


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝8   💬4   ❤️2
231
🥈
我愛JS
📝1   💬2   ❤️1
51
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登