เคยไหม ที่สั่งให้ AI เขียนโค้ดเรียก S3 แล้วมันเขียนเสร็จ แต่คุณไม่รู้ว่ามันจะพังตรงไหน เพราะการเทสต์ AWS จริงต้องมีบัญชี ต้องเสียเงิน แล้วบางทีก็เผาเครดิตไปเยอะกว่าที่ตั้งใจ
AWS เพิ่งปล่อย AWS Emulator เมื่อ 11 พ.ย. ตัวนี้เป็นตัวจำลอง AWS API ที่รันในเครื่องเรา คุณชี้ AWS CLI หรือ SDK ไปที่ endpoint ในเครื่อง แล้วมันจะตอบเหมือนของจริง ที่สำคัญกว่านั้นคือ มันถูกสร้างขึ้นโดย agent
หลักการเรียบมาก เมื่อ emulator เริ่มทำงานมันจะ:
สร้าง credential, config file และ certificate ของตัวเอง
เขียนไว้ที่ ~/.aws/emulator/9297/
ฟัง HTTPS ที่ 127.0.0.1:9297 (bind แค่เครื่องตัวเอง)
จากนั้นเราก็แค่ export env vars ให้ชี้มาที่มัน แล้วโค้ดของเราไม่ต้องแก้อะไรเลย:
bash copy export AWS_ENDPOINT_URL = https://127.0.0.1:9297
export AWS_SHARED_CREDENTIALS_FILE =~ /.aws/emulator/9297/emulator_credentials
export AWS_CONFIG_FILE =~ /.aws/emulator/9297/config
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
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_PROFILE
จุดที่ผมชอบคือ มันสร้าง key ใหม่ทุกครั้งที่ start และ access key ID ขึ้นต้นด้วย EMULATOR แถว request ที่ sign ด้วย key อื่นจะถูกปฏิเสธ ทำให้เรายังไม่หลุดไปใช้ credential จริงแบบเงียบ ๆ
ตัว emulator เองเป็น account เดียวคือ 000000000000 ลองเช็คสุขภาพกับดูว่าเราคุยกับใคร:
bash copy curl --cacert ~/.aws/emulator/9297/ca.pem https://127.0.0.1:9297/__admin/health
aws sts get-caller-identity
แล้วก็ใช้คำสั่ง AWS ปกติได้เลย:
bash copy $ aws s3 mb s3://local-getting-started
make_bucket: local-getting-started
$ echo "hello from the emulator" > hello.txt
$ aws s3 cp hello.txt s3://local-getting-started/
upload: ./hello.txt to s3://local-getting-started/hello.txt
$ aws s3 ls s3://local-getting-started/
บน Linux ใช้ RPM หรือ Debian package ได้เลย:
bash copy PKG = https://downloads.aws.com/aws-emulator/packages/aws-emulator/LTS/latest
sudo dnf install -y $PKG /aws-emulator-x86_64.rpm
aws-emulator -v
ส่วน macOS กับ Windows ต้องรันใน Docker โดย build image จาก Dockerfile สั้น ๆ ที่อยู่ในเอกสาร (AWS ไม่ปล่อย image สำเร็จรูป)
พร้อมกันนี้มี aws-emulator skill สำหรับ agent อย่าง Kiro, Cursor และ Claude Code ติดตั้งด้วย:
bash copy aws agent-toolkit add-skill --skill-name aws-emulator --region us-east-1
ต้องมี AWS CLI v2.35.0 ขึ้นไป
นี่คือส่วนที่ผมชอบที่สุดของเรื่องนี้ AWS Emulator ถูกสร้างและดูแลโดย agent จาก AWS API models โดยใช้ Bedrock AgentCore Runtime, CodePipeline และ CodeCommit
วงจรการทำงานของ agent มีสองกลุ่ม:
กลุ่มหนึ่งหา gap: เทียบ response ของ emulator กับ AWS จริง และ static compare โค้ดของ emulator กับ Smithy model ที่ publish ไว้ แล้วเปิด issue ทีละเรื่อง
กลุ่มที่สองแก้: รับ issue มาเขียนเทสต์ ทำ behavior ให้ครบ แล้ว review การเปลี่ยนแปลง
พอ push เข้า source repo มันจะ trigger CodePipeline ให้รัน fidelity tests ก่อน publish ออกไปที่ GitHub repo สาธารณะ
เรื่องความปลอดภัยก็จัดการแบบนี้: เพราะโค้ดเขียนโดย agent จึงมี security agent อีกตัวหนึ่ง review แบบ adversarial ทั้งระหว่างแก้และอีกครั้งใน pipeline ก่อน ship
นี่คือ pattern ที่น่าสนใจมาก ๆ: agent เขียนโค้ด → agent อื่นหาบั๊ก → agent อื่นแก้ → เทสต์อัตโนมัติ → agent ด้านความปลอดภัยตรวจอีกชั้น
ตัว emulator จะมีค่าตัวเลขที่เรียกว่า fidelity score บอกว่า service แต่ละตัวผ่านกี่ test จากทั้งหมด เช่น 40 of 50 แปลว่า 50 test ของ service นั้นผ่าน 40 ตัว
วิธีวัดคือเอา program สั้น ๆ ที่ใช้ AWS SDK ทำ workflow จริง (เช่น เก็บ object แล้วอ่านแล้วลบ) แล้วเทียบกับ AWS จริงว่าตรงกันทุกจุด: status code, body, error code และ message, resource และ data ที่ถูกสร้าง
จุดที่ดีคือ ชุด test เปิดเผย อยู่ที่ repo aws-emulator-evaluation-suite รวมถึงตัวที่ยังไม่ผ่านด้วย ใครอยากรู้ว่า AWS Emulator ตรงกับของจริงแค่ไหนใน service ที่ตัวเองใช้ ดูคะแนนได้เลย
ข้อควรระวังคือคะแนนอาจ ลดลง แม้ emulator จะดีขึ้น เพราะการเพิ่ม test ใหม่ทำให้ตัวส่วนที่ยังไม่ผ่านเพิ่มขึ้น ต้องอ่านเป็น snapshot ของผลิตภัณฑ์ที่กำลังดีขึ้น ไม่ใช่คะแนนสะสม
ถ้า emulator ยังไม่ implement operation นั้น มันจะตอบ HTTP 501 (Not Implemented) เลย เทสต์จะ fail ทันที ดีกว่าที่แอบผ่าน
AWS พูดตรง ๆ มากในบทความนี้ ซึ่งผมชอบ เพราะมันเป็นของที่ทำตามได้:
มันไม่ evaluate IAM policy อย่างที่ AWS ทำ request ที่ AWS จะปฏิเสธ อาจผ่านใน emulator
ไม่มีพฤติกรรมข้าม account หรือข้าม Region
ไม่ใช่ตัวแทน production ความใกล้เคียงกับ AWS ขึ้นกับ service และ feature
อย่าใช้มันทดสอบว่าแอปของเราปลอดภัยหรือไม่ ต้องเทสต์ security settings และทั้งแอปบน AWS จริงก่อนขึ้น production
เก็บ credential จริงออกจาก environment ของเทสต์ เสมอ
สรุปคือ AWS Emulator เหมาะกับ "เขียนโค้ด + ทดสอบว่าการเรียก API ถูกรูปแบบไหม" ไม่ใช่ "เขียนโค้ด + ทดสอบว่า permission ถูกไหม"
คำถามที่คนจะถามแรกคือ "ต่างจาก LocalStack ยังไง" ข้อแตกต่างที่ชัดเจนจากตัวเลขและสถาปัตยกรรม:
AWS Emulator เป็นของ AWS จริง เขียนด้วย Rust จาก AWS API models ที่ publish ไว้ เลย error code และ message ออกมาเหมือนของจริงโดยโครงสร้าง
มีระบบวัด fidelity เป็นตัวเลขสาธารณะ พร้อมเปิดเผยชุด test ทั้งที่ผ่านและไม่ผ่าน
มี embedded mode สำหรับเทสต์ ใน Rust SDK — instantiate ใน process ทดสอบแล้ว wire เข้า HTTP client ของ SDK แต่ละ instance แยก state กัน รันขนานได้หลายตัว
โค้ดตัวอย่าง embedded mode:
rust copy use aws_emulator_embedded :: { AwsEmulatorEmbedded , EmbeddedOptions };
#[tokio :: test]
async fn put_then_get_returns_the_item () {
let emulator = AwsEmulatorEmbedded :: new ( EmbeddedOptions :: default ());
let config = aws_config :: defaults ( aws_config :: BehaviorVersion :: latest ())
. http_client (emulator . http_client ())
. region ( aws_config :: Region :: new ( "us-east-1" ))
. credentials_provider (emulator . aws_credentials_provider ())
. load ()
.await ;
let ddb = aws_sdk_dynamodb :: Client :: new ( & config);
ddb . create_table ()
. table_name ( "emulator-demo-table" )
. attribute_definitions (
AttributeDefinition :: builder ()
. attribute_name ( "id" ) . attribute_type ( ScalarAttributeType :: S )
. build () . unwrap ())
. key_schema (
KeySchemaElement :: builder ()
. attribute_name ( "id" ) . key_type ( KeyType :: Hash )
. build () . unwrap ())
. billing_mode ( BillingMode :: PayPerRequest )
. send () .await. unwrap ();
ddb . put_item ()
. table_name ( "emulator-demo-table" )
. item ( "id" , AttributeValue :: S ( "item-1" . into ()))
. item ( "msg" , AttributeValue :: S ( "hi" . into ()))
. send () .await. unwrap ();
let got = ddb . get_item ()
. table_name ( "emulator-demo-table" )
. key ( "id" , AttributeValue :: S ( "item-1" . into ()))
. send () .await. unwrap ();
assert_eq! (got . item () . unwrap () . get ( "msg" ) . unwrap () . as_s () . unwrap (), "hi" );
}
จุดที่ AWS โชว์ในบทความคือเปิด Kiro แล้วสั่งให้มันสร้าง DynamoDB table, ใส่ item, อ่านกลับ ทั้งหมดผ่าน emulator ที่รันอยู่ในเครื่อง:
plaintext copy kiro> Using the local AWS Emulator (the environment variables
are already set in this shell), create a DynamoDB table
"kiro-demo" with a string key "id", put an item
{id: "item-1", msg: "hello from kiro"}, then read it
back with get-item.
$ aws dynamodb create-table --table-name kiro-demo \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
$ aws dynamodb put-item --table-name kiro-demo \
--item '{"id": {"S": "item-1"}, "msg": {"S": "hello from kiro"}}'
$ aws dynamodb get-item --table-name kiro-demo --key '{"id": {"S": "item-1"}}'
นี่คือ loop ที่ผมว่ามีค่าที่สุด: agent เขียนโค้ด → รันเทสต์ → เห็น error จริง → แก้ → รันใหม่ ทั้งหมดเกิดในเครื่องโดยไม่ต้องรอ deploy หรือเสียเงิน ซึ่งก่อนหน้านี้มันคือรอบที่ช้าที่สุดของ workflow พัฒนาโค้ด
ถ้างานของเรามี dependency กับ AWS อยู่จริง ๆ อย่าง S3, DynamoDB, SQS หรือ Bedrock แล้ว emulator นี้น่าจะคุ้ม เพราะ:
ไม่มีค่าใช้จ่ายเพิ่ม จ่ายแค่ตอน deploy ขึ้น AWS จริง
เทสต์เป็นเรื่องปกติ ไม่ต้องมี infra
agent ทำงานได้จริง ไม่ต้องเดา API
แต่ให้ดู fidelity score ของ service ที่เราใช้ก่อน แล้วค่อยตัดสินใจว่าจะพึ่งมันแค่ไหน และอย่าลืมว่าเรื่อง permission กับ security ยังต้องเทสต์บน AWS จริงเสมอ