跳到主要內容

【2026 最新】AWS Emulator 教學:Claude Code 怎麼驗 S3?本機寫讀與上雲前六步核對

最後更新: ·
AWS Emulator 教學:S3 本機驗收與雲端驗證邊界

你讓 Claude Code 寫好一段 S3 上傳程式,終端機顯示成功,卻不確定它把檔案送去哪裡,也不知道真的部署後會不會被權限擋住。這篇 AWS Emulator 教學,帶你先在本機完成「寫入、讀回、核對內容」,再把仍要上雲驗證的部分逐項留下來。

前半專為完全沒有雲端背景的讀者寫;操作段適合已有 Docker、Python 3 與可用 Claude Code 帳號的人。你不必先開 AWS 帳號,就能學習模擬器的本機流程;Claude Code 的登入與模型使用費用則是另一件事。

本文依 2026 年 11 月 12 日查閱的官方指南、SDK 文件與公開測試整理。本次環境沒有 Docker,未啟動模擬器,因此以下是可跟做的接線與驗收方法,沒有宣稱已取得本機執行成績。

先說結論:本機過關=接對端點+工具回應+狀態核對

把模擬器當成練習場:Agent 負責操作,測試程式負責對答案,上雲驗收另開一張考卷。燈亮了只是收到回應;檔案內容、物件位置與清理紀錄都對上,才算完成這次練習。

AWS 在 2026 年 11 月 11 日發布 AWS Emulator。它提供本機 AWS API 端點;API 可以理解成程式向服務下單的窗口,SDK 則是幫你填好請求格式的工具包。官方 README說明不需要 AWS 帳號,並將用途限定在開發與測試。

一、AWS Emulator 教學先認五個零件

  • ① Agent「操作助理」:Claude Code 讀專案、改程式、執行命令;它說完成後,仍要拿可核對的結果驗收。
  • ② SDK「訂單翻譯員」:本篇用 Python 的 Boto3,把 put_object 轉成 S3 請求。
  • ③ Endpoint「收件地址」:https://127.0.0.1:9297 指向你的電腦;127.0.0.1 是回送位址,像寄給自己家。
  • ④ Bucket/Key「櫃子與標籤」:S3 的 bucket 是物件容器,key 是物件名稱;hello.txt 是本次標籤。
  • ⑤ 驗收「打開看內容」:讀回位元組、比對原文、查看物件清單,最後記錄刪除結果。

這個分工和 Agent Harness 的執行迴圈相通:模型提出動作,工具真正執行,觀察結果再決定下一步。模擬器提供練習用服務,沒有替你檢查所有業務需求。

二、先搭練習場:保留驗證,讓連線留在本機

第 1 步:「我的機器能跑嗎?」先確認既有工具

在全新的空資料夾操作,先輸入 docker version、python3 --version 與 claude --version。Docker 要同時能連到執行引擎。若缺少工具,先依各自官方安裝流程完成;Claude Code 可從 官方上手頁開始。這篇不需要指定模型名稱或更改方案。

下面以 macOS/Linux 的 POSIX shell 為例。Windows 讀者使用官方 Docker 指南的 PowerShell 版本,或在已配置的 WSL 環境操作,別把兩種 shell 的變數語法混貼。

第 2 步:「下載的是哪一份?」自己建 Docker image

依 官方 Docker 安裝指南建立名為 Dockerfile 的檔案。下列預設 x86_64;Apple Silicon/Arm 把檔名改為 aws-emulator-aarch64.rpm。latest 會隨發布更新,所以首跑要留下映像身分。

FROM public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
ADD https://downloads.aws.com/aws-emulator/packages/aws-emulator/LTS/latest/aws-emulator-x86_64.rpm /tmp/aws-emulator.rpm
RUN rpm -i /tmp/aws-emulator.rpm && rm /tmp/aws-emulator.rpm \
    && mkdir -p /home/emulator && chown 1000 /home/emulator
USER 1000
ENV HOME=/home/emulator
EXPOSE 9297
ENTRYPOINT ["aws-emulator", "-b", "0.0.0.0"]
docker build -t al-aws-emulator .
docker image inspect al-aws-emulator --format '{{.Id}}'
mkdir -p "$HOME/.aws/emulator"
docker run --rm --memory=2g --memory-swap=2g \
  -p 127.0.0.1:9297:9297 \
  -e HOME="$HOME" \
  -v "$HOME/.aws/emulator:$HOME/.aws/emulator" \
  al-aws-emulator -p 9297 --telemetry off

