feat(aws): expand resource surface area + add VpcOrigin, ListenerRule, TrustStore, HostedZone, HealthCheck#631
Conversation
…, TrustStore, HostedZone, HealthCheck
Many AWS resources were narrow/opinionated and could not express the full
config AWS supports. Expand them to the full surface and add the missing
lower-level resources.
New resources:
- CloudFront.VpcOrigin — front a private ALB/NLB/EC2 without public exposure
- ELBv2.ListenerRule — ALB path/host/header/query/method/source-IP routing
- ELBv2.TrustStore — CA bundle for mTLS verify mode
- Route53.HostedZone — Records no longer need a hand-supplied zone id
- Route53.HealthCheck — health-check source for failover routing
Expanded:
- S3.Bucket — versioning, encryption/SSE-KMS, public-access-block, CORS,
lifecycle, ownership/ACL, logging, acceleration, request-payer,
website, replication, intelligent-tiering, object-lock, policy
- SQS.Queue — redrive/DLQ, redrive-allow, KMS/SSE, policy, full FIFO surface
- Route53.Record — weighted/latency/failover/geolocation/multivalue/alias routing
- ELBv2.Listener — full action union (redirect, fixed-response, weighted forward,
OIDC/Cognito auth), mTLS, ALPN, SSL policy, SNI certs;
LoadBalancer + TargetGroup gaps filled
- ECS.Task/Service — multi-container task definitions; de-opinionated Service
(optional ALB, capacity providers, deployment circuit
breaker, placement, exec) with corrected replace-vs-in-place
- RDS.DBInstance/DBCluster (+ Aurora) — storage/IOPS, engine version, multi-AZ,
performance insights, enhanced monitoring, backup/maintenance
windows, parameter/option groups, encryption/KMS, IAM auth,
log exports, serverless-v2 scaling; diff replacement-set fixes
Requires alchemy-run/distilled#351 (route-53 list-response schema fix); the
submodule pointer is bumped to that commit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Install the packages built from this commit: alchemy bun add alchemy@https://pkg.ing/alchemy/c6d67f0@alchemy.run/better-auth bun add @alchemy.run/better-auth@https://pkg.ing/@alchemy.run/better-auth/c6d67f0@alchemy.run/pr-package bun add @alchemy.run/pr-package@https://pkg.ing/@alchemy.run/pr-package/c6d67f0 |
- ELBv2 TrustStore: regenerate the checked-in CA fixture as X.509 v3 with CA:TRUE (v1 certs are rejected with "certificate version is not supported"); the full mTLS lifecycle now passes. - S3 replication: provision the IAM replication role + versioned destination bucket in-test so it is self-contained (drop the S3_TEST_REPLICATION gate and the S3_REPLICATION_ROLE_ARN env dependency). - RDS DBInstance/DBCluster: the testing account has no default VPC/subnets, so provision an EC2.Network (VPC + subnets across 2 AZs) + DBSubnetGroup and pass dbSubnetGroupName. - CloudFront VpcOrigin: use EC2.Network (attaches the IGW CloudFront requires), deploy networking before the origin, and raise the test timeout to 30m (CloudFront VPC-origin global propagation is slow). Bumps the distilled submodule to include the CloudFront VpcOriginList list-response schema fix (alchemy-run/distilled#351). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DBInstance/DBCluster delete returned as soon as deletion was *initiated*. RDS deletion is async, so a dependent (DBSubnetGroup, VPC) was torn down next while the DB was still `deleting`, and AWS rejected it with `InvalidDBSubnetGroupStateFault: ... still using it`. Poll describeDB* after delete until NotFound (bounded ~10 min) so teardown ordering is correct. Tests: the RDS lifecycle tests now let the engine generate a unique DBSubnetGroup name (a leftover group from an interrupted run otherwise forces a cross-VPC ModifyDBSubnetGroup). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| * proxies (Envoy/App Mesh), metric agents (otel/cloudwatch), or any | ||
| * companion process that shares the task's network namespace. | ||
| */ | ||
| sidecars?: ecs.ContainerDefinition[]; |
There was a problem hiding this comment.
nice work on this. one thing on the Task container shape, feel free to ignore if you've already thought about it.
the main/container/sidecars setup feels a bit different from how task defs normally work everywhere else (aws api, terraform, cfn, cdk all just take a flat list of containers). ecs doesn't really have a "primary" container either, it's just the essential flag plus the service picking one by name, so the primary vs sidecar thing is kind of us inventing it.
wonder if it'd be cleaner to keep it as a flat array and have the bundling just be an image source, something like:
containers: [
{ name: "app", image: Bundle({ main: import.meta.filename }), essential: true },
{ name: "otel", image: "public.ecr.aws/.../otel:latest" },
]then a prebuilt image task is just image: "..." with no main needed. There might be better DX then this just what came to mind. But anyway just a thought, not a blocker
CloudFront VPC-origin deployment is slow (global propagation) and routinely exceeds 10 min. The reconcile's wait bound was 600s (60 * 10s), so a real deploy would fail spuriously with the origin still `Deploying`. Raise to ~20 min (120 * 10s). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…no orphan delete used the stale `output.etag` and could not remove an origin stuck in `Deploying` (e.g. after an interrupted create) — CloudFront then left the origin and its managed ENIs behind, which blocked the fronted ALB/VPC from being torn down. Now: observe current state, wait for `Deployed` so it is deletable, delete with the current ETag, then block until the record is gone so dependents can be reclaimed. Returns early if already gone (idempotent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…get to 45m The full VPC-origin lifecycle (create -> Deployed -> delete -> gone) runs ~35-40 min because CloudFront VPC-origin propagation is very slow. Keep it gated behind CLOUDFRONT_TEST_VPC_ORIGIN with a 45-min budget; the probe + list cover the wiring + typed-error surface in CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ions ENIs from a just-deleted ALB or CloudFront VPC origin can take several minutes to detach after the owning resource is gone. The subnet delete retried DependencyViolation for only ~2 min (exponential x 10), so a VPC-origin/ALB teardown could fail and orphan the subnet/VPC. Cap the backoff at 30s and extend the budget to ~12 min. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
deleteBucketLifecycle is eventually consistent — the rule can linger on reads for a few seconds, so the immediate post-delete assertion flaked. Retry until the config clears (mirrors the syncBucketCors path, which happened not to flake). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lizers The ECS Task/Service tests register task definitions (and, for the manual-LB service test, create an ALB / target group / listener) out of band. The trailing deregister/delete ran only on success, so a failed or interrupted run orphaned them (ACTIVE task-def revisions, a stray internal ALB). Register them as Effect.addFinalizer cleanups so they are reclaimed on scope close regardless of outcome (LIFO: listener -> target group -> load balancer). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Many AWS resources were narrow / opinionated and couldn't express the full config AWS supports. This expands them to the full surface area and adds the missing lower-level resources. All non-gated tests pass and
tsgo -bis clean.Depends on alchemy-run/distilled#351 (Route53 list-response schema fix); the submodule pointer is bumped to that commit.
New resources
CloudFront.VpcOrigin— front a private ALB/NLB/EC2 without exposing it publicly.ELBv2.ListenerRule— ALB path/host/header/query/method/source-IP routing.ELBv2.TrustStore— CA bundle for mTLS verify mode.Route53.HostedZone+Route53.HealthCheck— Records no longer need a hand-supplied zone id, and failover routing gets a health-check source.Expanded resources
S3.Bucket— versioning, encryption, public-access-block, CORS, lifecycle, ownership/ACL, logging, acceleration, request-payer, website, replication, intelligent-tiering, object-lock, explicit policy.SQS.Queue— redrive/DLQ, redrive-allow, KMS/SSE, policy, full FIFO surface.Route53.Record— weighted / latency / failover / geolocation / multivalue / alias routing.ELBv2.Listener— full action union (redirect, fixed-response, weighted forward, OIDC/Cognito auth), mTLS, ALPN, SSL policy, SNI certs.LoadBalancer+TargetGroupgaps filled.ECS.Task/ECS.Service— multi-container task definitions (sidecars + task-level config); de-opinionated Service: ALB is optional, plus capacity-provider strategy, deployment circuit breaker, placement, exec, with corrected replace-vs-in-place diff.RDS.DBInstance/RDS.DBCluster(passed throughAurora) — storage/IOPS, engine version, multi-AZ, performance insights, enhanced monitoring, backup/maintenance windows, parameter/option groups, encryption/KMS, IAM auth, log exports, serverless-v2 scaling. Diff replacement-sets corrected so in-place-updatable knobs no longer force replacement.Testing
Non-gated live tests pass for every resource and
tsgo -bis clean. Lifecycles that need slow provisioning or external prerequisites are implemented andskipIf-gated behind env vars (RDS_TEST_LIFECYCLE,CLOUDFRONT_TEST_VPC_ORIGIN,ELBV2_TEST_MTLS,S3_TEST_REPLICATION); making those green is in progress, which is why this is a draft.