github ministackorg/ministack v1.5.32

5 hours ago

What's Changed

New Contributors

[1.5.32] — 2026-10-23

Added

  • EC2 — Verified Access control plane — instances, trust providers (oidc, and jamf, crowdstrike and jumpcloud devices), groups, load-balancer and network-interface endpoints, trust provider attachments, instance logging configuration, and group and endpoint policies, as the aws_verifiedaccess_* Terraform resources call them, with AWS's codes, messages and check order. Under AUTH=true each call is authorized on every resource AWS checks it against. No access evaluation or Cedar parsing; rds and cidr endpoints and NativeApplicationOidcOptions answer UnsupportedOperation. Contributed by @kharabasz.
  • Step Functions — Distributed Map — a Map whose ProcessorConfig mode is DISTRIBUTED ran inline, with no map run and its ItemReader ignored; it now creates a Map Run (ListMapRuns, DescribeMapRun, UpdateMapRun, ListExecutions with mapRunArn) whose items run as child executions under <state machine>/<label>, reads its items from S3 (s3:getObject as JSON, JSONL or CSV, s3:listObjectsV2 object metadata, MaxItems), and fails with States.ExceedToleratedFailureThreshold past its tolerated failures. Reported by @cupidchan.
  • SSM — service settings — GetServiceSetting, UpdateServiceSetting and ResetServiceSetting, per account and region, persisted. SettingValue is validated for the ids whose accepted values AWS documents, and /ssm/parameter-store/default-parameter-tier sets the Tier of a PutParameter that names none. Unblocks Terraform's aws_ssm_service_setting. Contributed by @skialpine.
  • Auth — SigV4a signatures are verified under AUTH=true — requests signed with AWS4-ECDSA-P256-SHA256, which SDKs use for Multi-Region Access Points, were refused for every IAM user. Header and presigned S3 signatures are now checked with the P-256 key SigV4a derives from the secret, with their date or expiry, and an X-Amz-Region-Set that leaves out the serving region is refused (RegionSetMismatch on S3, the unknown-key error elsewhere). Contributed by @iot-rocket.

