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

     1  package cloudwatch
     2  
     3  import (
     4  	cwApi "github.com/aws/aws-sdk-go-v2/service/cloudwatch"
     5  	cwTypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
     6  	api "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
     7  	"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
     8  	"github.com/khulnasoft-lab/defsec/internal/adapters/cloud/aws"
     9  	"github.com/khulnasoft-lab/defsec/pkg/concurrency"
    10  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/cloudwatch"
    11  	"github.com/khulnasoft-lab/defsec/pkg/state"
    12  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
    13  )
    14  
    15  type adapter struct {
    16  	*aws.RootAdapter
    17  	logsClient   *api.Client
    18  	alarmsClient *cwApi.Client
    19  }
    20  
    21  func init() {
    22  	aws.RegisterServiceAdapter(&adapter{})
    23  }
    24  
    25  func (a *adapter) Provider() string {
    26  	return "aws"
    27  }
    28  
    29  func (a *adapter) Name() string {
    30  	return "cloudwatch"
    31  }
    32  
    33  func (a *adapter) Adapt(root *aws.RootAdapter, state *state.State) error {
    34  
    35  	a.RootAdapter = root
    36  	a.logsClient = api.NewFromConfig(root.SessionConfig())
    37  	a.alarmsClient = cwApi.NewFromConfig(root.SessionConfig())
    38  	var err error
    39  
    40  	state.AWS.CloudWatch.LogGroups, err = a.getLogGroups()
    41  	if err != nil {
    42  		return err
    43  	}
    44  	state.AWS.CloudWatch.Alarms, err = a.getAlarms()
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  func (a *adapter) getAlarms() ([]cloudwatch.Alarm, error) {
    53  
    54  	a.Tracker().SetServiceLabel("Discovering alarms...")
    55  	var apiAlarms []cwTypes.MetricAlarm
    56  
    57  	var input cwApi.DescribeAlarmsInput
    58  	for {
    59  		output, err := a.alarmsClient.DescribeAlarms(a.Context(), &input)
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  		apiAlarms = append(apiAlarms, output.MetricAlarms...)
    64  		a.Tracker().SetTotalResources(len(apiAlarms))
    65  		if output.NextToken == nil {
    66  			break
    67  		}
    68  		input.NextToken = output.NextToken
    69  	}
    70  
    71  	a.Tracker().SetServiceLabel("Adapting log groups...")
    72  	return concurrency.Adapt(apiAlarms, a.RootAdapter, a.adaptAlarm), nil
    73  }
    74  
    75  func (a *adapter) getLogGroups() ([]cloudwatch.LogGroup, error) {
    76  
    77  	a.Tracker().SetServiceLabel("Discovering log groups...")
    78  
    79  	var apiLogGroups []types.LogGroup
    80  	var input api.DescribeLogGroupsInput
    81  	for {
    82  		output, err := a.logsClient.DescribeLogGroups(a.Context(), &input)
    83  		if err != nil {
    84  			return nil, err
    85  		}
    86  		apiLogGroups = append(apiLogGroups, output.LogGroups...)
    87  		a.Tracker().SetTotalResources(len(apiLogGroups))
    88  		if output.NextToken == nil {
    89  			break
    90  		}
    91  		input.NextToken = output.NextToken
    92  	}
    93  
    94  	a.Tracker().SetServiceLabel("Adapting log groups...")
    95  	return concurrency.Adapt(apiLogGroups, a.RootAdapter, a.adaptLogGroup), nil
    96  }
    97  
    98  func (a *adapter) adaptLogGroup(group types.LogGroup) (*cloudwatch.LogGroup, error) {
    99  
   100  	metadata := a.CreateMetadataFromARN(*group.Arn)
   101  
   102  	var kmsKeyId string
   103  	var retentionInDays int
   104  
   105  	if group.KmsKeyId != nil {
   106  		kmsKeyId = *group.KmsKeyId
   107  	}
   108  
   109  	if group.RetentionInDays != nil {
   110  		retentionInDays = int(*group.RetentionInDays)
   111  	}
   112  
   113  	var metricFilters []cloudwatch.MetricFilter
   114  	var err error
   115  	if *group.MetricFilterCount > 0 {
   116  		metricFilters, err = a.getMetricFilters(group.LogGroupName, metadata)
   117  		if err != nil {
   118  			return nil, err
   119  		}
   120  
   121  	}
   122  
   123  	arn := defsecTypes.StringDefault("", metadata)
   124  	if group.Arn != nil {
   125  		arn = defsecTypes.String(*group.Arn, metadata)
   126  	}
   127  
   128  	name := defsecTypes.StringDefault("", metadata)
   129  	if group.LogGroupName != nil {
   130  		name = defsecTypes.String(*group.LogGroupName, metadata)
   131  	}
   132  
   133  	return &cloudwatch.LogGroup{
   134  		Metadata:        metadata,
   135  		Arn:             arn,
   136  		Name:            name,
   137  		KMSKeyID:        defsecTypes.String(kmsKeyId, metadata),
   138  		RetentionInDays: defsecTypes.Int(retentionInDays, metadata),
   139  		MetricFilters:   metricFilters,
   140  	}, nil
   141  }
   142  
   143  func (a *adapter) adaptAlarm(alarm cwTypes.MetricAlarm) (*cloudwatch.Alarm, error) {
   144  
   145  	metadata := a.CreateMetadataFromARN(*alarm.AlarmArn)
   146  
   147  	var dimensions []cloudwatch.AlarmDimension
   148  	for _, dimension := range alarm.Dimensions {
   149  
   150  		name := defsecTypes.StringDefault("", metadata)
   151  		if dimension.Name != nil {
   152  			name = defsecTypes.String(*dimension.Name, metadata)
   153  		}
   154  
   155  		value := defsecTypes.StringDefault("", metadata)
   156  		if dimension.Value != nil {
   157  			value = defsecTypes.String(*dimension.Value, metadata)
   158  		}
   159  
   160  		dimensions = append(dimensions, cloudwatch.AlarmDimension{
   161  			Metadata: metadata,
   162  			Name:     name,
   163  			Value:    value,
   164  		})
   165  	}
   166  
   167  	var metrics []cloudwatch.MetricDataQuery
   168  	for _, metric := range alarm.Metrics {
   169  
   170  		id := defsecTypes.StringDefault("", metadata)
   171  		if metric.Id != nil {
   172  			id = defsecTypes.String(*metric.Id, metadata)
   173  		}
   174  
   175  		expression := defsecTypes.StringDefault("", metadata)
   176  		if metric.Expression != nil {
   177  			expression = defsecTypes.String(*metric.Expression, metadata)
   178  		}
   179  
   180  		metrics = append(metrics, cloudwatch.MetricDataQuery{
   181  			Metadata:   metadata,
   182  			ID:         id,
   183  			Expression: expression,
   184  		})
   185  	}
   186  
   187  	name := defsecTypes.StringDefault("", metadata)
   188  	if alarm.AlarmName != nil {
   189  		name = defsecTypes.String(*alarm.AlarmName, metadata)
   190  	}
   191  
   192  	metric := defsecTypes.StringDefault("", metadata)
   193  	if alarm.MetricName != nil {
   194  		metric = defsecTypes.String(*alarm.MetricName, metadata)
   195  	}
   196  
   197  	return &cloudwatch.Alarm{
   198  		Metadata:   metadata,
   199  		AlarmName:  name,
   200  		MetricName: metric,
   201  		Dimensions: dimensions,
   202  		Metrics:    metrics,
   203  	}, nil
   204  }
   205  
   206  func (a *adapter) getMetricFilters(name *string, metadata defsecTypes.Metadata) ([]cloudwatch.MetricFilter, error) {
   207  
   208  	var apiMetricFilters []types.MetricFilter
   209  	input := api.DescribeMetricFiltersInput{
   210  		LogGroupName: name,
   211  	}
   212  	for {
   213  		output, err := a.logsClient.DescribeMetricFilters(a.Context(), &input)
   214  		if err != nil {
   215  			return nil, err
   216  		}
   217  
   218  		apiMetricFilters = append(apiMetricFilters, output.MetricFilters...)
   219  		if output.NextToken == nil {
   220  			break
   221  		}
   222  		input.NextToken = output.NextToken
   223  	}
   224  
   225  	var metricFilters []cloudwatch.MetricFilter
   226  	for _, mf := range apiMetricFilters {
   227  
   228  		name := defsecTypes.StringDefault("", metadata)
   229  		if mf.FilterName != nil {
   230  			name = defsecTypes.String(*mf.FilterName, metadata)
   231  		}
   232  
   233  		pattern := defsecTypes.StringDefault("", metadata)
   234  		if mf.FilterPattern != nil {
   235  			pattern = defsecTypes.String(*mf.FilterPattern, metadata)
   236  		}
   237  		metricFilters = append(metricFilters, cloudwatch.MetricFilter{
   238  			Metadata:      metadata,
   239  			FilterName:    name,
   240  			FilterPattern: pattern,
   241  		})
   242  
   243  	}
   244  
   245  	return metricFilters, nil
   246  }