What's Changed
New Contributors
[1.4.20] — 2026-08-19
Added
- RDS —
FailoverDBCluster— forcing an Aurora failover wasInvalidAction; it now promotes a reader to writer (explicitTargetDBInstanceIdentifieror the lowestPromotionTier), reporting the transitionalfailing-overstatus and flippedIsClusterWriterflags. Metadata-only until per-instance replication lands. Contributed by @Kiran01bm. - RDS — opt-in Aurora PostgreSQL reader replication — with
MINISTACK_RDS_PG_CLUSTER_REPLICATION=1, extra cluster members run their own PostgreSQL containers, cloned withpg_basebackupand streaming WAL as hot standbys (read-only,ReaderEndpointresolves to a reader). Off by default; Aurora MySQL and the no-flag path keep aliasing the writer's shared container. Contributed by @Kiran01bm. - CloudFormation — API Gateway (v1) API keys and usage plans —
AWS::ApiGateway::ApiKey,UsagePlanandUsagePlanKeyfailed withUnsupported resource type; they now provision through the runtime stores withRefandFn::GetAttwired, unblocking CDKRestApi/ApiKeyand Terraformaws_api_gateway_api_key. Contributed by @ryan-bennett. - AWS IoT Jobs — control plane and device data plane —
CreateJobfell through toUnsupported IoT pathandiot-jobs-datadid not exist; theiotservice now serves the nine job operations and a newiot-jobs-dataservice the device ones, sharing one store and the AWS execution state machine. Contributed by @iot-rocket.
Fixed
- S3 — server-side encryption is stated, validated, and enforced — SSE-S3, SSE-KMS and SSE-C headers were accepted and forgotten. SSE is now contract state: validated on write, echoed on HEAD/GET, and enforced for SSE-C (keyless/plain read 400
InvalidRequest, wrong-key read 403AccessDenied), following versions, copies and multipart completes. Contributed by @gaul. - DynamoDB — key attribute types are enforced on
PutItem,Query, andUpdateTable— a key declaredSaccepted anNvalue on write and in a key condition, and an attribute-definitions-onlyUpdateTablechanged a key's type in place; all three now returnValidationException, so no API changes a key's type. Reported by @iot-rocket. - CloudWatch — extended-statistic percentiles are computed instead of aliased to
Average—GetMetricDataand alarm evaluation now interpolatepNNfrom the period's samples on both paths, and a percentile alarm'sStateReasonreports the actual statistic (e.g.p95). Contributed by @MGSousa. - S3 — presigned SigV4 URLs verify for virtual-hosted addressing and temporary credentials — a virtual-hosted URL was rewritten to path-style before its signature was recomputed, and an STS-signed URL was checked against the static secret; verification now runs against the original signed URI and the secret STS issued. Reported by @mayankgupta57.
- Step Functions —
arn:aws:states:::events:putEventsactually publishes the event — the optimized EventBridge integration fell through to the task passthrough, so the state reportedSUCCEEDEDwhile nothing reached any target; it now calls EventBridgePutEventsand returns its response. Reported by @iwasakar. - S3 — SSE-C is enforced and echoed on
UploadPartCopyandCompleteMultipartUpload—UploadPartCopyaccepted a part for an SSE-C upload without the upload's key and read an SSE-C copy source without the source key, and neither echoed the stored encryption;UploadPartCopynow requires both keys (including a?versionId=-qualified source) and echoesSSECustomerAlgorithm/SSECustomerKeyMD5, andCompleteMultipartUploadechoesServerSideEncryption. Contributed by @iot-rocket. - Aurora DSQL —
SELECT ... FOR UPDATEis gated on lock strength, not the predicate — strict mode rejected a locking read unless it was a single table with an equality on every key column (0A000), failing quoted identifiers from every mainstream ORM. Measured against a live cluster,FOR UPDATEnow locks whatever the query selects, whileFOR NO KEY UPDATE/FOR SHARE/FOR KEY SHAREare refused with0A000. Contributed by @vivedo. - Aurora DSQL — quoted identifiers are normalized the way the server stores them —
DROP COLUMN "ID"and mixed-case or schema-qualified table names were mis-resolved; identifiers are now folded as PostgreSQL folds them (bare lower-cased, quoted verbatim) and the relation requoted part by part before lookup. Contributed by @vivedo. - CloudFormation —
AWS::IoT::Policyupdates apply instead of rolling the stack back — the type had no update handler, so an edit hitResourceAlreadyExistsExceptionand rolled back. A changedPolicyDocumentis now a no-interruption update stored as a new default version (pruned to IoT's five-version cap), and a changedPolicyNameis a replacement. Contributed by @maximoosemine. - EC2 — instance public IP and DNS reach the SDKs —
DescribeInstances/RunInstancesemitted the address underpublicIpAddress/publicDnsNamerather than the wire tagsipAddress/dnsName, so every SDK dropped both; they now ride the real tags, and generated addresses complete to four octets. Contributed by @iot-rocket. - S3 — versioning edge cases: the null version, delete markers, and versioned copies — suspended-bucket PUT/DELETE store under the literal
nullversion, pre-versioning objects stay addressable asVersionId=null,DeleteObjectsmints markers (x-amz-delete-marker: trueon the hidden 404), andUploadPartCopy/CopyObjecthonor the source?versionId=. Contributed by @gaul. - S3 —
CompleteMultipartUploadhonorsIf-Match/If-None-Match— conditional writes landed on PutObject but were ignored on the multipart path, so a create-once or compare-and-swap upload could silently overwrite; the complete now evaluates the same preconditions (412 on violation, 404NoSuchKeyforIf-Matchon a missing object). Contributed by @gaul. - S3 — canned ACLs are stored, and object ACLs bind to versions —
PutBucketAcl/CreateBucketdropped thex-amz-aclheader SDKs send, so buckets read back owner-only; both now validate and store the canned grants (InvalidArgument/MalformedACLError/MissingSecurityHeaderas on AWS), and object ACLs are per-version like tags. Contributed by @gaul. - S3 —
CRC64NVMEchecksums are computed instead of refused — the default SDK/CLI checksum algorithm returnedInvalidRequest, so a stockaws s3 cpfailed; it is now computed from a stdlib table (no new dependency), validated on upload (BadDigeston mismatch) and returned on GET/HEAD.CRC32Cstill needs its native library. Contributed by @gaul. - CloudFormation — auto-generated physical names keep their uniqueness suffix when truncated — a deeply-nested stack whose generated name exceeded a resource's name cap truncated every resource to the same string and collapsed them onto one; the hash suffix that guarantees uniqueness is now always preserved. Contributed by @ryan-bennett.
- IAM — role
Descriptioncharset is validated —CreateRole,UpdateRoleandUpdateRoleDescriptionnow reject a description outside IAM's allowed character set or longer than 1000 characters with400 ValidationError. Reported by @iot-rocket. - CloudFormation —
AWS::SSM::Parametergoes through the SSM API — instead of writing the store directly, so a create over an existing name fails (ParameterAlreadyExists), updates incrementVersion, aNamechange replaces,SecureStringis rejected, andFn::GetAttexposesArn/Type/Value. Reported by @iot-rocket. - CloudFormation —
AWS::SSM::Parameter::Value<...>is re-resolved onUpdateStack— the parameter name is kept and re-resolved on every operation, so an update withUsePreviousValue=truepicks up a value changed in Parameter Store since the last deploy. Reported by @iot-rocket.