Skip to content

Commit

Permalink
feat: multi secret support (#1008)
Browse files Browse the repository at this point in the history
* feat: multi secret support

Signed-off-by: chenk <[email protected]>

* feat: multi secret support

Signed-off-by: chenk <[email protected]>

* feat: multi secret support

Signed-off-by: chenk <[email protected]>

---------

Signed-off-by: chenk <[email protected]>
  • Loading branch information
chen-keinan authored Mar 3, 2023
1 parent d4f25bb commit c6dc804
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 14 deletions.
20 changes: 13 additions & 7 deletions pkg/kube/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (

// MapContainerNamesToDockerAuths creates the mapping from a container name to the Docker authentication
// credentials for the specified kube.ContainerImages and image pull Secrets.
func MapContainerNamesToDockerAuths(images ContainerImages, secrets []corev1.Secret) (map[string]docker.Auth, error) {
auths, wildcardServers, err := MapDockerRegistryServersToAuths(secrets)
func MapContainerNamesToDockerAuths(images ContainerImages, secrets []corev1.Secret, multiSecretSupport bool) (map[string]docker.Auth, error) {
auths, wildcardServers, err := MapDockerRegistryServersToAuths(secrets, multiSecretSupport)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -53,7 +53,7 @@ func matchSubDomain(wildcardServers []string, subDomain string) string {

// MapDockerRegistryServersToAuths creates the mapping from a Docker registry server
// to the Docker authentication credentials for the specified slice of image pull Secrets.
func MapDockerRegistryServersToAuths(imagePullSecrets []corev1.Secret) (map[string]docker.Auth, []string, error) {
func MapDockerRegistryServersToAuths(imagePullSecrets []corev1.Secret, multiSecretSupport bool) (map[string]docker.Auth, []string, error) {
auths := make(map[string]docker.Auth)
wildcardServers := make([]string, 0)
for _, secret := range imagePullSecrets {
Expand All @@ -79,7 +79,13 @@ func MapDockerRegistryServersToAuths(imagePullSecrets []corev1.Secret) (map[stri
if err != nil {
return nil, nil, err
}
auths[server] = auth
if a, ok := auths[server]; multiSecretSupport && ok {
user := fmt.Sprintf("%s,%s", a.Username, auth.Username)
pass := fmt.Sprintf("%s,%s", a.Password, auth.Password)
auths[server] = docker.Auth{Username: user, Password: pass}
} else {
auths[server] = auth
}
if strings.HasPrefix(server, "*.") {
wildcardServers = append(wildcardServers, server)
}
Expand Down Expand Up @@ -109,7 +115,7 @@ const (
type SecretsReader interface {
ListByLocalObjectReferences(ctx context.Context, refs []corev1.LocalObjectReference, ns string) ([]corev1.Secret, error)
ListImagePullSecretsByPodSpec(ctx context.Context, spec corev1.PodSpec, ns string) ([]corev1.Secret, error)
CredentialsByWorkloadAndEnv(ctx context.Context, workload client.Object, secretsInfo map[string]string) (map[string]docker.Auth, error)
CredentialsByWorkloadAndEnv(ctx context.Context, workload client.Object, secretsInfo map[string]string, multiSecretSupport bool) (map[string]docker.Auth, error)
}

// NewSecretsReader constructs a new SecretsReader which is using the client
Expand Down Expand Up @@ -193,7 +199,7 @@ func (r *secretsReader) GetSecretsFromEnv(ctx context.Context, secretsInfo map[s
return secretsFromEnv, nil
}

func (r *secretsReader) CredentialsByWorkloadAndEnv(ctx context.Context, workload client.Object, secretsInfo map[string]string) (map[string]docker.Auth, error) {
func (r *secretsReader) CredentialsByWorkloadAndEnv(ctx context.Context, workload client.Object, secretsInfo map[string]string, multiSecretSupport bool) (map[string]docker.Auth, error) {
spec, err := GetPodSpec(workload)
if err != nil {
return nil, fmt.Errorf("getting Pod template: %w", err)
Expand All @@ -208,5 +214,5 @@ func (r *secretsReader) CredentialsByWorkloadAndEnv(ctx context.Context, workloa
}
imagePullSecrets = append(imagePullSecrets, secretsFromEnv...)

return MapContainerNamesToDockerAuths(GetContainerImagesFromPodSpec(spec), imagePullSecrets)
return MapContainerNamesToDockerAuths(GetContainerImagesFromPodSpec(spec), imagePullSecrets, multiSecretSupport)
}
41 changes: 36 additions & 5 deletions pkg/kube/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestMapDockerRegistryServersToAuths(t *testing.T) {
}`),
},
},
})
}, false)
g.Expect(err).ToNot(HaveOccurred())
assert.Equal(t, len(wildcardServers), 1)
g.Expect(auths).To(MatchAllKeys(Keys{
Expand Down Expand Up @@ -85,7 +85,7 @@ func TestMapDockerRegistryServersToAuths(t *testing.T) {
}`),
},
},
})
}, false)

g.Expect(err).ToNot(HaveOccurred())
assert.Equal(t, len(wildcardServers), 0)
Expand Down Expand Up @@ -119,7 +119,7 @@ func TestMapDockerRegistryServersToAuths(t *testing.T) {

auths, err := kube.MapContainerNamesToDockerAuths(kube.ContainerImages{
"container-1": "quay.io/my-company/my-service:2.0",
}, foundsecret)
}, foundsecret, false)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(auths).To(MatchAllKeys(Keys{
"container-1": Equal(docker.Auth{
Expand All @@ -129,6 +129,37 @@ func TestMapDockerRegistryServersToAuths(t *testing.T) {
}),
}))
})
t.Run("Test with service account and secret with same registry domain should map container images to Docker authentication credentials from Pod secret with multi secret support", func(t *testing.T) {
g := NewGomegaWithT(t)

var saSecret corev1.Secret
err := loadResource("./testdata/fixture/sa_secret_same_domain.json", &saSecret)
require.NoError(t, err)
var secret corev1.Secret
err = loadResource("./testdata/fixture/secret_same_domain.json", &secret)
require.NoError(t, err)
var sa corev1.ServiceAccount
err = loadResource("./testdata/fixture/sa_with_image_pull_secret_same_domain.json", &sa)
require.NoError(t, err)
client := fake.NewClientBuilder().WithScheme(trivyoperator.NewScheme()).WithObjects(&saSecret).WithObjects(&secret).WithObjects(&sa).Build()
sr := kube.NewSecretsReader(client)
spec := corev1.PodSpec{ImagePullSecrets: []corev1.LocalObjectReference{{Name: "regcred"}, {Name: "notexist"}}, ServiceAccountName: "default"}
foundsecret, err := sr.ListImagePullSecretsByPodSpec(context.Background(), spec, "default")
require.NoError(t, err)
assert.True(t, len(foundsecret) == 2)

auths, err := kube.MapContainerNamesToDockerAuths(kube.ContainerImages{
"container-1": "quay.io/my-company/my-service:2.0",
}, foundsecret, true)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(auths).To(MatchAllKeys(Keys{
"container-1": Equal(docker.Auth{
Auth: "",
Username: "root,user",
Password: "s3cret,Admin12345",
}),
}))
})
}

func TestMapContainerNamesToDockerAuths(t *testing.T) {
Expand Down Expand Up @@ -164,7 +195,7 @@ func TestMapContainerNamesToDockerAuths(t *testing.T) {
}`),
},
},
})
}, false)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(auths).To(MatchAllKeys(Keys{
"container-1": Equal(docker.Auth{
Expand Down Expand Up @@ -202,7 +233,7 @@ func TestMapContainerNamesToDockerAuths(t *testing.T) {
}`),
},
},
})
}, false)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(auths).To(MatchAllKeys(Keys{
"container-1": Equal(docker.Auth{
Expand Down
13 changes: 13 additions & 0 deletions pkg/plugins/trivy/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,16 @@ func SkipDBUpdate(c Config) string {
}
return "--skip-db-update"
}

// MultiSecretSupport validate if trivy multi secret support
func MultiSecretSupport(c Config) bool {
tag, err := c.GetImageTag()
if err != nil {
return true
}
// support backward competability with older tags
if compareTagVersion(tag, "< 0.38.0") {
return false
}
return true
}
9 changes: 7 additions & 2 deletions pkg/vulnerabilityreport/controller/workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/aquasecurity/trivy-operator/pkg/operator/jobs"
. "github.com/aquasecurity/trivy-operator/pkg/operator/predicate"
"github.com/aquasecurity/trivy-operator/pkg/operator/workload"
"github.com/aquasecurity/trivy-operator/pkg/plugins/trivy"
"github.com/aquasecurity/trivy-operator/pkg/trivyoperator"
"github.com/aquasecurity/trivy-operator/pkg/vulnerabilityreport"
"github.com/go-logr/logr"
Expand Down Expand Up @@ -225,8 +226,12 @@ func (r *WorkloadController) submitScanJob(ctx context.Context, owner client.Obj
if err != nil {
return err
}

credentials, err = r.CredentialsByWorkloadAndEnv(ctx, owner, privateRegistrySecrets)
pConfig, err := r.PluginContext.GetConfig()
if err != nil {
return err
}
multiSecretSupport := trivy.MultiSecretSupport(trivy.Config{PluginConfig: pConfig})
credentials, err = r.CredentialsByWorkloadAndEnv(ctx, owner, privateRegistrySecrets, multiSecretSupport)
if err != nil {
return err
}
Expand Down

0 comments on commit c6dc804

Please sign in to comment.