April 29, 2026 · v1.3.20
1.3.20 is the first release where API Gateway can enforce JWT authorizers and apply HTTP / HTTP_PROXY request parameter mappings, the DynamoDB Streams API is reachable from boto3.client("dynamodbstreams") instead of just driving the internal Lambda ESM path, DynamoDB tables can fan item mutations out to Kinesis as a streaming destination, and the gateway can speak TLS natively without a separate terminator. Plus a sweep of small AWS-shape fixes that close the kind of gaps Java SDK v2 and the AWS CLI notice quietly.
USE_SSLThe gateway listener now speaks TLS when USE_SSL=1 (also accepts true / yes). The flag name aligns with LocalStack's USE_SSL so a compose.yml switching emulator doesn't need TLS-specific changes. By default MiniStack auto-generates a self-signed RSA cert (CN: ministack-local, SAN: localhost, ministack, 127.0.0.1, ::1) cached under ${TMPDIR}/ministack-tls/ so the cert survives restarts. To pin a specific cert (e.g. an mkcert-issued one for browser trust), set MINISTACK_SSL_CERT and MINISTACK_SSL_KEY to PEM paths.
Auto-generation shells out to the openssl CLI (already present in both the Alpine and Debian images), so no Python crypto dependency is added. Unblocks AWS SDKs that hardcode https:// against Cognito Hosted UI endpoints (e.g. Amplify v6) without needing a separate TLS-terminating proxy. Closes #526. Contributed by @prandogabriel.
USE_SSL=1 docker run --rm -p 4566:4566 ministackorg/ministack:1.3.20 curl -k https://localhost:4566/_ministack/health
Both HTTP API (apigateway) and REST API (apigateway_v1) gain three coordinated features:
issuer + audience against a JWKS URL. RS256 signatures only — Cognito's standard. Authorizer issuers of the form https://cognito-idp.{region}.amazonaws.com/{poolId} are rewritten to MiniStack's local Cognito JWKS endpoint so locally-minted tokens verify without leaving the box. Cognito's signing key is now persisted under ${STATE_DIR}/cognito-rsa-key.pem so tokens minted in one process verify in another.HTTP / HTTP_PROXY request parameter mapping. append / overwrite / remove for headers and querystring, plus overwrite:path. Substitutions for $context.authorizer.jwt.claims.* and $stageVariables.* are applied at proxy time. The reserved-header list matches the AWS HTTP API spec exactly (the verifiable, public list — not a guess from a contributor's tests).MINISTACK_APIGW_PROXY_TIMEOUT_SECONDS (default 30), MINISTACK_APIGW_JWKS_TIMEOUT_SECONDS (default 5).Contributed by @marcin-nowak-scl.
A new module, ministack/services/dynamodb_streams.py, exposes ListStreams, DescribeStream, GetShardIterator, and GetRecords via boto3.client("dynamodbstreams") and the streams.dynamodb.{region}.amazonaws.com host. It reads the records already captured by the main DynamoDB service (emitted from PutItem, UpdateItem, DeleteItem, TransactWriteItems, and BatchWriteItem) so the public Streams API and the internal Lambda ESM path share one source of truth.
All four iterator types (TRIM_HORIZON, LATEST, AT_SEQUENCE_NUMBER, AFTER_SEQUENCE_NUMBER) and all four stream view types (NEW_AND_OLD_IMAGES, NEW_IMAGE, OLD_IMAGE, KEYS_ONLY) are supported. Single synthetic shard per stream; opaque base64 iterator tokens. Unblocks DynamoDbOutboxWorker-style consumers and any test harness that wants to DescribeStream + GetShardIterator + GetRecords directly. Contributed by @marcin-nowak-scl.
Four new operations on boto3.client("dynamodb"):
EnableKinesisStreamingDestinationDisableKinesisStreamingDestinationDescribeKinesisStreamingDestinationUpdateKinesisStreamingDestinationItem mutations from PutItem / UpdateItem / DeleteItem / TransactWriteItems / BatchWriteItem fan out to every ACTIVE destination as JSON-encoded records (via kinesis.put_record_internal) for Kinesis / Lambda ESM / Firehose-style consumers. DISABLED destinations remain on Describe for the ~24h AWS window; DeleteTable drops destinations.
The Kinesis fan-out is decoupled from StreamSpecification.StreamEnabled — a table can have a Kinesis destination without a DynamoDB Stream, and vice versa. Status transitions match AWS: Enable returns ENABLING (storage ACTIVE), Disable returns DISABLING (storage DISABLED), Update returns UPDATING (storage ACTIVE). The wire envelope reuses the DynamoDB Streams record shape — AWS does not publicly document the exact Kinesis envelope it produces, so MiniStack approximates it with the Streams record. Contributed by @marcin-nowak-scl.
aws-sdk:rds:removeFromGlobalCluster left global cluster members attached. The query-protocol parameter conversion uppercased DbClusterIdentifier to DBClusterIdentifier, but the RDS API shape for RemoveFromGlobalCluster intentionally uses the lowercase-b form. The task now preserves that member name so a successful remove actually detaches the cluster and a following DeleteGlobalCluster matches AWS behaviour. Contributed by @jayjanssen.ListShards NextToken returned a raw shard ID instead of an opaque base64url-encoded token. AWS specifies an opaque token (length 1–1048576) with a 300-second TTL that yields ExpiredNextTokenException when expired; MiniStack now emits one and rejects expired or malformed tokens with the AWS-correct error code. SDKs that round-trip the token (and the rare consumers that inspect or persist it) see AWS-shape behaviour.DescribeContinuousBackups returned EarliestRestorableDateTime: 0 / LatestRestorableDateTime: 0 when PITR was disabled. Emitting Unix epoch 1970 misled SDK consumers that parsed the values into datetimes (some of them quite confidently — January 1, 1970 is rarely what you want from a "latest restorable" field). Both fields are now omitted when PointInTimeRecoveryStatus is DISABLED and populated with a real timestamp when ENABLED.DescribeEndpoints returned the hardcoded real-AWS endpoint dynamodb.us-east-1.amazonaws.com. Endpoint-discovery-aware SDKs would cache that address and silently redirect subsequent calls away from MiniStack to real AWS — the kind of bug that only surfaces when the test machine has live AWS credentials. The endpoint now reflects MiniStack's own host (MINISTACK_HOST:GATEWAY_PORT) so SDKs keep talking to the emulator.# Regular image (Alpine) docker pull ministackorg/ministack:1.3.20 # Full image (Debian + DuckDB + psycopg2 + pymysql) docker pull ministackorg/ministack:1.3.20-full # pip pip install -U ministack
Full changelog: CHANGELOG.md.
Shipped by the MiniStack community. Contributions credited throughout. GitHub · r/ministack