Linux 在 docker run 後加入 --user "$(id -u):$(id -g)",讓產生的檔案屬於你。容器內的 0.0.0.0 讓 Docker 能轉接;主機端的 127.0.0.1:9297:9297 才把入口綁在本機,兩者分工不同。這裡以 --telemetry off 關閉遙測;保留預設的請求簽章驗證。

啟動後會在 ~/.aws/emulator/9297/ 產生當次金鑰、設定與 CA 憑證。模擬資源存在記憶體;停止程序會失去資源,掛載設定資料夾不等於持久保存 S3。2 GiB 是這份指令的記憶體上限,並非所有工作負載都足夠。

三、AWS Emulator 教學接線:把設定與程式包在同一回合

第 3 步:「會不會寄錯地方?」先建立測試啟動檔

保持模擬器運行,另開終端機。建立專案內的 Python 虛擬環境,僅在其中安裝 Boto3;保存版本,方便之後重跑。

python3 -m venv .venv
.venv/bin/python -m pip install boto3
.venv/bin/python -m pip freeze > requirements-tested.txt

將下面內容存為 run-local.sh。括號讓設定只在子 shell 生效;原本的工作終端設定不會被長期改寫。AWS 環境變數可能蓋過金鑰檔,所以先清掉,再接上當次模擬器檔案。完整接線原理見 官方 SDK 設定文件。

#!/bin/sh
set -eu
(
  unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_PROFILE AWS_DEFAULT_PROFILE
  export AWS_ENDPOINT_URL=https://127.0.0.1:9297
  export AWS_SHARED_CREDENTIALS_FILE="$HOME/.aws/emulator/9297/emulator_credentials"
  export AWS_CONFIG_FILE="$HOME/.aws/emulator/9297/config"
  export AWS_CA_BUNDLE="$HOME/.aws/emulator/9297/ca.pem"
  export AWS_EC2_METADATA_DISABLED=true
  export AWS_DISABLE_HOST_PREFIX_INJECTION=true
  export AWS_REGION=us-east-1
  export AWS_DEFAULT_REGION=us-east-1
  curl --fail --silent --show-error --cacert "$AWS_CA_BUNDLE" \
    "$AWS_ENDPOINT_URL/__admin/health" >&2
  .venv/bin/python s3_roundtrip.py
)

健康檢查的驗收是 HTTP 200 與 ok。證書錯誤先查檔案與啟動回合,保留 HTTPS 驗證;連線被拒則先看模擬器是否仍在運行。這裡固定 IP,並指定 S3 使用 path-style:bucket 放在路徑裡,避免 SDK 把名稱加到主機前面。

第 4 步:「成功寫入的是原文嗎?」逐位元組讀回

把下列程式存成 s3_roundtrip.py。它明確從本機模擬器檔案讀取金鑰,將端點與 CA 檔寫在 client 設定中,並在每次送出請求前再檢查目的地。這些檢查保護的是此程式的 SDK 呼叫;其他程序與 Agent 另開的命令仍需各自限制。

import configparser
import hashlib
import json
import os
from pathlib import Path
from urllib.parse import urlsplit
from uuid import uuid4

ENDPOINT = 'https://127.0.0.1:9297'

def require_local(url):
    u = urlsplit(url)
    if (u.scheme != 'https' or u.hostname != '127.0.0.1'
            or u.port != 9297 or u.username or u.password):
        raise RuntimeError('拒絕非本機測試端點')

