Skip to content

Commit

Permalink
Add support fo legacy dockercfg in scan jobs (#1183)
Browse files Browse the repository at this point in the history
Signed-off-by: alexey.makhonin <alexey.makhonin@flant.com>
  • Loading branch information
alex123012 committed Apr 27, 2023
1 parent 426c6e3 commit 773f8e3
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 15 deletions.
18 changes: 15 additions & 3 deletions pkg/docker/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,21 @@ type Config struct {
Auths map[string]Auth `json:"auths"`
}

func (c *Config) Read(contents []byte) error {
if err := json.Unmarshal(contents, c); err != nil {
return err
func (c *Config) Read(contents []byte, isLegacy bool) error {
if isLegacy {
// Because ~/.dockercfg contents is "auths" field in ~/.docker/config.json
// we can simply pass it to "Auths" field of Config
auths := make(map[string]Auth)
if err := json.Unmarshal(contents, &auths); err != nil {
return err
}
*c = Config{
Auths: auths,
}
} else {
if err := json.Unmarshal(contents, c); err != nil {
return err
}
}
var err error
c.Auths, err = decodeAuths(c.Auths)
Expand Down
30 changes: 28 additions & 2 deletions pkg/docker/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ func TestConfig_Read(t *testing.T) {

expectedAuth map[string]docker.Auth
expectedError error

isLegacy bool
}{
{
name: "Should return empty credentials when content is empty JSON object",
Expand Down Expand Up @@ -92,7 +94,7 @@ func TestConfig_Read(t *testing.T) {
givenJSON: `{
"auths": {
"https://index.docker.io/v1/": {
},
"harbor.domain": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
Expand All @@ -118,12 +120,36 @@ func TestConfig_Read(t *testing.T) {
}`,
expectedError: errors.New("expected username and password concatenated with a colon (:)"),
},
{
name: "Should process legacy .dockercfg json",
isLegacy: true,
givenJSON: `{
"https://index.docker.io/v1/": {
"auth": "ZG9ja2VyOmh1Yg=="
},
"harbor.domain": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
}
}`,
expectedAuth: map[string]docker.Auth{
"https://index.docker.io/v1/": {
Auth: "ZG9ja2VyOmh1Yg==",
Username: "docker",
Password: "hub",
},
"harbor.domain": {
Auth: "YWRtaW46SGFyYm9yMTIzNDU=",
Username: "admin",
Password: "Harbor12345",
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
dockerConfig := &docker.Config{}
err := dockerConfig.Read([]byte(tc.givenJSON))
err := dockerConfig.Read([]byte(tc.givenJSON), tc.isLegacy)
switch {
case tc.expectedError != nil:
assert.EqualError(t, err, tc.expectedError.Error())
Expand Down
24 changes: 15 additions & 9 deletions pkg/kube/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,28 @@ func matchSubDomain(wildcardServers []string, subDomain string) string {
func MapDockerRegistryServersToAuths(imagePullSecrets []corev1.Secret, multiSecretSupport bool) (map[string]docker.Auth, error) {
auths := make(map[string]docker.Auth)
for _, secret := range imagePullSecrets {
// Skip a deprecated secret of type "kubernetes.io/dockercfg" which contains a dockercfg file
// that follows the same format rules as ~/.dockercfg
// See https://docs.docker.com/engine/deprecated/#support-for-legacy-dockercfg-configuration-files
if secret.Type != corev1.SecretTypeDockerConfigJson {
var data []byte
var hasRequiredData, isLegacy bool

switch secret.Type {
case corev1.SecretTypeDockerConfigJson:
data, hasRequiredData = secret.Data[corev1.DockerConfigJsonKey]
case corev1.SecretTypeDockercfg:
data, hasRequiredData = secret.Data[corev1.DockerConfigKey]
isLegacy = true
default:
continue
}
data, hasRequiredData := secret.Data[corev1.DockerConfigJsonKey]
// Skip a secrets of type "kubernetes.io/dockerconfigjson" which does not contain
// the required ".dockerconfigjson" key.

// Skip a secrets of type "kubernetes.io/dockerconfigjson" or "kubernetes.io/dockercfg" which does not contain
// the required ".dockerconfigjson" or ".dockercfg" key.
if !hasRequiredData {
continue
}
dockerConfig := &docker.Config{}
err := dockerConfig.Read(data)
err := dockerConfig.Read(data, isLegacy)
if err != nil {
return nil, fmt.Errorf("reading %s field of %q secret: %w", corev1.DockerConfigJsonKey, secret.Namespace+"/"+secret.Name, err)
return nil, fmt.Errorf("reading %s or %s field of %q secret: %w", corev1.DockerConfigJsonKey, corev1.DockerConfigKey, secret.Namespace+"/"+secret.Name, err)
}
for authKey, auth := range dockerConfig.Auths {
server, err := docker.GetServerFromDockerAuthKey(authKey)
Expand Down
13 changes: 12 additions & 1 deletion pkg/kube/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,13 @@ func TestMapDockerRegistryServersToAuths(t *testing.T) {
auths, err := kube.MapDockerRegistryServersToAuths([]corev1.Secret{
{
Type: corev1.SecretTypeDockercfg,
Data: map[string][]byte{},
Data: map[string][]byte{
corev1.DockerConfigKey: []byte(`{
"quay.io": {
"auth": "dXNlcjpBZG1pbjEyMzQ1"
}
}`),
},
},
{
Type: corev1.SecretTypeDockerConfigJson,
Expand All @@ -96,6 +102,11 @@ func TestMapDockerRegistryServersToAuths(t *testing.T) {
Username: "root",
Password: "s3cret",
}),
"quay.io": Equal(docker.Auth{
Auth: "dXNlcjpBZG1pbjEyMzQ1",
Username: "user",
Password: "Admin12345",
}),
}))
})

Expand Down

0 comments on commit 773f8e3

Please sign in to comment.