Skip to content

Commit 7e3b96b

Browse files
committed
fix(query): handle list-form access_logs in ELBv2 LB Access Log Disabled
The Terraform query aws/elb_v2_lb_access_log_disabled assumed access_logs was always parsed as a single object and read resource.access_logs.enabled directly. When access_logs is written as a list (access_logs = [{ ... enabled = true }]), the parser stores it as an array, so that path is undefined and the load balancer is flagged even though access logging is enabled. Normalize access_logs to a list of blocks (mirroring the object-or-array handling used by other queries such as efs_volume_with_disabled_transit_encryption) so the enabled check works for both the single-block and list shapes. The true-positive cases (access_logs absent, enabled missing, or enabled = false) are still reported, including when access_logs is a list. Adds negative3.tf (list form with enabled = true, must not flag) and positive7.tf (list form with enabled = false, must still flag). Closes #8036 Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
1 parent 4d63f51 commit 7e3b96b

4 files changed

Lines changed: 77 additions & 7 deletions

File tree

assets/queries/terraform/aws/elb_v2_lb_access_log_disabled/query.rego

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,43 +25,71 @@ CxPolicy[result] {
2525
load_balancer := get_load_balancer(input.document[i].resource)
2626
resource := input.document[i].resource[load_balancer][name]
2727

28-
not common_lib.valid_key(resource.access_logs, "enabled")
28+
log_info := get_access_logs(resource)[_]
29+
not common_lib.valid_key(log_info.block, "enabled")
2930

3031
result := {
3132
"documentId": input.document[i].id,
3233
"resourceType": load_balancer,
3334
"resourceName": tf_lib.get_specific_resource_name(resource, load_balancer, name),
34-
"searchKey": sprintf("%s[%s].access_logs", [load_balancer,name]),
35+
"searchKey": get_search_key(load_balancer, name, log_info.index, "access_logs"),
3536
"issueType": "MissingAttribute",
3637
"keyExpectedValue": "'access_logs.enabled' should be defined and set to true",
3738
"keyActualValue": "'access_logs.enabled' is undefined",
38-
"searchLine": common_lib.build_search_line(["resource", load_balancer, name, "access_logs"], []),
39+
"searchLine": get_search_line(load_balancer, name, log_info.index, ["access_logs"]),
3940
}
4041
}
4142

4243
CxPolicy[result] {
4344
load_balancer := get_load_balancer(input.document[i].resource)
4445
resource := input.document[i].resource[load_balancer][name]
4546

46-
resource.access_logs.enabled != true
47+
log_info := get_access_logs(resource)[_]
48+
log_info.block.enabled != true
4749

4850
result := {
4951
"documentId": input.document[i].id,
5052
"resourceType": load_balancer,
5153
"resourceName": tf_lib.get_specific_resource_name(resource, load_balancer, name),
52-
"searchKey": sprintf("%s[%s].access_logs.enabled", [load_balancer,name]),
54+
"searchKey": get_search_key(load_balancer, name, log_info.index, "access_logs.enabled"),
5355
"issueType": "IncorrectValue",
5456
"keyExpectedValue": "'access_logs.enabled' should be defined and set to true",
5557
"keyActualValue": "'access_logs.enabled' is not set to true",
56-
"searchLine": common_lib.build_search_line(["resource", load_balancer, name, "access_logs", "enabled"], []),
58+
"searchLine": get_search_line(load_balancer, name, log_info.index, ["access_logs", "enabled"]),
5759
}
5860
}
5961

62+
# access_logs can be parsed as a single block (object) or, when written as a
63+
# list (access_logs = [{ ... }]) or as multiple blocks, as an array. Normalize
64+
# both shapes to a list of {block, index} so the checks above behave the same.
65+
get_access_logs(resource) = logs {
66+
is_array(resource.access_logs)
67+
logs := [{"block": block, "index": idx} | block := resource.access_logs[idx]]
68+
} else = logs {
69+
logs := [{"block": resource.access_logs, "index": null}]
70+
}
71+
72+
get_search_key(lb, name, index, suffix) = searchKey {
73+
index != null
74+
searchKey := sprintf("%s[%s].access_logs[%d].%s", [lb, name, index, trim_prefix(suffix, "access_logs.")])
75+
} else = searchKey {
76+
searchKey := sprintf("%s[%s].%s", [lb, name, suffix])
77+
}
78+
79+
get_search_line(lb, name, index, path_elements) = searchLine {
80+
index != null
81+
full_path := array.concat(["resource", lb, name], path_elements)
82+
path_with_index := array.concat(array.slice(full_path, 0, 4), array.concat([index], array.slice(full_path, 4, count(full_path))))
83+
searchLine := common_lib.build_search_line(path_with_index, [])
84+
} else = searchLine {
85+
full_path := array.concat(["resource", lb, name], path_elements)
86+
searchLine := common_lib.build_search_line(full_path, [])
87+
}
88+
6089
get_load_balancer(resource) = lb {
6190
common_lib.valid_key(resource,"aws_lb")
6291
lb = "aws_lb"
6392
} else = lb {
6493
common_lib.valid_key(resource,"aws_alb")
6594
lb = "aws_alb"
6695
}
67-
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# access_logs written as a list of objects (= [{ ... }]) instead of a block
2+
resource "aws_lb" "test" {
3+
name = "test-lb-tf"
4+
internal = false
5+
load_balancer_type = "network"
6+
7+
enable_deletion_protection = true
8+
9+
access_logs = [{
10+
bucket = aws_s3_bucket.lb_logs.id
11+
prefix = "test-lb"
12+
enabled = true
13+
}]
14+
15+
tags = {
16+
Environment = "production"
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# access_logs as a list with logging explicitly disabled - still a finding
2+
resource "aws_lb" "test" {
3+
name = "test-lb-tf"
4+
internal = false
5+
load_balancer_type = "network"
6+
7+
enable_deletion_protection = true
8+
9+
access_logs = [{
10+
bucket = aws_s3_bucket.lb_logs.id
11+
prefix = "test-lb"
12+
enabled = false
13+
}]
14+
15+
tags = {
16+
Environment = "production"
17+
}
18+
}

assets/queries/terraform/aws/elb_v2_lb_access_log_disabled/test/positive_expected_result.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,11 @@
3434
"severity": "MEDIUM",
3535
"line": 2,
3636
"fileName": "positive6.tf"
37+
},
38+
{
39+
"queryName": "ELBv2 LB Access Log Disabled",
40+
"severity": "MEDIUM",
41+
"line": 12,
42+
"fileName": "positive7.tf"
3743
}
3844
]

0 commit comments

Comments
 (0)