AWS EmulatorをWindowsのDockerで動かす(S3をオフラインで試す)

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で公開されています。

aws/aws-emulator

公式ドキュメントは以下です。

AWS Emulator User Guide

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

コメント

タイトルとURLをコピーしました