2020-12-09 15:31:34 +00:00
|
|
|
package aws
|
|
|
|
|
|
|
|
import (
|
2021-01-20 13:01:57 +00:00
|
|
|
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
|
|
|
|
|
2020-12-09 15:31:34 +00:00
|
|
|
"github.com/cloudskiff/driftctl/pkg/resource"
|
|
|
|
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
|
2021-05-21 14:09:45 +00:00
|
|
|
|
2020-12-09 15:31:34 +00:00
|
|
|
"github.com/cloudskiff/driftctl/pkg/terraform"
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
|
|
|
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
|
|
|
"github.com/hashicorp/terraform/flatmap"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
sgRuleTypeIngress = "ingress"
|
|
|
|
sgRuleTypeEgress = "egress"
|
|
|
|
)
|
|
|
|
|
|
|
|
type VPCSecurityGroupRuleSupplier struct {
|
|
|
|
reader terraform.ResourceReader
|
2021-05-21 14:09:45 +00:00
|
|
|
deserializer *resource.Deserializer
|
2020-12-09 15:31:34 +00:00
|
|
|
client ec2iface.EC2API
|
|
|
|
runner *terraform.ParallelResourceReader
|
|
|
|
}
|
|
|
|
|
2021-05-21 14:09:45 +00:00
|
|
|
type securityGroupRule struct {
|
|
|
|
Type string
|
|
|
|
SecurityGroupId string
|
|
|
|
Protocol string
|
|
|
|
FromPort int
|
|
|
|
ToPort int
|
|
|
|
Self bool
|
|
|
|
SourceSecurityGroupId string
|
|
|
|
CidrBlocks []string
|
|
|
|
Ipv6CidrBlocks []string
|
|
|
|
PrefixListIds []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *securityGroupRule) getId() string {
|
|
|
|
attrs := resource.Attributes{
|
|
|
|
"type": s.Type,
|
|
|
|
"security_group_id": s.SecurityGroupId,
|
|
|
|
"protocol": s.Protocol,
|
|
|
|
"from_port": float64(s.FromPort),
|
|
|
|
"to_port": float64(s.ToPort),
|
|
|
|
"self": s.Self,
|
|
|
|
"source_security_group_id": s.SourceSecurityGroupId,
|
|
|
|
"cidr_blocks": toInterfaceSlice(s.CidrBlocks),
|
|
|
|
"ipv6_cidr_blocks": toInterfaceSlice(s.Ipv6CidrBlocks),
|
|
|
|
"prefix_list_ids": toInterfaceSlice(s.PrefixListIds),
|
|
|
|
}
|
|
|
|
|
|
|
|
return resourceaws.CreateSecurityGroupRuleIdHash(&attrs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toInterfaceSlice(val []string) []interface{} {
|
|
|
|
var res []interface{}
|
|
|
|
for _, v := range val {
|
|
|
|
res = append(res, v)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewVPCSecurityGroupRuleSupplier(provider *AWSTerraformProvider, deserializer *resource.Deserializer) *VPCSecurityGroupRuleSupplier {
|
2021-01-20 13:01:57 +00:00
|
|
|
return &VPCSecurityGroupRuleSupplier{
|
2021-01-22 17:06:17 +00:00
|
|
|
provider,
|
2021-05-21 14:09:45 +00:00
|
|
|
deserializer,
|
2021-01-22 17:06:17 +00:00
|
|
|
ec2.New(provider.session),
|
|
|
|
terraform.NewParallelResourceReader(provider.Runner().SubRunner()),
|
2021-01-20 13:01:57 +00:00
|
|
|
}
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-17 15:54:53 +00:00
|
|
|
func (s *VPCSecurityGroupRuleSupplier) Resources() ([]resource.Resource, error) {
|
2021-01-15 13:15:31 +00:00
|
|
|
securityGroups, defaultSecurityGroups, err := listSecurityGroups(s.client)
|
2020-12-09 15:31:34 +00:00
|
|
|
if err != nil {
|
2021-01-20 13:01:57 +00:00
|
|
|
return nil, remoteerror.NewResourceEnumerationError(err, resourceaws.AwsSecurityGroupRuleResourceType)
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
2021-01-15 13:15:31 +00:00
|
|
|
secGroups := make([]*ec2.SecurityGroup, 0, len(securityGroups)+len(defaultSecurityGroups))
|
|
|
|
secGroups = append(secGroups, securityGroups...)
|
|
|
|
secGroups = append(secGroups, defaultSecurityGroups...)
|
|
|
|
securityGroupsRules := s.listSecurityGroupsRules(secGroups)
|
2020-12-09 15:31:34 +00:00
|
|
|
results := make([]cty.Value, 0)
|
|
|
|
if len(securityGroupsRules) > 0 {
|
|
|
|
for _, securityGroupsRule := range securityGroupsRules {
|
|
|
|
rule := securityGroupsRule
|
|
|
|
s.runner.Run(func() (cty.Value, error) {
|
|
|
|
return s.readSecurityGroupRule(rule)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
results, err = s.runner.Wait()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2021-05-21 14:09:45 +00:00
|
|
|
return s.deserializer.Deserialize(resourceaws.AwsSecurityGroupRuleResourceType, results)
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
|
2021-05-21 14:09:45 +00:00
|
|
|
func (s *VPCSecurityGroupRuleSupplier) readSecurityGroupRule(rule securityGroupRule) (cty.Value, error) {
|
|
|
|
id := rule.getId()
|
|
|
|
|
2020-12-09 15:31:34 +00:00
|
|
|
resSgRule, err := s.reader.ReadResource(terraform.ReadResourceArgs{
|
|
|
|
Ty: resourceaws.AwsSecurityGroupRuleResourceType,
|
|
|
|
ID: id,
|
|
|
|
Attributes: flatmap.Flatten(map[string]interface{}{
|
2021-05-21 14:09:45 +00:00
|
|
|
"type": rule.Type,
|
|
|
|
"security_group_id": rule.SecurityGroupId,
|
|
|
|
"protocol": rule.Protocol,
|
|
|
|
"from_port": rule.FromPort,
|
|
|
|
"to_port": rule.ToPort,
|
|
|
|
"self": rule.Self,
|
|
|
|
"source_security_group_id": rule.SourceSecurityGroupId,
|
|
|
|
"cidr_blocks": rule.CidrBlocks,
|
|
|
|
"ipv6_cidr_blocks": rule.Ipv6CidrBlocks,
|
|
|
|
"prefix_list_ids": rule.PrefixListIds,
|
2020-12-09 15:31:34 +00:00
|
|
|
}),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
logrus.Warnf("Error reading rule from security group %s: %+v", id, err)
|
|
|
|
return cty.NilVal, err
|
|
|
|
}
|
|
|
|
return *resSgRule, nil
|
|
|
|
}
|
|
|
|
|
2021-05-21 14:09:45 +00:00
|
|
|
func (s *VPCSecurityGroupRuleSupplier) listSecurityGroupsRules(securityGroups []*ec2.SecurityGroup) []securityGroupRule {
|
|
|
|
var securityGroupsRules []securityGroupRule
|
2020-12-09 15:31:34 +00:00
|
|
|
for _, sg := range securityGroups {
|
|
|
|
for _, rule := range sg.IpPermissions {
|
|
|
|
securityGroupsRules = append(securityGroupsRules, s.addSecurityGroupRule(sgRuleTypeIngress, rule, sg)...)
|
|
|
|
}
|
|
|
|
for _, rule := range sg.IpPermissionsEgress {
|
|
|
|
securityGroupsRules = append(securityGroupsRules, s.addSecurityGroupRule(sgRuleTypeEgress, rule, sg)...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return securityGroupsRules
|
|
|
|
}
|
|
|
|
|
|
|
|
// addSecurityGroupRule will iterate through each "Source" as per Aws definition and create a
|
|
|
|
// rule with custom attributes
|
2021-05-21 14:09:45 +00:00
|
|
|
func (s *VPCSecurityGroupRuleSupplier) addSecurityGroupRule(ruleType string, rule *ec2.IpPermission, sg *ec2.SecurityGroup) []securityGroupRule {
|
|
|
|
var rules []securityGroupRule
|
2020-12-09 15:31:34 +00:00
|
|
|
for _, groupPair := range rule.UserIdGroupPairs {
|
2021-05-21 14:09:45 +00:00
|
|
|
r := securityGroupRule{
|
|
|
|
Type: ruleType,
|
|
|
|
SecurityGroupId: aws.StringValue(sg.GroupId),
|
|
|
|
Protocol: aws.StringValue(rule.IpProtocol),
|
|
|
|
FromPort: int(aws.Int64Value(rule.FromPort)),
|
|
|
|
ToPort: int(aws.Int64Value(rule.ToPort)),
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
if aws.StringValue(groupPair.GroupId) == aws.StringValue(sg.GroupId) {
|
2021-05-21 14:09:45 +00:00
|
|
|
r.Self = true
|
2020-12-09 15:31:34 +00:00
|
|
|
} else {
|
2021-05-21 14:09:45 +00:00
|
|
|
r.SourceSecurityGroupId = aws.StringValue(groupPair.GroupId)
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
rules = append(rules, r)
|
|
|
|
}
|
|
|
|
for _, ipRange := range rule.IpRanges {
|
2021-05-21 14:09:45 +00:00
|
|
|
r := securityGroupRule{
|
|
|
|
Type: ruleType,
|
|
|
|
SecurityGroupId: aws.StringValue(sg.GroupId),
|
|
|
|
Protocol: aws.StringValue(rule.IpProtocol),
|
|
|
|
FromPort: int(aws.Int64Value(rule.FromPort)),
|
|
|
|
ToPort: int(aws.Int64Value(rule.ToPort)),
|
|
|
|
CidrBlocks: []string{aws.StringValue(ipRange.CidrIp)},
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
rules = append(rules, r)
|
|
|
|
}
|
|
|
|
for _, ipRange := range rule.Ipv6Ranges {
|
2021-05-21 14:09:45 +00:00
|
|
|
r := securityGroupRule{
|
|
|
|
Type: ruleType,
|
|
|
|
SecurityGroupId: aws.StringValue(sg.GroupId),
|
|
|
|
Protocol: aws.StringValue(rule.IpProtocol),
|
|
|
|
FromPort: int(aws.Int64Value(rule.FromPort)),
|
|
|
|
ToPort: int(aws.Int64Value(rule.ToPort)),
|
|
|
|
Ipv6CidrBlocks: []string{aws.StringValue(ipRange.CidrIpv6)},
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
rules = append(rules, r)
|
|
|
|
}
|
|
|
|
for _, listId := range rule.PrefixListIds {
|
2021-05-21 14:09:45 +00:00
|
|
|
r := securityGroupRule{
|
|
|
|
Type: ruleType,
|
|
|
|
SecurityGroupId: aws.StringValue(sg.GroupId),
|
|
|
|
Protocol: aws.StringValue(rule.IpProtocol),
|
|
|
|
FromPort: int(aws.Int64Value(rule.FromPort)),
|
|
|
|
ToPort: int(aws.Int64Value(rule.ToPort)),
|
|
|
|
PrefixListIds: []string{aws.StringValue(listId.PrefixListId)},
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
rules = append(rules, r)
|
|
|
|
}
|
|
|
|
// Filter default rules for default security group
|
|
|
|
if sg.GroupName != nil && *sg.GroupName == "default" {
|
2021-05-21 14:09:45 +00:00
|
|
|
results := make([]securityGroupRule, 0, len(rules))
|
2020-12-09 15:31:34 +00:00
|
|
|
for _, r := range rules {
|
2021-02-04 21:42:57 +00:00
|
|
|
r := r
|
2020-12-09 15:31:34 +00:00
|
|
|
if s.isDefaultIngress(&r) || s.isDefaultEgress(&r) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
results = append(results, r)
|
|
|
|
}
|
|
|
|
return results
|
|
|
|
}
|
|
|
|
|
|
|
|
return rules
|
|
|
|
}
|
|
|
|
|
2021-05-21 14:09:45 +00:00
|
|
|
func (s *VPCSecurityGroupRuleSupplier) isDefaultIngress(rule *securityGroupRule) bool {
|
|
|
|
return rule.Type == sgRuleTypeIngress &&
|
|
|
|
rule.FromPort == 0 &&
|
|
|
|
rule.ToPort == 0 &&
|
|
|
|
rule.Protocol == "-1" &&
|
2020-12-09 15:31:34 +00:00
|
|
|
rule.CidrBlocks == nil &&
|
|
|
|
rule.Ipv6CidrBlocks == nil &&
|
|
|
|
rule.PrefixListIds == nil &&
|
2021-05-21 14:09:45 +00:00
|
|
|
rule.SourceSecurityGroupId == "" &&
|
|
|
|
rule.Self
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|
|
|
|
|
2021-05-21 14:09:45 +00:00
|
|
|
func (s *VPCSecurityGroupRuleSupplier) isDefaultEgress(rule *securityGroupRule) bool {
|
|
|
|
return rule.Type == sgRuleTypeEgress &&
|
|
|
|
rule.FromPort == 0 &&
|
|
|
|
rule.ToPort == 0 &&
|
|
|
|
rule.Protocol == "-1" &&
|
2020-12-09 15:31:34 +00:00
|
|
|
rule.Ipv6CidrBlocks == nil &&
|
|
|
|
rule.PrefixListIds == nil &&
|
2021-05-21 14:09:45 +00:00
|
|
|
rule.SourceSecurityGroupId == "" &&
|
2020-12-09 15:31:34 +00:00
|
|
|
rule.CidrBlocks != nil &&
|
2021-05-21 14:09:45 +00:00
|
|
|
len(rule.CidrBlocks) == 1 &&
|
|
|
|
(rule.CidrBlocks)[0] == "0.0.0.0/0"
|
2020-12-09 15:31:34 +00:00
|
|
|
}
|