• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubescape / operator / 6706549703

31 Oct 2023 12:34PM UTC coverage: 22.338%. First build
6706549703

Pull #183

github

web-flow
Merge c201b655e into 366b3c30b
Pull Request #183: apply security to crobjob

3 of 3 new or added lines in 1 file covered. (100.0%)

818 of 3662 relevant lines covered (22.34%)

1.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/mainhandler/kubescapehandler.go
1
package mainhandler
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "errors"
7
        "fmt"
8
        "math/rand"
9
        "time"
10

11
        v1 "github.com/kubescape/backend/pkg/client/v1"
12
        "github.com/kubescape/go-logger"
13
        "github.com/kubescape/go-logger/helpers"
14
        "github.com/kubescape/operator/config"
15
        "go.opentelemetry.io/otel"
16

17
        armoapi "github.com/armosec/armoapi-go/apis"
18
        "github.com/armosec/armoapi-go/armotypes"
19
        "github.com/armosec/utils-go/httputils"
20
        utilsapisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
21

22
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23
)
24

25
const (
26
        WaitTimeForKubescapeScanResponse = 40
27
        KubescapeCronJobTemplateName     = "kubescape-cronjob-template"
28
)
29

30
type kubescapeResponseData struct {
31
        reporter v1.IReportSender
32
        scanID   string
33
}
34

35
func (actionHandler *ActionHandler) deleteKubescapeCronJob(ctx context.Context) error {
×
36
        ctx, span := otel.Tracer("").Start(ctx, "actionHandler.deleteKubescapeCronJob")
×
37
        defer span.End()
×
38

×
39
        if !actionHandler.config.Components().KubescapeScheduler.Enabled {
×
40
                return errors.New("KubescapeScheduler is not enabled")
×
41
        }
×
42

43
        kubescapeJobParams := getKubescapeJobParams(&actionHandler.command)
×
44
        if kubescapeJobParams == nil {
×
45
                return fmt.Errorf("failed to convert kubescapeJobParams list to KubescapeJobParams")
×
46
        }
×
47

48
        if err := actionHandler.k8sAPI.KubernetesClient.BatchV1().CronJobs(actionHandler.config.Namespace()).Delete(context.Background(), kubescapeJobParams.JobName, metav1.DeleteOptions{}); err != nil {
×
49
                return err
×
50
        }
×
51

52
        if err := actionHandler.k8sAPI.KubernetesClient.CoreV1().ConfigMaps(actionHandler.config.Namespace()).Delete(context.Background(), kubescapeJobParams.JobName, metav1.DeleteOptions{}); err != nil {
×
53
                return err
×
54
        }
×
55
        return nil
×
56
}
57

58
func (actionHandler *ActionHandler) updateKubescapeCronJob(ctx context.Context) error {
×
59
        ctx, span := otel.Tracer("").Start(ctx, "actionHandler.updateKubescapeCronJob")
×
60
        defer span.End()
×
61

×
62
        if !actionHandler.config.Components().KubescapeScheduler.Enabled {
×
63
                return errors.New("KubescapeScheduler is not enabled")
×
64
        }
×
65

66
        jobParams := getKubescapeJobParams(&actionHandler.command)
×
67
        if jobParams == nil {
×
68
                return fmt.Errorf("failed to convert kubescapeJobParams list to KubescapeJobParams")
×
69
        }
×
70

71
        jobTemplateObj, err := actionHandler.k8sAPI.KubernetesClient.BatchV1().CronJobs(actionHandler.config.Namespace()).Get(context.Background(), jobParams.JobName, metav1.GetOptions{})
×
72
        if err != nil {
×
73
                return err
×
74
        }
×
75

76
        jobTemplateObj.Spec.Schedule = getCronTabSchedule(actionHandler.command)
×
77
        if jobTemplateObj.Spec.JobTemplate.Spec.Template.Annotations == nil {
×
78
                jobTemplateObj.Spec.JobTemplate.Spec.Template.Annotations = make(map[string]string)
×
79
        }
×
80
        jobTemplateObj.Spec.JobTemplate.Spec.Template.Annotations[armotypes.CronJobTemplateAnnotationUpdateJobIDDeprecated] = actionHandler.command.JobTracking.JobID // deprecated
×
81
        jobTemplateObj.Spec.JobTemplate.Spec.Template.Annotations[armotypes.CronJobTemplateAnnotationUpdateJobID] = actionHandler.command.JobTracking.JobID
×
82

×
83
        _, err = actionHandler.k8sAPI.KubernetesClient.BatchV1().CronJobs(actionHandler.config.Namespace()).Update(context.Background(), jobTemplateObj, metav1.UpdateOptions{})
×
84
        if err != nil {
×
85
                return err
×
86
        }
×
87
        return nil
×
88
}
89

