Skip to content

Commit 7556072

Browse files
authored
Merge pull request #260 from kubescape/regv2
regv2
2 parents 086456a + 7887f49 commit 7556072

File tree

5 files changed

+173
-37
lines changed

5 files changed

+173
-37
lines changed

go.mod

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ go 1.23.0
55
toolchain go1.23.2
66

77
require (
8-
github.com/armosec/armoapi-go v0.0.467
8+
github.com/armosec/armoapi-go v0.0.473
99
github.com/armosec/cluster-notifier-api-go v0.0.5
10-
github.com/armosec/registryx v0.0.16
10+
github.com/armosec/registryx v0.0.18
1111
github.com/armosec/utils-go v0.0.58
1212
github.com/armosec/utils-k8s-go v0.0.30
1313
github.com/aws/aws-sdk-go v1.50.8
@@ -38,6 +38,7 @@ require (
3838
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.44.0
3939
go.opentelemetry.io/otel v1.28.0
4040
go.opentelemetry.io/otel/trace v1.28.0
41+
golang.org/x/sync v0.8.0
4142
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
4243
istio.io/pkg v0.0.0-20231221211216-7635388a563e
4344
k8s.io/api v0.30.2
@@ -95,6 +96,7 @@ require (
9596
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect
9697
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
9798
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
99+
github.com/Masterminds/semver/v3 v3.3.0 // indirect
98100
github.com/Microsoft/go-winio v0.6.2 // indirect
99101
github.com/OneOfOne/xxhash v1.2.8 // indirect
100102
github.com/acobaugh/osrelease v0.1.0 // indirect
@@ -287,7 +289,6 @@ require (
287289
golang.org/x/mod v0.21.0 // indirect
288290
golang.org/x/net v0.29.0 // indirect
289291
golang.org/x/oauth2 v0.21.0 // indirect
290-
golang.org/x/sync v0.8.0 // indirect
291292
golang.org/x/sys v0.25.0 // indirect
292293
golang.org/x/term v0.24.0 // indirect
293294
golang.org/x/text v0.18.0 // indirect

go.sum

+6-4
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
9797
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
9898
github.com/IBM/sarama v1.42.1 h1:wugyWa15TDEHh2kvq2gAy1IHLjEjuYOYgXz/ruC/OSQ=
9999
github.com/IBM/sarama v1.42.1/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ=
100+
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
101+
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
100102
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
101103
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
102104
github.com/Microsoft/hcsshim v0.12.5 h1:bpTInLlDy/nDRWFVcefDZZ1+U8tS+rz3MxjKgu9boo0=
@@ -137,14 +139,14 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
137139
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
138140
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
139141
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
140-
github.com/armosec/armoapi-go v0.0.467 h1:HkPC4ZWMIoQo0rh0M0yFumOlo/Orrf1TvaRciVv48JI=
141-
github.com/armosec/armoapi-go v0.0.467/go.mod h1:TruqDSAPgfRBXCeM+Cgp6nN4UhJSbe7la+XDKV2pTsY=
142+
github.com/armosec/armoapi-go v0.0.473 h1:YPCz2Tj5GmdegItI9PPwY1e4AXGCp2RxS9S17mOF8Zc=
143+
github.com/armosec/armoapi-go v0.0.473/go.mod h1:TruqDSAPgfRBXCeM+Cgp6nN4UhJSbe7la+XDKV2pTsY=
142144
github.com/armosec/cluster-notifier-api-go v0.0.5 h1:UKY58ehKocKgtqzrawyaIHJa5paG9A4srv+4/6n+Ez4=
143145
github.com/armosec/cluster-notifier-api-go v0.0.5/go.mod h1:p5w9/zWIWwpi8W8mHGQdE6HuBb3AxXmZM9Rp//JWvx0=
144146
github.com/armosec/gojay v1.2.17 h1:VSkLBQzD1c2V+FMtlGFKqWXNsdNvIKygTKJI9ysY8eM=
145147
github.com/armosec/gojay v1.2.17/go.mod h1:vuvX3DlY0nbVrJ0qCklSS733AWMoQboq3cFyuQW9ybc=
146-
github.com/armosec/registryx v0.0.16 h1:L+oA9h4cJO42YfqYGO+NkmeloY0+z/VQCPjqVU6i9kU=
147-
github.com/armosec/registryx v0.0.16/go.mod h1:tWzKL9LcYySAfcujIPgYSvKG+HiJqqiMxF5juUaBKxU=
148+
github.com/armosec/registryx v0.0.18 h1:DkZ0DEjXSFJshsZQgVSWijTv5VAQ+kyVIdNB8a8E39A=
149+
github.com/armosec/registryx v0.0.18/go.mod h1:48rlQqJa+WGTKzPsusO8f0BPN6ZeuiiMXoVJYd3h7VU=
148150
github.com/armosec/utils-go v0.0.58 h1:g9RnRkxZAmzTfPe2ruMo2OXSYLwVSegQSkSavOfmaIE=
149151
github.com/armosec/utils-go v0.0.58/go.mod h1:CdqKHKruVJMCxGcZXYW9J+5P9FZou8dMzVpcB0Xt8pk=
150152
github.com/armosec/utils-k8s-go v0.0.30 h1:Gj8MJck0jZPSLSq8ZMiRPT3F/laOYQdaLxXKKcjijt4=

mainhandler/handlerequests.go

+2
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ func (actionHandler *ActionHandler) runCommand(ctx context.Context, sessionObj *
260260
return actionHandler.updateRegistryScanCronJob(ctx, sessionObj)
261261
case apis.TypeDeleteRegistryScanCronJob:
262262
return actionHandler.deleteRegistryScanCronJob(ctx)
263+
case apis.TypeScanRegistryV2:
264+
return actionHandler.scanRegistriesV2(ctx, sessionObj)
263265
default:
264266
logger.L().Ctx(ctx).Error(fmt.Sprintf("Command %s not found", c.CommandName))
265267
}

mainhandler/vulnscan.go

+99
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8+
"github.com/armosec/registryx/interfaces"
9+
"github.com/armosec/registryx/registryclients"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
811
"net/url"
912
"strings"
1013
"time"
@@ -156,6 +159,102 @@ func (actionHandler *ActionHandler) scanRegistries(ctx context.Context, sessionO
156159
return actionHandler.scanRegistry(ctx, registryScan, sessionObj)
157160
}
158161

162+
func (actionHandler *ActionHandler) scanRegistriesV2(ctx context.Context, sessionObj *utils.SessionObj) error {
163+
ctx, span := otel.Tracer("").Start(ctx, "actionHandler.scanRegistries")
164+
defer span.End()
165+
166+
if !actionHandler.config.Components().Kubevuln.Enabled {
167+
return errors.New("kubevuln is not enabled")
168+
}
169+
170+
// send change status of registry to scanning
171+
imageRegistry, err := actionHandler.loadRegistryFromSessionObj(sessionObj)
172+
if err != nil {
173+
return fmt.Errorf("scanRegistriesV2 failed to load registry from sessionObj with err %v", err)
174+
}
175+
176+
if err = actionHandler.loadRegistrySecret(ctx, sessionObj, imageRegistry); err != nil {
177+
return fmt.Errorf("scanRegistriesV2 failed to load secret with err %v", err)
178+
}
179+
180+
client, err := registryclients.GetRegistryClient(imageRegistry)
181+
if err != nil {
182+
return fmt.Errorf("scanRegistriesV2 failed to get registry client with err %v", err)
183+
}
184+
185+
images, err := client.GetImagesToScan(ctx)
186+
if err != nil {
187+
return fmt.Errorf("scanRegistriesV2 failed to get registry images to scan with err %v", err)
188+
}
189+
190+
registryScanCMDList := actionHandler.getRegistryImageScanCommands(sessionObj, client, imageRegistry, images)
191+
sessionObj.Reporter.SendDetails(fmt.Sprintf("sending %d images from registry %v to vuln scan", len(registryScanCMDList), imageRegistry), actionHandler.sendReport)
192+
193+
return sendAllImagesToRegistryScan(ctx, actionHandler.config, registryScanCMDList)
194+
}
195+
196+
func (actionHandler *ActionHandler) loadRegistrySecret(ctx context.Context, sessionObj *utils.SessionObj, imageRegistry apitypes.ContainerImageRegistry) error {
197+
secretName := sessionObj.Command.Args[apitypes.RegistrySecretNameArgKey].(string)
198+
secret, err := actionHandler.k8sAPI.KubernetesClient.CoreV1().Secrets(apitypes.KubescapeNamespace).Get(ctx, secretName, metav1.GetOptions{})
199+
if err != nil {
200+
return fmt.Errorf("loadRegistrySecret failed to get secret with err %v", err)
201+
}
202+
203+
var secretMap map[string]string
204+
err = json.Unmarshal(secret.Data[apitypes.RegistryAuthFieldInSecret], &secretMap)
205+
if err != nil {
206+
return fmt.Errorf("loadRegistrySecret failed to unmarshal registry secret with err %v", err)
207+
}
208+
err = imageRegistry.FillSecret(secretMap)
209+
if err != nil {
210+
return fmt.Errorf("loadRegistrySecret failed to fill registry secret with err %v", err)
211+
}
212+
return nil
213+
}
214+
215+
func (actionHandler *ActionHandler) loadRegistryFromSessionObj(sessionObj *utils.SessionObj) (apitypes.ContainerImageRegistry, error) {
216+
regInfo := sessionObj.Command.Args[apitypes.RegistryInfoArgKey].(map[string]interface{})
217+
regInfoBytes, err := json.Marshal(regInfo)
218+
if err != nil {
219+
return nil, fmt.Errorf("scanRegistriesV2 failed to marshal command arg with err %v", err)
220+
}
221+
imageRegistry, err := apitypes.UnmarshalRegistry(regInfoBytes)
222+
if err != nil {
223+
return nil, fmt.Errorf("scanRegistriesV2 failed to unmarshal command with err %v", err)
224+
}
225+
return imageRegistry, nil
226+
}
227+
228+
func (actionHandler *ActionHandler) getRegistryImageScanCommands(sessionObj *utils.SessionObj, client interfaces.RegistryClient, imageRegistry apitypes.ContainerImageRegistry, images map[string]string) []*apis.RegistryScanCommand {
229+
registryScanCMDList := make([]*apis.RegistryScanCommand, 0, len(images))
230+
for image, tag := range images {
231+
repository := image
232+
parts := strings.Split(image, "/")
233+
if len(parts) > 1 {
234+
repository = parts[1]
235+
}
236+
registryScanCommand := &apis.ImageScanParams{
237+
ParentJobID: sessionObj.Reporter.GetJobID(),
238+
JobID: uuid.NewString(),
239+
ImageTag: image + ":" + tag,
240+
Session: apis.SessionChain{ActionTitle: "vulnerability-scan", JobIDs: make([]string, 0), Timestamp: sessionObj.Reporter.GetTimestamp()},
241+
Args: map[string]interface{}{
242+
identifiers.AttributeRegistryName: imageRegistry.GetDisplayName(),
243+
identifiers.AttributeRepository: repository,
244+
identifiers.AttributeTag: tag,
245+
identifiers.AttributeUseHTTP: false,
246+
identifiers.AttributeSkipTLSVerify: false,
247+
identifiers.AttributeSensor: imageRegistry.GetBase().ClusterName,
248+
},
249+
}
250+
registryScanCommand.Credentialslist = append(registryScanCommand.Credentialslist, *client.GetDockerAuth())
251+
registryScanCMDList = append(registryScanCMDList, &apis.RegistryScanCommand{
252+
ImageScanParams: *registryScanCommand,
253+
})
254+
}
255+
return registryScanCMDList
256+
}
257+
159258
func (actionHandler *ActionHandler) loadRegistryScan(ctx context.Context, sessionObj *utils.SessionObj) (*registryScan, error) {
160259
registryScan := NewRegistryScan(actionHandler.config, actionHandler.k8sAPI)
161260
if regName, authMethodType := actionHandler.parseRegistryName(sessionObj); regName != "" {

watcher/registryhandler.go

+62-30
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import (
66
"fmt"
77
"github.com/armosec/armoapi-go/apis"
88
"github.com/armosec/armoapi-go/armotypes"
9+
"github.com/armosec/registryx/registryclients"
910
"github.com/kubescape/backend/pkg/command"
1011
"github.com/kubescape/backend/pkg/command/types/v1alpha1"
1112
"github.com/kubescape/go-logger"
1213
"github.com/kubescape/go-logger/helpers"
1314
"github.com/kubescape/k8s-interface/k8sinterface"
15+
"golang.org/x/sync/errgroup"
1416
batchv1 "k8s.io/api/batch/v1"
1517
v1 "k8s.io/api/core/v1"
1618
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -130,9 +132,25 @@ func (ch *RegistryCommandsHandler) patchCommandStatus(command *v1alpha1.Operator
130132
logger.L().Info("patchCommandStatus: command status patched successfully")
131133
}
132134

133-
func (ch *RegistryCommandsHandler) checkRegistry(_ v1alpha1.OperatorCommand) ([]byte, error) {
134-
mockResponse := []string{"mockRepo1", "mockRepo2", "mockRepo3"}
135-
payload, err := json.Marshal(mockResponse)
135+
func (ch *RegistryCommandsHandler) checkRegistry(cmd v1alpha1.OperatorCommand) ([]byte, error) {
136+
registry, err := armotypes.UnmarshalRegistry(cmd.Spec.Body)
137+
if err != nil {
138+
logger.L().Error("checkRegistry - failed to unmarshal command payload", helpers.Error(err))
139+
return nil, err
140+
}
141+
client, err := registryclients.GetRegistryClient(registry)
142+
if err != nil {
143+
logger.L().Error("checkRegistry - failed to get registry client", helpers.Error(err))
144+
return nil, err
145+
}
146+
147+
repositories, err := client.GetAllRepositories(context.Background())
148+
if err != nil {
149+
logger.L().Error("checkRegistry - failed to get registry repositories", helpers.Error(err))
150+
return nil, err
151+
}
152+
153+
payload, err := json.Marshal(repositories)
136154
if err != nil {
137155
return nil, err
138156
}
@@ -173,34 +191,48 @@ func (ch *RegistryCommandsHandler) upsertRegistry(cmd v1alpha1.OperatorCommand)
173191
logger.L().Error("upsertRegistry - failed to unmarshal command payload", helpers.Error(err))
174192
return err
175193
}
194+
errGroup := errgroup.Group{}
195+
errGroup.Go(func() error {
196+
secret, err := createSecretObject(registry)
197+
if err != nil {
198+
logger.L().Error("upsertRegistry - failed to create secret resource", helpers.Error(err))
199+
return err
200+
}
201+
if err = ch.upsertResource(secret, secretGVR, secret.Name); err != nil {
202+
logger.L().Error("upsertRegistry - failed to upsert secret resource", helpers.Error(err))
203+
return err
204+
}
205+
return nil
206+
})
207+
208+
errGroup.Go(func() error {
209+
configMap, err := createConfigMapObject(registry)
210+
if err != nil {
211+
logger.L().Error("upsertRegistry - failed to create config map resource", helpers.Error(err))
212+
return err
213+
}
214+
if err = ch.upsertResource(configMap, configMapGVR, configMap.Name); err != nil {
215+
logger.L().Error("upsertRegistry - failed to upsert config map resource", helpers.Error(err))
216+
return err
217+
}
218+
return nil
219+
})
220+
221+
errGroup.Go(func() error {
222+
cronJob, err := createCronJobObject(ch.k8sAPI, registry)
223+
if err != nil {
224+
logger.L().Error("upsertRegistry - failed to create cron job resource", helpers.Error(err))
225+
return err
226+
}
227+
if err = ch.upsertResource(cronJob, cronJobGVR, cronJob.Name); err != nil {
228+
logger.L().Error("upsertRegistry - failed to upsert cron job resource", helpers.Error(err))
229+
return err
230+
}
231+
return nil
232+
})
176233

177-
secret, err := createSecretObject(registry)
178-
if err != nil {
179-
logger.L().Error("upsertRegistry - failed to create secret resource", helpers.Error(err))
180-
return err
181-
}
182-
if err = ch.upsertResource(secret, secretGVR, secret.Name); err != nil {
183-
logger.L().Error("upsertRegistry - failed to upsert secret resource", helpers.Error(err))
184-
return err
185-
}
186-
187-
configMap, err := createConfigMapObject(registry)
188-
if err != nil {
189-
logger.L().Error("upsertRegistry - failed to create config map resource", helpers.Error(err))
190-
return err
191-
}
192-
if err = ch.upsertResource(configMap, configMapGVR, configMap.Name); err != nil {
193-
logger.L().Error("upsertRegistry - failed to upsert config map resource", helpers.Error(err))
194-
return err
195-
}
196-
197-
cronJob, err := createCronJobObject(ch.k8sAPI, registry)
198-
if err != nil {
199-
logger.L().Error("upsertRegistry - failed to create cron job resource", helpers.Error(err))
200-
return err
201-
}
202-
if err = ch.upsertResource(cronJob, cronJobGVR, cronJob.Name); err != nil {
203-
logger.L().Error("upsertRegistry - failed to upsert cron job resource", helpers.Error(err))
234+
if err := errGroup.Wait(); err != nil {
235+
logger.L().Error("upsertRegistry - failed to upsert registry", helpers.Error(err))
204236
return err
205237
}
206238

0 commit comments

Comments
 (0)