Skip to content

Commit

Permalink
acknoledge that imagePullSecrets contain multiple credentials
Browse files Browse the repository at this point in the history
Signed-off-by: Matthias Bertschy <[email protected]>
  • Loading branch information
matthyx committed Feb 4, 2025
1 parent 31815b7 commit caadb09
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 38 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ require (
github.com/gorilla/mux v1.8.1
github.com/kubescape/backend v0.0.26
github.com/kubescape/go-logger v0.0.23
github.com/kubescape/k8s-interface v0.0.183
github.com/kubescape/k8s-interface v0.0.184
github.com/kubescape/kubescape-network-scanner v0.0.15
github.com/kubescape/node-agent v0.2.152
github.com/kubescape/opa-utils v0.0.278
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -668,8 +668,8 @@ github.com/kubescape/backend v0.0.26 h1:3R77BF34s1Y1rmUTBsOwNJOqYtvXwq+48rAicos7
github.com/kubescape/backend v0.0.26/go.mod h1:FpazfN+c3Ucuvv4jZYCnk99moSBRNMVIxl5aWCZAEBo=
github.com/kubescape/go-logger v0.0.23 h1:5xh+Nm8eGImhFbtippRKLaFgsvlKE1ufvQhNM2P/570=
github.com/kubescape/go-logger v0.0.23/go.mod h1:Ayg7g769c7sXVB+P3fkJmbsJpoEmMmaUf9jeo+XuC3U=
github.com/kubescape/k8s-interface v0.0.183 h1:eTuHlKJkBYYA03AR/YGr4KUC+xnbV6SG0/8+yrt9Yrs=
github.com/kubescape/k8s-interface v0.0.183/go.mod h1:YjIAQtrK4nCy+XQ/6jwo+BqlLyJk7DN2Mx4pUcbzq10=
github.com/kubescape/k8s-interface v0.0.184 h1:GzqfD9ynIWYEFRuJWgeNSBCfWDHfurKU9eZBiTLHuN4=
github.com/kubescape/k8s-interface v0.0.184/go.mod h1:YjIAQtrK4nCy+XQ/6jwo+BqlLyJk7DN2Mx4pUcbzq10=
github.com/kubescape/kubescape-network-scanner v0.0.15 h1:LsaVCQzj0PbA30BeFdzxchW2bkg6nn5quwllWmm/2/s=
github.com/kubescape/kubescape-network-scanner v0.0.15/go.mod h1:fqTzRCWsuniGEEZHtOEdITxnqx+i5ICdOVuenSQJd3U=
github.com/kubescape/kubescape/v3 v3.0.4 h1:gZ5d8QMxLYZQ6Yz9wRvGcDQlBUIV+v/Y/41g56/YDy8=
Expand Down
9 changes: 7 additions & 2 deletions mainhandler/testdata/vulnscan/pod.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"spec": {
"containers": [
{
"image": "nginx:1.15",
"image": "private.docker.io/library/nginx:1.15",
"imagePullPolicy": "IfNotPresent",
"name": "nginx",
"ports": [
Expand All @@ -35,6 +35,11 @@
]
}
],
"imagePullSecrets": [
{
"name": "regcreds"
}
],
"dnsPolicy": "ClusterFirst",
"enableServiceLinks": true,
"nodeName": "minikube",
Expand Down Expand Up @@ -156,4 +161,4 @@
"qosClass": "BestEffort",
"startTime": "2023-02-13T15:25:52Z"
}
}
}
12 changes: 12 additions & 0 deletions mainhandler/testdata/vulnscan/regcreds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"apiVersion": "v1",
"kind": "Secret",
"type": "kubernetes.io/dockerconfigjson",
"data": {
".dockerconfigjson": "ewoJImF1dGhzIjogewoJCSJwcml2YXRlLmRvY2tlci5pbyI6IHsKICAgICAgICAgICAgInVzZXJuYW1lIjogIllXUnRhVzQ9IiwKICAgICAgICAgICAgInBhc3N3b3JkIjogIlNHRnlZbTl5TVRJek5EVT0iLAoJCQkiYXV0aCI6ICJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0iCgkJfSwKCQkiaHR0cHM6Ly9pbmRleC5kb2NrZXIuaW8vdjEvIjogewoJCQkiYXV0aCI6ICJiV0YwZEdoNWVEcDBiM1J2IgoJCX0KICAgIH0KfQ=="
},
"metadata": {
"name": "regcreds",
"namespace": "default"
}
}
4 changes: 2 additions & 2 deletions mainhandler/vulnscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,12 @@ func getImageScanConfig(k8sAPI *k8sinterface.KubernetesApi, namespace string, po
if pod != nil {
// TODO: this should not happen every scan
// build a list of secrets from the the registry secrets
secrets, err := cloudsupport.GetImageRegistryCredentials(imageTag, pod)
secrets, err := cloudsupport.GetImageRegistryCredentials(k8sAPI, imageTag, pod)
if err != nil {
return nil, err
}
for i := range secrets {
imageScanConfig.authConfigs = append(imageScanConfig.authConfigs, secrets[i])
imageScanConfig.authConfigs = append(imageScanConfig.authConfigs, secrets[i]...)
}
}

Expand Down
125 changes: 94 additions & 31 deletions mainhandler/vulnscan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,116 @@ package mainhandler

import (
"context"
_ "embed"
"encoding/json"
"fmt"
"os"
"testing"

_ "embed"

dockerregistry "github.com/docker/docker/api/types/registry"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
k8sfake "k8s.io/client-go/kubernetes/fake"
"k8s.io/utils/ptr"
)

//go:embed testdata/vulnscan/registry-secret.json
var registrySecret []byte
func fileToPod(filePath string) *corev1.Pod {
b, err := os.ReadFile(filePath)
if err != nil {
return nil
}
var pod *corev1.Pod
err = json.Unmarshal(b, &pod)
if err != nil {
return nil
}
return pod
}

func fileToSecret(filePath string) *corev1.Secret {
b, err := os.ReadFile(filePath)
if err != nil {
return nil
}
var secret *corev1.Secret
err = json.Unmarshal(b, &secret)
if err != nil {
return nil
}
return secret
}

func Test_ActionHandler_getImageScanConfig(t *testing.T) {
expectedAuthConfigs := []dockerregistry.AuthConfig{
type args struct {
namespace string
pod *corev1.Pod
imageTag string
}
tests := []struct {
name string
args args
objects []runtime.Object
want *ImageScanConfig
wantErr assert.ErrorAssertionFunc
}{
{
Username: "test-user",
Password: "test-pass",
ServerAddress: "docker.io",
name: "no registry treated as docker.io",
args: args{
imageTag: "nginx:latest",
},
objects: []runtime.Object{fileToSecret("testdata/vulnscan/registry-secret.json")},
want: &ImageScanConfig{
insecure: ptr.To(true),
authConfigs: []dockerregistry.AuthConfig{
{Username: "test-user", Password: "test-pass", ServerAddress: "docker.io"},
{Username: "test-user-quay", Password: "test-pass-quay", ServerAddress: "quay.io"},
},
},
wantErr: assert.NoError,
},
{
Username: "test-user-quay",
Password: "test-pass-quay",
ServerAddress: "quay.io",
name: "quay.IO",
args: args{
imageTag: "quay.IO/kubescape/nginx:latest",
},
objects: []runtime.Object{fileToSecret("testdata/vulnscan/registry-secret.json")},
want: &ImageScanConfig{
skipTLSVerify: ptr.To(true),
authConfigs: []dockerregistry.AuthConfig{
{Username: "test-user", Password: "test-pass", ServerAddress: "docker.io"},
{Username: "test-user-quay", Password: "test-pass-quay", ServerAddress: "quay.io"},
},
},
wantErr: assert.NoError,
},
{
name: "pod with registry secret",
args: args{
pod: fileToPod("testdata/vulnscan/pod.json"),
},
objects: []runtime.Object{fileToSecret("testdata/vulnscan/regcreds.json")},
want: &ImageScanConfig{
authConfigs: []dockerregistry.AuthConfig{
{Username: "YWRtaW4=", Password: "SGFyYm9yMTIzNDU=", Auth: "YWRtaW46SGFyYm9yMTIzNDU=", ServerAddress: "private.docker.io"},
{Username: "matthyx", Password: "toto", Auth: "bWF0dGh5eDp0b3Rv", ServerAddress: "https://index.docker.io/v1/"},
},
},
wantErr: assert.NoError,
},
}

var secret *corev1.Secret
require.NoError(t, json.Unmarshal(registrySecret, &secret))

k8sApiMock := &k8sinterface.KubernetesApi{
Context: context.TODO(),
KubernetesClient: k8sfake.NewSimpleClientset(secret),
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
k8sApiMock := &k8sinterface.KubernetesApi{
Context: context.TODO(),
KubernetesClient: k8sfake.NewClientset(tt.objects...),
}
got, err := getImageScanConfig(k8sApiMock, tt.args.namespace, tt.args.pod, tt.args.imageTag)
if !tt.wantErr(t, err, fmt.Sprintf("getImageScanConfig(%v, %v, %v, %v)", k8sApiMock, tt.args.namespace, tt.args.pod, tt.args.imageTag)) {
return
}
assert.Equalf(t, tt.want, got, "getImageScanConfig(%v, %v, %v, %v)", k8sApiMock, tt.args.namespace, tt.args.pod, tt.args.imageTag)
})
}

res, err := getImageScanConfig(k8sApiMock, "", nil, "nginx:latest") // no registry treated as docker.io
assert.NoError(t, err)
assert.Equal(t, expectedAuthConfigs, res.authConfigs)
assert.True(t, *res.insecure)
assert.Nil(t, res.skipTLSVerify)

res, err = getImageScanConfig(k8sApiMock, "", nil, "quay.IO/kubescape/nginx:latest")
assert.NoError(t, err)
assert.Equal(t, expectedAuthConfigs, res.authConfigs)
assert.Nil(t, res.insecure)
assert.True(t, *res.skipTLSVerify)
}

0 comments on commit caadb09

Please sign in to comment.