Skip to content

Commit

Permalink
feat(misconf): add support for AWS::EC2::SecurityGroupIngress/Egress
Browse files Browse the repository at this point in the history
  • Loading branch information
nikpivkin committed May 23, 2024
1 parent bac4689 commit 8c81620
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 32 deletions.
51 changes: 51 additions & 0 deletions pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,57 @@ Resources:
},
},
},
{
name: "security group with ingress and egress rules",
source: `AWSTemplateFormatVersion: 2010-09-09
Resources:
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: MySecurityGroup
GroupDescription: MySecurityGroup
InboundRule:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref MySecurityGroup
Description: Inbound
CidrIp: 0.0.0.0/0
OutboundRule:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId: !GetAtt MySecurityGroup.GroupId
Description: Outbound
CidrIp: 0.0.0.0/0
RuleWithoutGroup:
Type: AWS::EC2::SecurityGroupIngress
Properties:
CidrIpv6: ::/0
Description: Inbound
`,
expected: ec2.EC2{
SecurityGroups: []ec2.SecurityGroup{
{
Description: types.StringTest("MySecurityGroup"),
IngressRules: []ec2.SecurityGroupRule{
{
Description: types.StringTest("Inbound"),
CIDRs: []types.StringValue{
types.StringTest("0.0.0.0/0"),
},
},
},
EgressRules: []ec2.SecurityGroupRule{
{
Description: types.StringTest("Outbound"),
CIDRs: []types.StringValue{
types.StringTest("0.0.0.0/0"),
},
},
},
},
},
},
},
}

for _, tt := range tests {
Expand Down
85 changes: 53 additions & 32 deletions pkg/iac/adapters/cloudformation/aws/ec2/security_group.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package ec2

import (
"golang.org/x/exp/maps"

"github.com/aquasecurity/trivy/pkg/iac/providers/aws/ec2"
"github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser"
"github.com/aquasecurity/trivy/pkg/iac/types"
)

func getSecurityGroups(ctx parser.FileContext) (groups []ec2.SecurityGroup) {
func getSecurityGroups(ctx parser.FileContext) []ec2.SecurityGroup {
mGroups := make(map[string]ec2.SecurityGroup)

for _, r := range ctx.GetResourcesByType("AWS::EC2::SecurityGroup") {
group := ec2.SecurityGroup{
Metadata: r.Metadata(),
Expand All @@ -17,52 +21,69 @@ func getSecurityGroups(ctx parser.FileContext) (groups []ec2.SecurityGroup) {
VPCID: r.GetStringProperty("VpcId"),
}

groups = append(groups, group)
mGroups[r.ID()] = group
}

for _, r := range ctx.GetResourcesByType("AWS::EC2::SecurityGroupIngress") {
groupID := r.GetProperty("GroupId").AsString()

if group, ok := mGroups[groupID]; ok {
group.IngressRules = append(group.IngressRules, adaptRule(r))
mGroups[groupID] = group
}
}
return groups

for _, r := range ctx.GetResourcesByType("AWS::EC2::SecurityGroupEgress") {
groupID := r.GetProperty("GroupId").AsString()

if group, ok := mGroups[groupID]; ok {
group.EgressRules = append(group.EgressRules, adaptRule(r))
mGroups[groupID] = group
}
}

if len(mGroups) > 0 {
return maps.Values(mGroups)
}
return nil
}

func getIngressRules(r *parser.Resource) (sgRules []ec2.SecurityGroupRule) {
if ingressProp := r.GetProperty("SecurityGroupIngress"); ingressProp.IsList() {
for _, ingress := range ingressProp.AsList() {
rule := ec2.SecurityGroupRule{
Metadata: ingress.Metadata(),
Description: ingress.GetStringProperty("Description"),
CIDRs: nil,
}
v4Cidr := ingress.GetProperty("CidrIp")
if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() {
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata()))
}
v6Cidr := ingress.GetProperty("CidrIpv6")
if v6Cidr.IsString() && v6Cidr.AsStringValue().IsNotEmpty() {
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata()))
}

sgRules = append(sgRules, rule)
sgRules = append(sgRules, adaptRule(ingress))
}
}

return sgRules
}

func getEgressRules(r *parser.Resource) (sgRules []ec2.SecurityGroupRule) {
if egressProp := r.GetProperty("SecurityGroupEgress"); egressProp.IsList() {
for _, egress := range egressProp.AsList() {
rule := ec2.SecurityGroupRule{
Metadata: egress.Metadata(),
Description: egress.GetStringProperty("Description"),
}
v4Cidr := egress.GetProperty("CidrIp")
if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() {
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata()))
}
v6Cidr := egress.GetProperty("CidrIpv6")
if v6Cidr.IsString() && v6Cidr.AsStringValue().IsNotEmpty() {
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata()))
}

sgRules = append(sgRules, rule)
sgRules = append(sgRules, adaptRule(egress))
}
}
return sgRules
}

func adaptRule(r interface {
GetProperty(string) *parser.Property
Metadata() types.Metadata
GetStringProperty(string, ...string) types.StringValue
}) ec2.SecurityGroupRule {
rule := ec2.SecurityGroupRule{
Metadata: r.Metadata(),
Description: r.GetStringProperty("Description"),
}
v4Cidr := r.GetProperty("CidrIp")
if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() {
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata()))
}
v6Cidr := r.GetProperty("CidrIpv6")
if v6Cidr.IsString() && v6Cidr.AsStringValue().IsNotEmpty() {
rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata()))
}

return rule
}

0 comments on commit 8c81620

Please sign in to comment.