Skip to content

Commit 55fa610

Browse files
authored
feat(misconf): add support for AWS::EC2::SecurityGroupIngress/Egress (#6755)
1 parent cd360dd commit 55fa610

File tree

2 files changed

+104
-32
lines changed

2 files changed

+104
-32
lines changed

pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,57 @@ Resources:
272272
},
273273
},
274274
},
275+
{
276+
name: "security group with ingress and egress rules",
277+
source: `AWSTemplateFormatVersion: 2010-09-09
278+
Resources:
279+
MySecurityGroup:
280+
Type: AWS::EC2::SecurityGroup
281+
Properties:
282+
GroupName: MySecurityGroup
283+
GroupDescription: MySecurityGroup
284+
InboundRule:
285+
Type: AWS::EC2::SecurityGroupIngress
286+
Properties:
287+
GroupId: !Ref MySecurityGroup
288+
Description: Inbound
289+
CidrIp: 0.0.0.0/0
290+
OutboundRule:
291+
Type: AWS::EC2::SecurityGroupEgress
292+
Properties:
293+
GroupId: !GetAtt MySecurityGroup.GroupId
294+
Description: Outbound
295+
CidrIp: 0.0.0.0/0
296+
RuleWithoutGroup:
297+
Type: AWS::EC2::SecurityGroupIngress
298+
Properties:
299+
CidrIpv6: ::/0
300+
Description: Inbound
301+
`,
302+
expected: ec2.EC2{
303+
SecurityGroups: []ec2.SecurityGroup{
304+
{
305+
Description: types.StringTest("MySecurityGroup"),
306+
IngressRules: []ec2.SecurityGroupRule{
307+
{
308+
Description: types.StringTest("Inbound"),
309+
CIDRs: []types.StringValue{
310+
types.StringTest("0.0.0.0/0"),
311+
},
312+
},
313+
},
314+
EgressRules: []ec2.SecurityGroupRule{
315+
{
316+
Description: types.StringTest("Outbound"),
317+
CIDRs: []types.StringValue{
318+
types.StringTest("0.0.0.0/0"),
319+
},
320+
},
321+
},
322+
},
323+
},
324+
},
325+
},
275326
}
276327

277328
for _, tt := range tests {
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package ec2
22

33
import (
4+
"golang.org/x/exp/maps"
5+
46
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/ec2"
57
"github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser"
68
"github.com/aquasecurity/trivy/pkg/iac/types"
79
)
810

9-
func getSecurityGroups(ctx parser.FileContext) (groups []ec2.SecurityGroup) {
11+
func getSecurityGroups(ctx parser.FileContext) []ec2.SecurityGroup {
12+
mGroups := make(map[string]ec2.SecurityGroup)
13+
1014
for _, r := range ctx.GetResourcesByType("AWS::EC2::SecurityGroup") {
1115
group := ec2.SecurityGroup{
1216
Metadata: r.Metadata(),
@@ -17,52 +21,69 @@ func getSecurityGroups(ctx parser.FileContext) (groups []ec2.SecurityGroup) {
1721
VPCID: r.GetStringProperty("VpcId"),
1822
}
1923

20-
groups = append(groups, group)
24+
mGroups[r.ID()] = group
25+
}
26+
27+
for _, r := range ctx.GetResourcesByType("AWS::EC2::SecurityGroupIngress") {
28+
groupID := r.GetProperty("GroupId").AsString()
29+
30+
if group, ok := mGroups[groupID]; ok {
31+
group.IngressRules = append(group.IngressRules, adaptRule(r))
32+
mGroups[groupID] = group
33+
}
2134
}
22-
return groups
35+
36+
for _, r := range ctx.GetResourcesByType("AWS::EC2::SecurityGroupEgress") {
37+
groupID := r.GetProperty("GroupId").AsString()
38+
39+
if group, ok := mGroups[groupID]; ok {
40+
group.EgressRules = append(group.EgressRules, adaptRule(r))
41+
mGroups[groupID] = group
42+
}
43+
}
44+
45+
if len(mGroups) > 0 {
46+
return maps.Values(mGroups)
47+
}
48+
return nil
2349
}
2450

2551
func getIngressRules(r *parser.Resource) (sgRules []ec2.SecurityGroupRule) {
2652
if ingressProp := r.GetProperty("SecurityGroupIngress"); ingressProp.IsList() {
2753
for _, ingress := range ingressProp.AsList() {
28-
rule := ec2.SecurityGroupRule{
29-
Metadata: ingress.Metadata(),
30-
Description: ingress.GetStringProperty("Description"),
31-
CIDRs: nil,
32-
}
33-
v4Cidr := ingress.GetProperty("CidrIp")
34-
if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() {
35-
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata()))
36-
}
37-
v6Cidr := ingress.GetProperty("CidrIpv6")
38-
if v6Cidr.IsString() && v6Cidr.AsStringValue().IsNotEmpty() {
39-
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata()))
40-
}
41-
42-
sgRules = append(sgRules, rule)
54+
sgRules = append(sgRules, adaptRule(ingress))
4355
}
4456
}
57+
4558
return sgRules
4659
}
4760

4861
func getEgressRules(r *parser.Resource) (sgRules []ec2.SecurityGroupRule) {
4962
if egressProp := r.GetProperty("SecurityGroupEgress"); egressProp.IsList() {
5063
for _, egress := range egressProp.AsList() {
51-
rule := ec2.SecurityGroupRule{
52-
Metadata: egress.Metadata(),
53-
Description: egress.GetStringProperty("Description"),
54-
}
55-
v4Cidr := egress.GetProperty("CidrIp")
56-
if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() {
57-
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata()))
58-
}
59-
v6Cidr := egress.GetProperty("CidrIpv6")
60-
if v6Cidr.IsString() && v6Cidr.AsStringValue().IsNotEmpty() {
61-
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata()))
62-
}
63-
64-
sgRules = append(sgRules, rule)
64+
sgRules = append(sgRules, adaptRule(egress))
6565
}
6666
}
6767
return sgRules
6868
}
69+
70+
func adaptRule(r interface {
71+
GetProperty(string) *parser.Property
72+
Metadata() types.Metadata
73+
GetStringProperty(string, ...string) types.StringValue
74+
}) ec2.SecurityGroupRule {
75+
rule := ec2.SecurityGroupRule{
76+
Metadata: r.Metadata(),
77+
Description: r.GetStringProperty("Description"),
78+
}
79+
v4Cidr := r.GetProperty("CidrIp")
80+
if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() {
81+
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata()))
82+
}
83+
v6Cidr := r.GetProperty("CidrIpv6")
84+
if v6Cidr.IsString() && v6Cidr.AsStringValue().IsNotEmpty() {
85+
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata()))
86+
}
87+
88+
return rule
89+
}

0 commit comments

Comments
 (0)