def main():
    import boto3
    from botocore.config import Config
    if os.environ.get('AWS_ENDPOINT_URL') != ENDPOINT:
        raise RuntimeError('請先載入本機測試環境')
    require_local(ENDPOINT)
    folder = Path.home() / '.aws/emulator/9297'
    cfg = configparser.ConfigParser()
    if not cfg.read(folder / 'emulator_credentials'):
        raise RuntimeError('找不到當次模擬器金鑰')
    keys = cfg['default']
    s3 = boto3.client(
        's3', endpoint_url=ENDPOINT, region_name='us-east-1',
        aws_access_key_id=keys['aws_access_key_id'],
        aws_secret_access_key=keys['aws_secret_access_key'],
        verify=str(folder / 'ca.pem'),
        config=Config(signature_version='s3v4',
                      inject_host_prefix=False, proxies={},
                      s3={'addressing_style': 'path'},
                      connect_timeout=3, read_timeout=10,
                      retries={'total_max_attempts': 1}))
    def guard(request, **kwargs):
        require_local(request.url)
    s3.meta.events.register('before-send.s3.*', guard)
    def log(op, response, **extra):
        print(json.dumps({'op': op,
              'status': response['ResponseMetadata']['HTTPStatusCode'],
              **extra}, ensure_ascii=False))
    bucket = 'al-lab-' + uuid4().hex
    key = 'hello.txt'
    payload = '你好,Agent!\n'.encode('utf-8')
    log('CreateBucket', s3.create_bucket(Bucket=bucket), bucket=bucket)
    log('PutObject', s3.put_object(Bucket=bucket, Key=key, Body=payload))
    response = s3.get_object(Bucket=bucket, Key=key)
    stream = response['Body']
    try:
        actual = stream.read()
    finally:
        stream.close()
    if actual != payload:
        raise RuntimeError('讀回位元組不相同;保留資源供排錯')
    log('GetObject', response, bytes=len(actual),
        sha256=hashlib.sha256(actual).hexdigest())
    listing = s3.list_objects_v2(Bucket=bucket)
    if not any(x['Key'] == key for x in listing.get('Contents', [])):
        raise RuntimeError('物件清單缺少目標;保留資源供排錯')
    log('ListObjectsV2', listing, key=key)
    log('DeleteObject', s3.delete_object(Bucket=bucket, Key=key))
    log('DeleteBucket', s3.delete_bucket(Bucket=bucket))
    print(json.dumps({'result': 'PASS', 'scope': 'local-s3-roundtrip'}))

if __name__ == '__main__':
    main()

執行 sh run-local.sh > trace.jsonl;若退出碼非零,先看終端錯誤,不能只搜尋 PASS 字樣。輸出包含健康檢查與各 API 的結構化紀錄,健康檢查另送到標準錯誤,trace.jsonl 只保留測試程式的逐行紀錄;最後一行記錄 result: PASS,表示本次流程與清理都完成。

這段教學程式使用小型假資料,遇到錯誤立即停止,保留剩餘資源供排錯;它沒有加入失敗後自動清理與正式服務的重試策略。成功路徑才依序刪除物件和 bucket。若要把它改為正式應用,先閱讀 GetObject 的串流與回應欄位,再獨立設計錯誤、逾時與清理流程。

第 5 步:「Agent 說好了,證據在哪?」給 Claude Code 明確考卷

在同一個練習資料夾開啟 claude,貼上這段任務。先讓它讀檔與說明,再執行既有檢查;沿用你的權限設定。

請檢查 run-local.sh 與 s3_roundtrip.py,僅處理這個練習資料夾。
目標是模擬器的 S3 寫入、讀回、內容核對與清理。
先列出所有 AWS API 及目的端點;不得改成真實 AWS。
不要讀取、輸出或複製金鑰內容,不要關閉 TLS 或請求簽章驗證。
確認送出前的本機端點檢查後,執行 sh run-local.sh。
報告退出碼、每個 API 的狀態、讀回長度與 SHA-256,並檢查清理紀錄。
若失敗,先指出是哪一層,再提出最小修改;保留原始失敗紀錄。
未執行的項目寫未測;不要代為開雲端帳號、部署或發布 issue。

這是 Claude Code 官方實務指南所強調的「提供可執行檢查」:你給出具體過關條件,讓助理拿結果回報。Prompt 是任務要求;端點檢查與工具權限才是執行時限制。要理解如何把限制放進執行層,可接著讀 最小 Harness 實作。

AWS Emulator 教學:本機 S3 工具回合與真實 AWS 驗收分開
流程示意:本機先核對請求、回應與狀態;權限與部署另在真實 AWS 驗收。

四、第 6 步:相容性怎麼查?先點名 API,再看測試實際問了什麼

本篇成功路徑呼叫六種 S3 operation:CreateBucket、PutObject、GetObject、ListObjectsV2、DeleteObject、DeleteBucket。其中建立容器與寫讀內容屬於不同層次;控制面像管理櫃子,資料面像存取櫃裡的檔案。

按 官方專案相容性流程做三件事:在 測試 manifest找 s3:PutObject 等名稱;打開對應測試看它的資料、參數與斷言;再對照你使用版本的 release 分數。光看到 operation 名稱出現,還不足以證明你的特定情境通過。

例如官方有 二進位 put/get roundtrip 測試,可用來學它如何驗內容。你自己的繁中文字、空內容、大物件或額外 metadata,仍要各有明確條件。找到同名 API 是找到了題目入口,還要看考卷真的考哪一題。

