github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/cloud/aws/ec2/ec2.go (about)

     1  package ec2
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/aws/aws-sdk-go-v2/aws"
     8  	"github.com/khulnasoft-lab/defsec/pkg/concurrency"
     9  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
    10  
    11  	ec2api "github.com/aws/aws-sdk-go-v2/service/ec2"
    12  	ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
    13  	aws2 "github.com/khulnasoft-lab/defsec/internal/adapters/cloud/aws"
    14  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/ec2"
    15  	"github.com/khulnasoft-lab/defsec/pkg/state"
    16  )
    17  
    18  type adapter struct {
    19  	*aws2.RootAdapter
    20  	client *ec2api.Client
    21  }
    22  
    23  func init() {
    24  	aws2.RegisterServiceAdapter(&adapter{})
    25  }
    26  
    27  func (a *adapter) Provider() string {
    28  	return "aws"
    29  }
    30  
    31  func (a *adapter) Name() string {
    32  	return "ec2"
    33  }
    34  
    35  func (a *adapter) Adapt(root *aws2.RootAdapter, state *state.State) error {
    36  
    37  	a.RootAdapter = root
    38  	a.client = ec2api.NewFromConfig(root.SessionConfig())
    39  	var err error
    40  
    41  	state.AWS.EC2.Instances, err = a.getInstances()
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	state.AWS.EC2.SecurityGroups, err = a.getSecurityGroups()
    47  	if err != nil {
    48  		return err
    49  	}
    50  
    51  	state.AWS.EC2.NetworkACLs, err = a.getNetworkACLs()
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	state.AWS.EC2.VPCs, err = a.getVPCs()
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	state.AWS.EC2.LaunchTemplates, err = a.getLaunchTemplates()
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	state.AWS.EC2.Volumes, err = a.getVolumes()
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	for i, vpc := range state.AWS.EC2.VPCs {
    72  		for _, group := range state.AWS.EC2.SecurityGroups {
    73  			if group.VPCID.EqualTo(vpc.ID.Value()) {
    74  				state.AWS.EC2.VPCs[i].SecurityGroups = append(state.AWS.EC2.VPCs[i].SecurityGroups, group)
    75  			}
    76  		}
    77  	}
    78  
    79  	return nil
    80  }
    81  
    82  func (a *adapter) getInstances() (instances []ec2.Instance, err error) {
    83  
    84  	a.Tracker().SetServiceLabel("Discovering instances...")
    85  	var apiInstances []ec2Types.Instance
    86  	input := &ec2api.DescribeInstancesInput{
    87  		Filters: []ec2Types.Filter{
    88  			{
    89  				Name:   aws.String("instance-state-name"),
    90  				Values: []string{"running"},
    91  			},
    92  		},
    93  	}
    94  
    95  	for {
    96  		output, err := a.client.DescribeInstances(a.Context(), input)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		for _, res := range output.Reservations {
   101  			apiInstances = append(apiInstances, res.Instances...)
   102  		}
   103  
   104  		a.Tracker().SetTotalResources(len(apiInstances))
   105  		if output.NextToken == nil {
   106  			break
   107  		}
   108  		input.NextToken = output.NextToken
   109  	}
   110  
   111  	a.Tracker().SetServiceLabel("Adapting instances...")
   112  	return concurrency.Adapt(apiInstances, a.RootAdapter, a.adaptInstance), nil
   113  }
   114  
   115  func (a *adapter) adaptInstance(instance ec2Types.Instance) (*ec2.Instance, error) {
   116  
   117  	volumeBlockMap := make(map[string]*ec2.BlockDevice)
   118  	var volumeIds []string
   119  	instanceMetadata := a.CreateMetadata("instance/" + *instance.InstanceId)
   120  
   121  	i := ec2.NewInstance(instanceMetadata)
   122  	if instance.MetadataOptions != nil {
   123  		i.MetadataOptions.HttpTokens = defsecTypes.StringDefault(string(instance.MetadataOptions.HttpTokens), instanceMetadata)
   124  		i.MetadataOptions.HttpEndpoint = defsecTypes.StringDefault(string(instance.MetadataOptions.HttpEndpoint), instanceMetadata)
   125  	}
   126  
   127  	if instance.BlockDeviceMappings != nil {
   128  		for _, blockMapping := range instance.BlockDeviceMappings {
   129  			volumeMetadata := a.CreateMetadata(fmt.Sprintf("volume/%s", *blockMapping.Ebs.VolumeId))
   130  			ebsDevice := &ec2.BlockDevice{
   131  				Metadata:  volumeMetadata,
   132  				Encrypted: defsecTypes.BoolDefault(false, volumeMetadata),
   133  			}
   134  			if strings.EqualFold(*blockMapping.DeviceName, *instance.RootDeviceName) {
   135  				// is root block device
   136  				i.RootBlockDevice = ebsDevice
   137  			} else {
   138  				i.EBSBlockDevices = append(i.EBSBlockDevices, ebsDevice)
   139  			}
   140  			volumeBlockMap[*blockMapping.Ebs.VolumeId] = ebsDevice
   141  			volumeIds = append(volumeIds, *blockMapping.Ebs.VolumeId)
   142  		}
   143  	}
   144  
   145  	volumes, err := a.client.DescribeVolumes(a.Context(), &ec2api.DescribeVolumesInput{
   146  		VolumeIds: volumeIds,
   147  	})
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	for _, v := range volumes.Volumes {
   153  		block := volumeBlockMap[*v.VolumeId]
   154  		if block != nil {
   155  			block.Encrypted = defsecTypes.BoolDefault(false, block.Metadata)
   156  			if v.Encrypted != nil {
   157  				block.Encrypted = defsecTypes.Bool(*v.Encrypted, block.Metadata)
   158  			}
   159  		}
   160  	}
   161  	return i, nil
   162  }