Fixed

  • Auth — requests without credentials are anonymous in every service — under AUTH=true a request with no Authorization header and no query signature ran as the account root everywhere but S3; it is now refused in the service's own error, as on AWS: MissingAuthenticationToken 403 from Query and REST-XML services, MissingAuthenticationTokenException from JSON services, AccessDenied 403 from SQS, UnrecognizedClientException from Secrets Manager. Operations the SDKs send unsigned (Cognito sign-in, GetId, AssumeRoleWithWebIdentity), SNS ConfirmSubscription and Unsubscribe, API Gateway and Function URL invokes and S3 keep their behaviour. Contributed by @iot-rocket.
  • Auth — a query signed for s3 is refused by other services — under AUTH=true a SigV4 presigned query with an s3 credential scope skipped the signature check when another service served it; it is now refused with SignatureDoesNotMatch "Credential should be scoped to correct service: ''. ", as AWS answers, while S3 keeps verifying its own presigned URLs. Reported by @iot-rocket.
  • S3 — access points and Multi-Region Access Points under AUTH=true — an access point policy was stored but never applied, and unsigned requests, SigV2 Authorization headers and PutBucketPolicy/DeleteBucketPolicy through an access point were served; a request through an access point alias or ARN is now allowed on the access point by an identity policy or its policy, an unsigned or SigV2-header one gets 400 InvalidRequest, bucket policy writes get 403 AccessDenied, and SigV2 presigned URLs for an access point ARN verify. MRAP requests are authorized on the member bucket and then on the MRAP. Contributed by @iot-rocket.
  • S3 — ACLs and Block Public Access — on a BucketOwnerEnforced bucket ACL writes answered 200 and a stored grant still opened the bucket; PutBucketAcl and PutObjectAcl now answer 400 AccessControlListNotSupported, uploads refuse any ACL but an owner-only one, and CreateBucket or a switch to BucketOwnerEnforced refuses a granting ACL with InvalidBucketAclWithObjectOwnership. Under AUTH=true a new bucket has all four Block Public Access settings on, as on AWS, so a public policy or ACL answers 403 AccessDenied and CreateBucket with a public ACL InvalidBucketAclWithBlockPublicAccessError; RestrictPublicBuckets drops a bucket policy only when it is public. Contributed by @iot-rocket.
  • S3 — CORS under AUTH=true — every preflight answered 200 with Access-Control-Allow-Origin: *, whatever the bucket's CORS configuration; a preflight now has to match one of the bucket's rules (403 AccessForbidden without a configuration or a match, 400 BadRequest without Origin) and gets that rule's headers. Contributed by @iot-rocket.
  • S3 — presigned expiry and multipart object size — under AUTH=true a presigned URL without X-Amz-Expires never expired; it now answers 400 AuthorizationQueryParametersError "Query-string authentication version 4 requires the X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature, X-Amz-Date, X-Amz-SignedHeaders, and X-Amz-Expires parameters.", and a negative value "X-Amz-Expires must be non-negative". CompleteMultipartUpload checks x-amz-mp-object-size: a size other than the parts' total answers 400 InvalidRequest "The provided 'x-amz-mp-object-size' header value 11 does not match what was computed: 10", a non-numeric one "Value for x-amz-mp-object-size header is invalid: 'abc'". Reported by @adzcodemi.
  • CloudFront — origins that name a load balancer or a Function URL in this MiniStack — a custom origin at a load balancer's DNSName or a Function URL's <url-id>.lambda-url.<region>.on.aws answered 502, as for any AWS hostname. A load balancer is now reached on its HTTP listener at the origin's HTTPPort and a Function URL over HTTPS, with the origin's custom headers, so a target that checks a secret header works; OriginReadTimeout applies (504). A Function URL refuses a forwarded viewer Host with 403 {"Message":null} and an unsigned AWS_IAM URL answers 403 {"Message":"Forbidden"}, as on AWS. Reported by @kinoh and @smiley-uriux.
  • CloudFront — functions — a viewer-request function that returned the request it was given rebuilt the query string, so ?flag reached the origin as ?flag=; it is now rebuilt only when the returned querystring differs. CreateFunction keeps its Tags (deleted with the function), answers invalid base64 code with MalformedInput "Invalid Base64 encoding", and refuses a missing code, configuration, runtime or name and invalid tags in one MalformedXML before the name lookup, then InvalidTagging for repeated, aws: or more than 50 keys. Contributed by @jeffreyheller and @kharabasz.
  • ALB — X-Forwarded-* and X-Amzn-Trace-Id as the load balancer sets them — targets got an incoming X-Forwarded-For unchanged and a client-sent X-Forwarded-Proto/X-Forwarded-Port, and Lambda targets none of them; all targets now get X-Forwarded-For with the client address appended (kept or dropped under routing.http.xff_header_processing.mode preserve/remove), X-Forwarded-Proto and X-Forwarded-Port from the listener, and an X-Amzn-Trace-Id with a new Root, or a Self added to or updated in the one sent. Reported by @kinoh.
  • Lambda — Function URLs as AWS serves them — URL ids are 32 lowercase letters and digits; the event's headers carry the URL's own host, x-forwarded-for (the first address sent, or the caller), x-forwarded-port 443, x-forwarded-proto https, x-amzn-trace-id and the TLS fields; requestContext.accountId is anonymous for an AuthType NONE URL; and responses carry x-amzn-RequestId and X-Amzn-Trace-Id, with x-amzn-ErrorType AccessDeniedException on a 403. Reported by @smiley-uriux.
  • Lambda — versions, layers and containers — Publish: true on create or code update overwrote $LATEST's Version, so $LATEST disappeared from ListVersionsByFunction; it now stays $LATEST. A layer MiniStack doesn't hold from another account, such as Datadog's, resolves as an empty layer instead of AccessDeniedException. Function containers no longer publish port 8080 on every host address: none with DOCKER_NETWORK, 127.0.0.1 otherwise. Contributed by @skialpine and @kharabasz. Reported by @cupidchan.
  • API Gateway — HTTP API request ids and AWS_IAM headers — an HTTP API's responses carried x-amzn-requestid and x-amz-request-id; they now carry apigw-requestid, 16 base64 characters, as AWS does. Under AUTH=true a REST AWS_IAM method served a bearer token or a lower-case algorithm; it now answers 403 IncompleteSignatureException with API Gateway's message. Contributed by @jeffreyheller and @iot-rocket.
  • API Gateway v2 — WebSocket connections — DeleteConnection answered 204 but left the socket open; it now closes it, GetConnection and PostToConnection answer 410 GoneException, and $disconnect runs after the close. A route whose Lambda is a container image or another runtime now runs it, PostToConnection sends a text frame, and routes and stages keep RouteResponseSelectionExpression, ModelSelectionExpression, AccessLogSettings, ClientCertificateId and DeploymentId. Contributed by @toby6578. Reported by @cupidchan.
  • AppSync Events — AUTH=true checks the Event API's authorization — an HTTP publish, a WebSocket connection or a subscription was accepted with any API key or none unless APPSYNC_EVENTS_ENFORCE_AUTH was set; it now needs what the API or channel namespace accepts (an API key, a SigV4 signature, a Cognito or OIDC token), and a refused publish answers 401 UnauthorizedException "You are not authorized to make this call.". Contributed by @iot-rocket.
  • Cognito — signing keys, managed login and federation — every pool signed with one shared key (kid ministack-key-1); each pool now has its own access and ID token keys at its JWKS URI. Managed login refuses PKCE plain, an unregistered redirect_uri and an unknown grant_type (400 unsupported_grant_type); a federated user joins <user pool id>_<provider name> and carries identities; an OIDC provider with only oidc_issuer takes its endpoints from the issuer's /.well-known/openid-configuration. Contributed by @kinoh. Reported by @cupidchan.
  • Cognito — client_credentials — /oauth2/token issued a token to a client without client_credentials in AllowedOAuthFlows; it now answers invalid_grant (invalid_scope first for an unknown scope), and the pre token generation trigger runs for this grant only when LambdaVersion is V3_0. Contributed by @iot-rocket.
  • IoT — MQTT delivery as AWS IoT does — an unacknowledged QoS 1 message was resent every 10 seconds with DUP set; it is now resent after 30 seconds with DUP 0, on the open connection and after a persistent session resumes, and a No Local subscription receives the client's own messages, as AWS IoT Core ignores that option. Contributed by @iot-rocket.
  • IoT — thing-group membership by ARN — AddThingToThingGroup and RemoveThingFromThingGroup ignored thingGroupArn and thingArn and were authorized on the request path; they now act on the group and thing the ARNs name, refuse a mismatched or foreign ARN with 400 InvalidRequestException, and under AUTH=true are checked on the group and then the thing. Contributed by @iot-rocket.
  • CloudWatch — alarm tags and DatapointsToAlarm — PutMetricAlarm and PutCompositeAlarm dropped Tags on create; they are now stored over CBOR, JSON 1.0 and Query and ignored on update, as on AWS, with AWS's ValidationError, MalformedInput and aws:-key refusals. An alarm without DatapointsToAlarm no longer reports it as EvaluationPeriods. Contributed by @kharabasz.
  • DynamoDB — PartiQL statements are parsed as DynamoDB parses them — a parser replaces the regular-expression reader and answers malformed statements with AWS's messages (Statement wasn't well formed, can't be processed: Unexpected term, Missing right-hand side expression of infix operator, Aliasing is not supported, positions as at <line>:<column>:<length>); it skips comments, reads every number literal form, and supports ORDER BY, attribute_exists, attribute_not_exists, size, attribute_type, IS, set_add, set_delete, FROM ... WHERE ... SET and EXISTS(SELECT ...) in ExecuteTransaction. Reported by @hicksy (paritysuite.org).
  • DynamoDB — validation order, numbers and limits — transactions and batches report their member errors together before any table lookup; numbers are range-checked with their full exponent (Number overflow) and duplicate set members reported in byte order; legacy Expected conditions are validated; UpdateItem's 400KB check charges the request clause by clause before the condition; SET l[n] past the end appends instead of padding with NULL. Reported by @hicksy (paritysuite.org).
  • ElastiCache — transit encryption, AUTH tokens and subnet groups — a group with TransitEncryptionEnabled and an AuthToken served plaintext without a password; it now serves TLS only, signed by the CA at /_ministack/elasticache/ca.pem, requires the token, and ModifyReplicationGroup applies ROTATE, SET and DELETE. CreateCacheSubnetGroup now keeps its subnets, VPC and tags, and answers InvalidSubnet, CacheSubnetGroupAlreadyExists and CacheSubnetGroupInUse. Reported by @aditya-drizz.
  • ECS — capacity provider strategies — a service or task with capacityProviderStrategy dropped it and reported launchType EC2; the strategy is now kept without a launchType, the cluster's default applies when neither is given, both together are refused with InvalidParameterException "Specifying both a launch type and capacity provider strategy is not supported. Remove one and try again.", and AWS::ECS::Service passes it through. Reported by @aditya-drizz.
  • RDS — MaxAllocatedStorage only with storage autoscaling — every DB instance reported MaxAllocatedStorage equal to its allocated storage; it is now present only when storage autoscaling was turned on. Reported by @aditya-drizz.
  • Reset — /_ministack/reset no longer removes another MiniStack's containers — the OpenSearch, OpenSearch Serverless, DSQL, ECS and EKS resets removed every container with the service's label on the Docker daemon; they now remove only this instance's. Contributed by @jeffreyheller.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.