截至查閱日,官方最新 release 為 v1.0.322。安裝網址的 latest 與未來的 main 可能指向更新內容;記錄實際映像 ID、程式版本、SDK 版本與檢查日期,才能把結果對回正確來源。

Fidelity 官方說明將分數定義為指定服務通過的測試數/總測試數。考卷增加,比例可能下降;比較版本前要核對測試集版本與條件。服務總分也不等於你這六個呼叫的逐項保證;沒有測試覆蓋的行為應記成「未由該測試證實」。

五、本機過關後,帶什麼去上雲?

先分兩張驗收單。本機單留下端點、每次 API 狀態、bucket/key、位元組相等、摘要與清理結果。雲端單則包含實際角色、bucket policy、KMS、區域、網路與部署後的整段流程,並在你有授權的 AWS 測試環境執行。

官方安全文件明確要求不要用模擬器驗證應用安全:它對 IAM 的評估與 AWS 不同,也不檢查 S3 bucket policy 或 KMS key policy,跨帳號/跨區域另有界線。所以本機能讀回檔案,不能推導正式角色一定有權限,或不該讀的人一定被擋住。

另外,本機端點檢查是這份練習的刻意限制,上雲時應建立另一套明確配置與獨立測試,連同端點、憑證、帳號與清理策略一起審查。不要只刪一行檢查,就把本機腳本當成雲端驗收完成。可以用 AI Evals 的考卷設計思路,把「工具回應了」與「任務真的正確」分開評分。

常見問題:八個先講答案的判斷

1. 不開 AWS 帳號也能練習嗎?

可以。官方將模擬器設計為本機測試工具;本文練習不建立雲端資源。Claude Code 的帳號與用量另外處理。

2. 模擬器在本機,Claude Code 也全程離線嗎?

不是。服務端點在本機,與編碼助理連接的模型服務是不同路徑;本篇只使用假資料,任務也禁止輸出金鑰。

3. 可以隨便填 test/test 當金鑰嗎?

本篇不這樣做。預設驗證使用當次模擬器產生的金鑰;沿用舊金鑰或其他金鑰會被拒絕。

4. 為什麼不直接把 TLS 驗證關掉?

先修 CA 路徑。模擬器每次啟動會產生新憑證,程式用當次 ca.pem 驗證它,不必為了排錯放棄驗證。

5. PutObject 回 200 就完成嗎?

還沒。本篇要求 GetObject 讀回相同位元組,並用物件清單檢查位置;只有成功回應,尚未回答內容是否正確。

6. ETag 可以直接當所有物件的 MD5 嗎?

不要這樣假設。本篇直接比對位元組,再自行算 SHA-256;未使用 ETag 推導內容正確性。

7. Docker 掛載資料夾後,重啟還有物件嗎?

這裡的模擬資源存在記憶體。掛載用來讀取當次金鑰、設定與憑證;重跑時要重新建立測試資源。

8. 今天先做到哪裡就算入門?

留下完整成功回合,或一份能指出失敗層次的紀錄,再列出六種 API 的相容性檢查狀態。雲端尚未驗證的欄位明確寫未測。

給新手的三個重點

  • 先認地址:同一份 SDK 程式可接不同服務;本機檢查要在發送前生效。
  • 再認證據:工具回應、讀回內容與最終狀態要能彼此對上。
  • 最後認邊界:相容性看指定版本與具體測試,安全與部署留給真實 AWS 的驗收單。

接著閱讀

左右滑動查看更多推薦

下一步:先交出一份能回查的 S3 紀錄

今天先完成一個小目標:在新資料夾建立練習檔,讓 Claude Code 幫你檢查端點,再留下寫入、讀回與清理紀錄。把「本機過關=接對端點+工具回應+狀態核對」當成日後每個工具的驗收習慣。

想繼續把單次腳本接成完整 Agent 工作流,可從 AI 教學專區挑下一個觀念,或到 AlphaLab 課程依序練習。先把一回合做得可驗證,再增加第二個服務。

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

週日 Weekly 週報+週二、週四 Alpha Signal,每週最多三封。

我們不會 spam,隨時可退訂。已訂閱?管理訂閱偏好(會寄登入連結到你的信箱)

主題篩選與退訂說明

寄送日期以台灣時間為準。主題偏好會篩選每期精選,並非每篇新文章的即時通知;當期符合主題的文章不足時會略過寄送。

未勾選任何主題會收到所有主題的精選,並不會停止寄信。

取消勾選 Alpha Signal 可停止週二、週四短報,仍保留週日週報。若要停止所有電子報,請使用信件底部的「取消訂閱」。