Files
Ben Duncan adb3d9876d fix: read a tagged bucket's tags through S3 instead of S3 Control (#1109)
The AWS provider reads a bucket's tags with `ListTagsForResource` on S3 Control when it knows the account ID. S3 Control puts the account in the hostname — `https://{account}.{endpoint}` — so against an IP-addressed endpoint the request fails a DNS lookup before a packet leaves, and no endpoint configuration can help. A tagged bucket therefore fails its first read after being created.

`skip_requesting_account_id` alone does not fix it: `aws-sdk-go-base` takes the account ID from the STS `GetCallerIdentity` credentials check before it consults that flag, so `skip_credentials_validation` is needed alongside it. With no account ID the provider falls back to `GetBucketTagging`, which predastore serves.

`s3-webapp` is the only workbook that creates a bucket, and it uses no `aws_caller_identity` and references no other security group, so a blank account ID costs it nothing.

The bucket also gets `force_destroy`, since the webapp uploads into it and a destroy of a used bucket fails `BucketNotEmpty` without it.

The e2e harness now asserts the bucket carries the tags Terraform set, which is what catches this regressing, and no longer aborts the remaining workbooks on a failure — `s3-webapp` failing says nothing about whether RDS works, and four nights of `rds-quickstart` coverage were lost that way. `STOP_ON_FAIL=1` restores the early abort.

Every workbook's provider versions are pinned, so a run reproduces rather than picking up whatever the registry published that morning.
2026-09-26 16:11:00 -05:00
..

title, seoTitle, description, category, tags, sections, resources
title seoTitle description category tags sections resources
ECS Quickstart Terraform ECS Quickstart on Spinifex — Spinifex Docs Stand up a full AWS-compatible ECS stack with Terraform: a VPC, IAM roles, a cluster, a task definition, container instances, and a load-balanced service. Terraform Workbooks
terraform
ecs
containers
alb
iam
vpc
workbook
overview
prerequisites
instructions
troubleshooting
title url
ECS Service Documentation /docs/ecs
title url
Terraform AWS Provider https://registry.terraform.io/providers/hashicorp/aws/latest
title url
Spinifex Repository https://github.com/mulgadc/spinifex
title url
OpenTofu https://opentofu.org/

Terraform: ECS Quickstart

The smallest end-to-end ECS example on Spinifex: a VPC, the IAM roles ECS needs, a cluster, a task definition, container instances booted from the ECS node image, and an awsvpc service load-balanced behind an Application Load Balancer.

Overview

This workbook is the Terraform-native equivalent of the console's Provision capacity action. It provisions a full ECS stack in one apply: a VPC with two public subnets, the ecsInstanceRole instance profile, a task IAM role, an ECS cluster, an awsvpc task definition running nginx, one or more container instances launched from the spinifex-ecs-node AMI, and an Application Load Balancer with a target group the service registers into.

Because a Spinifex container instance reaches the control plane over the gateway (TLS + SigV4) rather than a managed AWS endpoint, the workbook makes the two things the console injects for you explicit: a LAN-reachable gateway URL and the gateway CA, both baked into the instance's cloud-init user-data. The agent draws its credentials from IMDS via the ecsInstanceRole instance profile, so no static keys are written.

Prerequisites

  • Spinifex running, with the AWS CLI configured for the spinifex profile (see Installing Spinifex) and OpenTofu (or Terraform) installed.

  • The spinifex-ecs-node AMI imported — resolved here by the tag:spinifex:managed-by=ecs filter:

    aws ec2 describe-images \
      --filters 'Name=tag:spinifex:managed-by,Values=ecs' \
      --query 'Images[].[ImageId,Name]' --output text
    
  • A LAN-reachable gateway URL — the host's WAN/bridge IP, not 127.0.0.1 (a guest VM cannot reach the host loopback). For example https://192.168.1.33:9999.

  • The gateway CA PEM readable at gateway_ca_cert_path (default /etc/spinifex/ca.pem).

Instructions

1. Fetch the workbook

git clone --depth 1 --filter=blob:none --sparse https://github.com/mulgadc/spinifex.git spinifex-tf
cd spinifex-tf
git sparse-checkout set docs/terraform-workbooks
cd docs/terraform-workbooks/ecs-quickstart

2. Apply

export AWS_PROFILE=spinifex

tofu init
tofu apply -var 'gateway_url=https://<host-lan-ip>:9999'

ecsInstanceRole is account-global. If you have already used the console's provision-capacity action it exists already, so skip re-creating it:

tofu apply \
  -var 'gateway_url=https://<host-lan-ip>:9999' \
  -var 'create_instance_role=false'

3. Verify

Container instances take ~30-60s to boot and register:

aws ecs list-container-instances --cluster ecs-quickstart
aws ecs describe-services --cluster ecs-quickstart --services ecs-quickstart-web \
  --query 'services[0].[runningCount,desiredCount]'

The ALB DNS name ends in .elb.spinifex.local and does not resolve from your host. Fetch its public IP and curl it:

aws elbv2 describe-load-balancers --names ecs-quickstart-alb \
  --query 'LoadBalancers[0].AvailabilityZones[].LoadBalancerAddresses[].IpAddress' \
  --output text
curl http://<alb_public_ip>

4. Variables

Variable Default Purpose
region ap-southeast-2 AWS region.
cluster_name ecs-quickstart Cluster + resource name prefix.
instance_type t3.small Container instance type.
container_count 1 Container instances + service desired count.
task_image docker.io/library/nginx:1.27-alpine Image the task runs.
spinifex_endpoint https://127.0.0.1:9999 Gateway as seen from the host running Terraform.
gateway_url (required) Gateway as seen from a guest VM (LAN-reachable).
gateway_ca_cert_path /etc/spinifex/ca.pem Host-readable gateway CA PEM.
create_instance_role true Create ecsInstanceRole; set false if it already exists.

5. Teardown

tofu destroy -var 'gateway_url=https://<host-lan-ip>:9999'

DeleteCluster cascades through the service, its tasks, and the container instance registrations, so the destroy round-trips cleanly.

Troubleshooting

Container instances never register. The agent registers over the gateway, not a managed endpoint. Confirm gateway_url is the host's LAN-reachable IP (not 127.0.0.1) and that gateway_ca_cert_path points at the real gateway CA. Because cloud-init write_files runs once per instance, a corrected user-data needs an instance replacement — tofu apply -replace='aws_instance.node[0]' — not an in-place modify.

apply fails resolving the AMI. The spinifex-ecs-node image is not imported, or its spinifex:managed-by=ecs tag is missing. Re-run the describe-images check in Prerequisites.

MissingParameter on the instance. The gateway's RunInstances requires a KeyName; the workbook generates a key pair for you, so this only appears if you have stripped that out.

Service runningCount stays below desiredCount. No instance has free capacity, or tasks cannot pull the image. Confirm at least one ACTIVE container instance and that the subnets have an Internet Gateway route.

create_instance_role conflict. If ecsInstanceRole already exists (from the console), pass -var 'create_instance_role=false' so Terraform does not try to recreate it.