A high-fidelity AWS emulator for local development and testing.
Goal: if it works on kumolo, it works on real AWS — and vice versa.
kumolo runs as a standalone server that accepts standard AWS SDK v2 requests. No mocking, no stubs — it behaves like real AWS.
docker run -p 5566:5566 ghcr.io/optiflowic/kumolo:latestOr with persistent storage:
docker run -p 5566:5566 -v $(pwd)/data:/data ghcr.io/optiflowic/kumolo:latestservices:
kumolo:
image: ghcr.io/optiflowic/kumolo:latest
ports:
- "5566:5566"
volumes:
- ./data:/dataDownload the latest binary from GitHub Releases and run:
kumoloPoint your AWS SDK at http://localhost:5566 — no other changes needed.
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
cfg, err := config.LoadDefaultConfig(context.Background(),
config.WithRegion("us-east-1"),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
)
if err != nil {
panic(err)
}
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String("http://localhost:5566")
o.UsePathStyle = true
})The same pattern applies to DynamoDB, KMS, STS, and other supported services.
| Service | Operations |
|---|---|
| Cognito | User pool and client CRUD, auth flows (SignUp, ConfirmSignUp, ResendConfirmationCode, InitiateAuth, RespondToAuthChallenge), admin operations, group management, token lifecycle (RevokeToken, GlobalSignOut, refresh token expiry), JWKS endpoint, Tags |
| DynamoDB | Table CRUD, Item operations (Get/Put/Delete/Update), Query, Scan, Batch operations, Transactions, PartiQL (ExecuteStatement / BatchExecuteStatement / ExecuteTransaction), Streams, TTL, Tags, Kinesis streaming destinations |
| KMS | Key management (Create/Describe/Enable/Disable/Schedule deletion), Data plane (Encrypt/Decrypt/GenerateDataKey/GenerateDataKeyPair), Aliases, Key rotation, Grants, Tags |
| S3 | Bucket CRUD, Object CRUD, Multipart Upload, Versioning, Tagging, CORS, Policy, Lifecycle, ACL (enforced), Encryption (SSE-S3 / SSE-KMS / SSE-C), Object Lock, SelectObjectContent, BucketLogging, BucketReplication, and more |
| STS | GetCallerIdentity, AssumeRole, GetSessionToken |
For the full list of supported operations, see the documentation.
| Environment Variable | Default | Description |
|---|---|---|
KUMOLO_PORT |
5566 |
HTTP listen port |
KUMOLO_DATA_DIR |
./data |
Persistent storage directory |
KUMOLO_LOG_LEVEL |
info |
Log level (debug, info, warn, error) |
kumolo aims for high fidelity, but some behaviors differ from real AWS by design or as a known gap.
DynamoDB
ConsumedCapacityis returned whenReturnConsumedCapacityisTOTALorINDEXES, butCapacityUnitsis always1.0— actual RCU/WCU are not computed.- Number attribute comparisons use
float64precision. Values with more than 15 significant digits may not compare correctly.
KMS
- Grant-based access control is not enforced — all KMS operations succeed regardless of grant
OperationsorConstraints. - Key rotation does not run on a schedule. Use
RotateKeyOnDemandto trigger a rotation in tests.
S3
- Bucket Policy rules are stored and returned but not enforced — all requests are permitted regardless of policy content.
- SigV4 request signatures are parsed but not cryptographically verified. This is intentional for local development.
STS
AssumeRolealways returns the same fixed credentials regardless of which role ARN is specified. Multiple distinct roles are not simulated.
See CONTRIBUTING.md.
MIT — see LICENSE.