90
func (actionHandler *ActionHandler) setKubescapeCronJob(ctx context.Context) error {
×
91
        ctx, span := otel.Tracer("").Start(ctx, "actionHandler.setKubescapeCronJob")
×
92
        defer span.End()
×
93

×
94
        if !actionHandler.config.Components().KubescapeScheduler.Enabled {
×
95
                return errors.New("KubescapeScheduler is not enabled")
×
96
        }
×
97

98
        req, err := getKubescapeRequest(actionHandler.command.Args)
×
99
        if err != nil {
×
100
                return err
×
101
        }
×
102

103
        // append security framework if TriggerSecurityFramework is true
104
        if actionHandler.config.TriggerSecurityFramework() {
×
105
                appendSecurityFramework(req)
×
106
        }
×
107

108
        for i := range req.TargetNames {
×
109
                name := fixK8sCronJobNameLimit(fmt.Sprintf("%s-%s-%d", "ks-scheduled-scan", req.TargetNames[i], rand.NewSource(time.Now().UnixNano()).Int63()))
×
110

×
111
                // create config map
×
112
                if err := createTriggerRequestConfigMap(actionHandler.k8sAPI, actionHandler.config.Namespace(), name, req); err != nil {
×
113
                        return err
×
114
                }
×
115

116
                jobTemplateObj, err := getCronJobTemplate(actionHandler.k8sAPI, KubescapeCronJobTemplateName, actionHandler.config.Namespace())
×
117
                if err != nil {
×
118
                        return err
×
119
                }
×
120

121
                setCronJobTemplate(jobTemplateObj, name, getCronTabSchedule(actionHandler.command), actionHandler.command.JobTracking.JobID, req.TargetNames[i], req.TargetType, req.HostScanner)
×
122

×
123
                // create cronJob
×
124
                if _, err := actionHandler.k8sAPI.KubernetesClient.BatchV1().CronJobs(actionHandler.config.Namespace()).Create(context.Background(), jobTemplateObj, metav1.CreateOptions{}); err != nil {
×
125
                        return err
×
126
                }
×
127
        }
128

129
        return nil
×
130
}
131

132
func HandleKubescapeResponse(ctx context.Context, config config.IConfig, sendReport bool, payload interface{}) (bool, *time.Duration) {
×
133
        data := payload.(*kubescapeResponseData)
×
134
        logger.L().Info(fmt.Sprintf("handle kubescape response for scan id %s", data.scanID))
×
135

×
136
        info := fmt.Sprintf("getting kubescape scanID %s job status", data.scanID)
×
137
        errChan := make(chan error)
×
138
        data.reporter.SendDetails(info, sendReport)
×
139
        if err := <-errChan; err != nil {
×
140
                logger.L().Ctx(ctx).Error("HandleKubescapeResponse failed to send error report", helpers.Error(err))
×
141
        }
×
142

143
        resp, err := httputils.HttpGetWithContext(ctx, KubescapeHttpClient, getKubescapeV1ScanStatusURL(config, data.scanID).String(), nil)
×
144
        if err != nil {
×
145
                info := fmt.Sprintf("get scanID job status with scanID '%s' returned an error: %s", data.scanID, err.Error())
×
146
                data.reporter.SendDetails(info, sendReport)
×
147
                if err := <-errChan; err != nil {
×
148
                        logger.L().Ctx(ctx).Error("HandleKubescapeResponse failed to send status report", helpers.Error(err))
×
149
                }
×
150
                data.reporter.SendError(err, sendReport, true)
×
151
                if err := <-errChan; err != nil {
×
152
                        logger.L().Ctx(ctx).Error("HandleKubescapeResponse::error in HTTP GET + failed to send error report", helpers.Error(err))
×
153
                }
×
154
                logger.L().Ctx(ctx).Error("get scanID job status returned an error", helpers.String("scanID", data.scanID), helpers.Error(err))
×
155
                return false, nil
×
156
        }
157

158
        response, err := readKubescapeV1ScanResponse(resp)
×
159
        if err != nil {
×
160
                info := fmt.Sprintf("parse scanID job status with scanID '%s' returned an error: %s", data.scanID, err.Error())
×
161
                data.reporter.SendDetails(info, sendReport)
×
162
                if err := <-errChan; err != nil {
×
163
                        logger.L().Ctx(ctx).Error("HandleKubescapeResponse::readKubescapeV1ScanResponse failed to send status report", helpers.Error(err))
×
164
                }
×
165
                data.reporter.SendError(err, sendReport, true)
×
166
                if err := <-errChan; err != nil {
×
167
                        logger.L().Ctx(ctx).Error("HandleKubescapeResponse::readKubescapeV1ScanResponse failed to send error report", helpers.Error(err))
×
168
                }
×
169
                logger.L().Ctx(ctx).Error("parse scanID job status returned an error", helpers.String("scanID", data.scanID), helpers.Error(err))
×
170
                return false, nil
×
171
        }
172

173
        if response.Type == utilsapisv1.BusyScanResponseType {
×
174
                nextTimeRehandled := time.Duration(WaitTimeForKubescapeScanResponse * time.Second)
×
175
                info = fmt.Sprintf("Kubescape get job status for scanID '%s' is %s next handle time is %s", data.scanID, utilsapisv1.BusyScanResponseType, nextTimeRehandled.String())
×
176
                logger.L().Info(info)
×
177
                data.reporter.SendDetails(info, sendReport)
×
178
                if err := <-errChan; err != nil {
×
179
                        logger.L().Ctx(ctx).Error("HandleKubescapeResponse::BusyScanResponseType failed to send status report", helpers.Error(err))
×
180
                }
×
181
                return true, &nextTimeRehandled
×
182
        }
183

184
        info = fmt.Sprintf("Kubescape get job status scanID '%s' finished successfully", data.scanID)
×
185
        logger.L().Info(info)
×
186
        data.reporter.SendDetails(info, sendReport)
×
187
        if err := <-errChan; err != nil {
×
188
                logger.L().Ctx(ctx).Error("HandleKubescapeResponse::Done failed to send status report", helpers.Error(err))
×
189
        }
×
190
        return false, nil
×
191
}
192

