java-topology/defects/terraform/patch/tf-aws-0001-cloudformation-stackset-orgid-scan.md

96 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000307
# tf-aws-0001 — Terraform AWS Provider: CloudFormation StackSet org-ID filter O(S×O)
**Severity:** MEDIUM
**CWE:** CWE-407 (Algorithmic Complexity — Linear Membership Test in Loop)
**File:** `internal/service/cloudformation/stack_set_instance.go`
**Function:** `findStackInstanceSummariesByFourPartKey`
## Defect
```go
// stack_set_instance.go:501-519
pages := cloudformation.NewListStackInstancesPaginator(conn, input)
for pages.HasMorePages() { // O(P) pages
page, err := pages.NextPage(ctx)
...
for _, v := range page.Summaries { // O(S/P) summaries per page
if slices.Contains(orgIDs, aws.ToString(v.OrganizationalUnitId)) { // O(O)
output = append(output, v)
}
}
}
```
`slices.Contains` performs a linear scan of `orgIDs` (a `[]string`) for every stack instance
summary returned by the AWS API.
In large AWS Organizations deployments:
- `orgIDs` can contain hundreds of OU IDs (user-supplied filter)
- Total stack instance summaries across all pages can be thousands
Total complexity: **O(S × O)** where S = total summaries, O = len(orgIDs).
At S=5000 stack instances, O=200 OU IDs → 1,000,000 string comparisons per Terraform plan/apply.
This is called during every `terraform plan` and `terraform apply` that touches
`aws_cloudformation_stack_set_instance` with an `deployment_targets` block.
## Fix
Pre-build a `map[string]bool` from `orgIDs` before the pagination loop:
```go
orgIDSet := make(map[string]bool, len(orgIDs))
for _, id := range orgIDs {
orgIDSet[id] = true
}
pages := cloudformation.NewListStackInstancesPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
...
for _, v := range page.Summaries {
if orgIDSet[aws.ToString(v.OrganizationalUnitId)] { // O(1)
output = append(output, v)
}
}
}
```
## Patch
```diff
--- a/internal/service/cloudformation/stack_set_instance.go
+++ b/internal/service/cloudformation/stack_set_instance.go
@@ -497,6 +497,12 @@ func findStackInstanceSummariesByFourPartKey(...) ([]awstypes.StackInstanceSumma
var output []awstypes.StackInstanceSummary
+ // CWE-407: pre-build an O(1) lookup set for orgIDs to avoid O(S×O)
+ // linear scan inside the pagination loop.
+ orgIDSet := make(map[string]bool, len(orgIDs))
+ for _, id := range orgIDs {
+ orgIDSet[id] = true
+ }
+
pages := cloudformation.NewListStackInstancesPaginator(conn, input)
for pages.HasMorePages() {
@@ -515,7 +521,7 @@ func findStackInstanceSummariesByFourPartKey(...) ([]awstypes.StackInstanceSumma
for _, v := range page.Summaries {
- if slices.Contains(orgIDs, aws.ToString(v.OrganizationalUnitId)) {
+ if orgIDSet[aws.ToString(v.OrganizationalUnitId)] {
output = append(output, v)
}
}
```
## Complexity
| S (summaries) | O (org IDs) | Before (comparisons) | After |
|---------------|-------------|---------------------|-------|
| 500 | 50 | 25,000 | 500 |
| 5,000 | 200 | 1,000,000 | 5,000 |
| 50,000 | 500 | 25,000,000 | 50,000|
## Reproduction
See `defects/terraform/unit/TfAwsCloudFormationAlgorithm.java` — ratio ≥ 5x at S=2000, O=200 (46x at S=7000, O=500).