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 }