Terraform part: variable "tags" { type = map(string) description = "A map of tag key-value pairs to filter S3 buckets." default = { Application = "3D Print Social" Environment = "audev" } } data "external" "s3_buckets" { program = ["python3", "${path.module}/query_s3_buckets.py"] query = { tags = jsonencode(var.tags) } } output "s3_buckets" { value = data.external.s3_buckets.result } Create query_s3_buckets.py in the root of the Terraform module, e.g. . ├── main.tf └── query_s3_buckets.py With this content: import json import os import sys def bucket_tagset_to_dict(tagset: list[dict]) -> dict: return {tag["Key"]: tag["Value"] for tag in tagset} def get_bucket_tags(bucket_name: str) -> dict: tags_response = os.popen( f"aws s3api get-bucket-tagging --bucket {bucket_name}", # noqa: S607, S605 ).read() return ( {tag["Key"]: tag["Value"] for tag in json.loads(tags_response)["TagSet"]} if tags_response else {} ) def get_buckets() -> list[str]: return json.loads( os.popen( "aws s3api list-buckets --query 'Buckets[*].Name' --output json", # noqa: S607, S605 ).read(), ) def filter_buckets_by_tags(tags: dict[str, str]) -> list[str]: buckets = get_buckets() return [ bucket for bucket in buckets if all(tag in get_bucket_tags(bucket).items() for tag in tags.items()) ] if __name__ == "__main__": input = sys.stdin.read() input_json = json.loads(input) tags = json.loads(input_json.get("tags", "{}")) buckets = filter_buckets_by_tags(tags) # Terraform external data resource expects a result printed to stdout print(json.dumps({"buckets": json.dumps(buckets)})) Output example: Changes to Outputs: + one_s3_bucket = "3dprint-audev-contact-attachments-20240531095242070500000001" + s3_buckets = { + buckets = jsonencode( [ + "3dprint-audev-contact-attachments-20240531095242070500000001", + "3dprint-audev-lambda-builds", + "3dprint-audev-orders-files-20240214174921309700000001", + "3dprint-audev-website", ] ) }