193
func (actionHandler *ActionHandler) kubescapeScan(ctx context.Context) error {
×
194
        ctx, span := otel.Tracer("").Start(ctx, "actionHandler.kubescapeScan")
×
195
        defer span.End()
×
196

×
197
        if !actionHandler.config.Components().Kubescape.Enabled {
×
198
                return errors.New("Kubescape is not enabled")
×
199
        }
×
200

201
        request, err := getKubescapeV1ScanRequest(actionHandler.command.Args)
×
202
        if err != nil {
×
203
                return err
×
204
        }
×
205

206
        // append security framework if TriggerSecurityFramework is true
207
        if actionHandler.config.TriggerSecurityFramework() {
×
208
                appendSecurityFramework(request)
×
209
        }
×
210

211
        body, err := json.Marshal(*request)
×
212
        if err != nil {
×
213
                return err
×
214
        }
×
215
        resp, err := httputils.HttpPostWithContext(ctx, KubescapeHttpClient, getKubescapeV1ScanURL(actionHandler.config).String(), nil, body)
×
216
        if err != nil {
×
217
                return err
×
218
        }
×
219
        response, err := readKubescapeV1ScanResponse(resp)
×
220
        if err != nil {
×
221
                return err
×
222
        }
×
223
        info := fmt.Sprintf("triggered successfully, scan ID: '%s'", response.ID)
×
224

×
225
        if response.Type == utilsapisv1.ErrorScanResponseType {
×
226
                info = fmt.Sprintf("Kubescape scanID '%s' returned an error: %s", response.ID, response.Response)
×
227
        }
×
228
        actionHandler.reporter.SendDetails(info, actionHandler.sendReport)
×
229
        logger.L().Info(info)
×
230

×
231
        data := &kubescapeResponseData{
×
232
                reporter: actionHandler.reporter,
×
233
                scanID:   response.ID,
×
234
        }
×
235

×
236
        if actionHandler.sendReport {
×
237
                nextHandledTime := WaitTimeForKubescapeScanResponse * time.Second
×
238
                commandResponseData := createNewCommandResponseData(KubescapeResponse, HandleKubescapeResponse, data, &nextHandledTime)
×
239
                insertNewCommandResponseData(actionHandler.commandResponseChannel, commandResponseData)
×
240
        }
×
241

242
        return nil
×
243
}
244

245
func getCronTabSchedule(command armoapi.Command) string {
×
246
        if kubescapeJobParams := getKubescapeJobParams(&command); kubescapeJobParams != nil {
×
247
                return kubescapeJobParams.CronTabSchedule
×
248
        }
×
249
        if schedule, ok := command.Args["cronTabSchedule"]; ok {
×
250
                if s, k := schedule.(string); k {
×
251
                        return s
×
252
                }
×
253
        }
254
        if len(command.Designators) > 0 {
×
255
                if schedule, ok := command.Designators[0].Attributes["cronTabSchedule"]; ok {
×
256
                        return schedule
×
257
                }
×
258
        }
259

260
        return ""
×
261
}
262

263
func getKubescapeJobParams(command *armoapi.Command) *armoapi.CronJobParams {
×
264

×
265
        if jobParams := command.GetCronJobParams(); jobParams != nil {
×
266
                return jobParams
×
267
        }
×
268

269
        // fallback
270
        if jobParams, ok := command.Args["kubescapeJobParams"]; ok {
×
271
                if kubescapeJobParams, ok := jobParams.(armoapi.CronJobParams); ok {
×
272
                        return &kubescapeJobParams
×
273
                }
×
274
                b, err := json.Marshal(jobParams)
×
275
                if err != nil {
×
276
                        return nil
×
277
                }
×
278
                kubescapeJobParams := &armoapi.CronJobParams{}
×
279
                if err = json.Unmarshal(b, kubescapeJobParams); err != nil {
×
280
                        return nil
×
281
                }
×
282
                return kubescapeJobParams
×
283
        }
284
        return nil
×
285
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc