AWSがAWSのAPIを手元で再現する「AWS Emulator」を公開したので、WindowsのDockerで動かしてS3を試しました。
AWSアカウントなしで動くのか、ネットにつながっていなくても使えるのかも確かめています。
AWS Emulatorとは
AWS CLIやAWS SDKからのリクエストを、AWSの代わりに受け付けるローカルのプログラムです。
S3、DynamoDB、SQS、Lambdaなど、AWSのAPIモデルが公開されているサービスを1つのエンドポイントでまとめて受け付けます。
AWSアカウントは不要で、リクエストやデータはAWSに送られません。作ったバケットやテーブルはメモリ上にあるだけなので、エミュレーターを止めると消えます。
ソースコードはGitHubで公開されています。
公式ドキュメントは以下です。
LinuxはRPMとDebianのパッケージがあり、そのまま動かせます。WindowsとmacOSはDockerで動かす方法になっていて、配布されているDockerfileからイメージを自分でビルドします(ビルド済みのイメージは配布されていません)。
イメージを作る
空のフォルダを作って、以下の内容で Dockerfile を保存します。
公式ドキュメントに載っている内容そのままです。
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"]
Apple シリコンのMacなどArmのCPUの場合は、aws-emulator-x86_64.rpm を aws-emulator-aarch64.rpm に変えます。
同じフォルダで以下のコマンドを実行します。
docker build -t aws-emulator .
ビルドは31秒で終わりました。イメージのサイズは1.27GBです。
ビルド中に Header V4 RSA/SHA512 Signature, key ID d940f624: NOKEY という警告が出ますが、署名を確認するための鍵をイメージに入れていないだけなので、そのまま進みます。
起動する
エミュレーターが認証情報や証明書を書き出すフォルダを先に作っておきます。
New-Item -ItemType Directory -Force "$env:USERPROFILE\.aws\emulator"
以下のコマンドで起動します。
$port = 9297
docker run -d --name aws-emulator --rm --memory=2g --memory-swap=2g -p "127.0.0.1:${port}:${port}" `
-v "$env:USERPROFILE\.aws\emulator:/home/emulator/.aws/emulator" `
aws-emulator -p $port --telemetry off
AWS Emulatorは初期設定で利用状況のデータ(テレメトリー)をAWSに送ります。リクエストの中身は送らないと書かれていますが、今回は --telemetry off でオフにしました。
公式の手順は -d なしでターミナルに張り付く形ですが、同じターミナルでCLIを打ちたかったので -d と --name を付けています。
-p は 127.0.0.1:9297:9297 のように 127.0.0.1 を付けます。-p 9297:9297 にすると、同じネットワークにある他のPCからもエミュレーターに接続できてしまいます。
ログは以下のコマンドで見られます。
docker logs aws-emulator
{"timestamp":"2026-11-13T06:46:02.501133Z","level":"INFO","fields":{"message":"aws-emulator emulator starting"},"target":"aws_emulator"}
{"timestamp":"2026-11-13T06:46:02.748985Z","level":"INFO","fields":{"message":"request authentication enabled","credentials_file":"/home/emulator/.aws/emulator/9297/emulator_credentials"},"target":"aws_emulator_server"}
{"timestamp":"2026-11-13T06:46:02.765787Z","level":"INFO","fields":{"message":"emulator server information","endpoint_url":"https://127.0.0.1:9297","health_check_url":"https://127.0.0.1:9297/__admin/health",...},"target":"aws_emulator_server"}
{"timestamp":"2026-11-13T06:46:02.765841Z","level":"WARN","fields":{"message":"the emulator listens on 0.0.0.0, not loopback: ...","bind_address":"0.0.0.0"},"target":"aws_emulator_server"}
This emulator collects usage and error telemetry: disabled ...
0.0.0.0 で待ち受けているという警告が出ますが、これはコンテナの中の話です。PC側は -p 127.0.0.1:... で自分のPCからしか接続できないので問題ありません。
起動すると %USERPROFILE%\.aws\emulator\9297 に以下のファイルができます。
emulator_credentials(このエミュレーター専用のアクセスキー)config(AWS CLI用の設定)ca.pem(HTTPSの証明書)truststore.p12(Java用の証明書)
アクセスキーと証明書は起動するたびに作り直されます。
AWS CLIをつなぐ
AWS CLIを使うターミナルで、以下の環境変数を設定します。
$env:AWS_ENDPOINT_URL = "https://127.0.0.1:9297"
$env:AWS_SHARED_CREDENTIALS_FILE = "$env:USERPROFILE\.aws\emulator\9297\emulator_credentials"
$env:AWS_CONFIG_FILE = "$env:USERPROFILE\.aws\emulator\9297\config"
$env:AWS_CA_BUNDLE = "$env:USERPROFILE\.aws\emulator\9297\ca.pem"
$env:AWS_EC2_METADATA_DISABLED = "true"
$env:AWS_DISABLE_HOST_PREFIX_INJECTION = "true"
$env:AWS_REGION = "us-east-1"
$env:AWS_DEFAULT_REGION = "us-east-1"
本物のAWSの認証情報が環境変数に入っていると、そちらが優先されるので消しておきます。
Remove-Item Env:AWS_ACCESS_KEY_ID, Env:AWS_SECRET_ACCESS_KEY, Env:AWS_SESSION_TOKEN, Env:AWS_PROFILE -ErrorAction SilentlyContinue
config の中の証明書のパスはコンテナの中のパス(/home/emulator/...)になっているので、Windowsでは AWS_CA_BUNDLE の指定が必要です。
エミュレーターにつながっているかは以下のコマンドで確認できます。
aws sts get-caller-identity
{
"UserId": "AIDAH5I7GEMO7ADXNFAZU",
"Account": "000000000000",
"Arn": "arn:aws:iam::000000000000:user/emulator"
}
Account が 000000000000 になっていればエミュレーターにつながっています。自分のアカウントIDが出た場合は、本物のAWSにつながっています。
AWS CLIが古いと本物のAWSに向かう
最初、手元のAWS CLIが2.6.2のままで試したところ、エミュレーターにつながりませんでした。
AWS_ENDPOINT_URL の環境変数に対応したのはAWS CLI 2.13.0からで、それより古いCLIはこの環境変数を無視して本物のAWSにリクエストを送ろうとします。
今回は念のためダミーのプロキシを設定して外に出ないようにしていたので、Failed to connect to proxy URL で止まりました。
Windowsでwingetから入れている場合は、以下のコマンドで更新できます。
winget upgrade --id Amazon.AWSCLI --exact
更新できない場合は、コマンドごとに --endpoint-url を付ければ古いCLIでもつながります。
aws sts get-caller-identity --endpoint-url https://127.0.0.1:9297
S3を試す
バケットを作って、ファイルをアップロードします。
"hello aws-emulator" | Out-File -Encoding ascii hello.txt
aws s3 mb s3://test-bucket
aws s3 cp hello.txt s3://test-bucket/hello.txt
make_bucket: test-bucket
upload: .\hello.txt to s3://test-bucket/hello.txt
一覧と中身の確認です。
aws s3 ls s3://test-bucket/
aws s3 cp s3://test-bucket/hello.txt -
2026-11-13 15:49:59 20 hello.txt
hello aws-emulator
署名付きURLも発行できて、curlでダウンロードできました。
$url = aws s3 presign s3://test-bucket/hello.txt
curl.exe --cacert "$env:USERPROFILE\.aws\emulator\9297\ca.pem" $url
hello aws-emulator
ちなみに、エンドポイントは localhost ではなく 127.0.0.1 のままにします。localhost にすると、JavaScriptやJava、GoのSDKはバケット名をホスト名に入れたリクエスト(test-bucket.localhost)を送るので、エミュレーターに届きません。
ネットワークを切っても動くか
イメージのビルドにはネットが必要ですが、ビルドしたあとはネットなしで動くのかを試しました。
--network none を付けて、外部と一切通信できないコンテナの中でエミュレーターを起動し、同じコンテナの中からcurlでS3にアクセスします。
PowerShell 5.1から実行すると引数の中の " が崩れて動かなかったので、Git Bashから実行しています。
docker run --rm --network none --entrypoint bash aws-emulator -c '
aws-emulator -p 9297 --telemetry off --auth off >/tmp/emu.log 2>&1 &
sleep 3
S="--aws-sigv4 aws:amz:us-east-1:s3 --user test:test -sk"
echo "health: $(curl -sk https://127.0.0.1:9297/__admin/health)"
echo "PUT bucket: $(curl $S -o /dev/null -w %{http_code} -X PUT https://127.0.0.1:9297/offline-bucket)"
echo "PUT object: $(curl $S -o /dev/null -w %{http_code} -X PUT --data-binary offline-ok https://127.0.0.1:9297/offline-bucket/a.txt)"
echo "GET object: $(curl $S https://127.0.0.1:9297/offline-bucket/a.txt)"
curl -s -m 3 -o /dev/null https://aws.amazon.com; echo "external rc=$?"
'
health: ok
PUT bucket: 200
PUT object: 200
GET object: offline-ok
external rc=6
外部への接続は失敗する(rc=6 は名前解決ができないエラー)状態で、バケットの作成、アップロード、ダウンロードができました。
--auth off は署名のチェックをしないオプションです。ただし署名そのものが無いと、どのサービスへのリクエストか判断できずに UnknownService が返ってきます。そのため、curlの --aws-sigv4 で適当なキーを使って署名しています。
注意点
公式ドキュメントに書かれている制限です。
- 作ったリソースはメモリ上にあるだけで、止めると消える
- リージョンとアカウントを分けて管理しない(リージョンを分けて試すなら、ポートを変えてエミュレーターを複数起動する)
- IAMのポリシーをAWSと同じようには評価しないので、権限の検証には使えない
- 長時間の運用や負荷試験は想定していない
AWSとどこまで同じ動きをするかは、リリースごとに scores.json.gz として公開されています。
v1.0.338のファイルからS3だけを対象にしたテストを数えると、1,226件中1,014件がAWSと同じ結果でした。条件付き書き込み(If-Match)、オブジェクトロック、SSE-Cなどは、まだ動かないものとしてリポジトリの issues/things-that-do-not-work/ に載っています。
S3以外だと、Lambdaの Invoke は関数のコードを実行せず NotImplemented を返すと、同じ場所に載っています(2026年11月13日時点)。Lambdaを含む処理を試したい場合は注意が必要です。
止める
docker stop aws-emulator
--rm を付けているのでコンテナも消えます。
%USERPROFILE%\.aws\emulator\9297 の中のファイルはエミュレーターが消してくれます(空の 9297 フォルダは残りました)。
イメージが要らなくなったら消しておきます。
docker image rm aws-emulator

コメント