Skip to content

Commit

Permalink
fix: change legacy-support for .dockercfg
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Kotzbauer <[email protected]>
  • Loading branch information
ckotzbauer committed Feb 4, 2022
1 parent 92c41c6 commit 6519b66
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
10 changes: 6 additions & 4 deletions .github/workflows/test-registries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,21 @@ jobs:
--docker-email="${{ secrets.TEST_EMAIL }}" \
-o json --dry-run=client | jq -r '.data.".dockerconfigjson"' > auth/hub.yaml
- name: Prepare legacy Hub secrets
- name: Prepare legacy GHCR secrets
shell: bash
env:
TEST_GCR_PASSWORD: ${{ secrets.TEST_GCR_PASSWORD }}
run: |
cat << EOF > .dockercfg
{
"https://index.docker.io/v1/": { "username": "${{ secrets.TEST_HUB_USERNAME }}", "password": "${{ secrets.TEST_HUB_PASSWORD }}" }
"ghcr.io": { "username": "${{ secrets.TEST_GHCR_USERNAME }}", "password": "${{ secrets.TEST_GHCR_PASSWORD }}" }
}
EOF
kubectl create secret generic hub-secret \
kubectl create secret generic ghcr-secret \
--from-file=.dockercfg \
--type=kubernetes.io/dockercfg \
-o json --dry-run=client | jq -r '.data.".dockercfg"' > auth/legacy-hub.yaml
-o json --dry-run=client | jq -r '.data.".dockercfg"' > auth/legacy-ghcr.yaml
- name: Execute Registry-Tests
run: make test-registries
94 changes: 94 additions & 0 deletions internal/registry/configfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package registry

import (
"encoding/base64"
"encoding/json"
"io"
"io/ioutil"
"strings"

"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/types"
"github.com/pkg/errors"
)

// This is ported from https://github.com/docker/cli/blob/v20.10.12/cli/config/config.go
// The only changes to the original source are the fact, that the "auth" field is not decoded
// when "username" or "password" are not blank to avoid overwrites.

const (
// This constant is only used for really old config files when the
// URL wasn't saved as part of the config file and it was just
// assumed to be this value.
defaultIndexServer = "https://index.docker.io/v1/"
)

// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
// auth config information with given directory and populates the receiver object
func LegacyLoadFromReader(configData io.Reader, configFile *configfile.ConfigFile) error {
b, err := ioutil.ReadAll(configData)
if err != nil {
return err
}

if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return errors.Errorf("The Auth config file is empty")
}
authConfig := types.AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
if len(origAuth) != 2 {
return errors.Errorf("Invalid Auth config file")
}

// Only decode the "auth" field when "username" and "password" are blank.
if len(authConfig.Username) == 0 && len(authConfig.Password) == 0 {
authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
if err != nil {
return err
}
}

authConfig.ServerAddress = defaultIndexServer
configFile.AuthConfigs[defaultIndexServer] = authConfig
} else {
for k, authConfig := range configFile.AuthConfigs {
// Only decode the "auth" field when "username" and "password" are blank.
if len(authConfig.Username) == 0 && len(authConfig.Password) == 0 {
authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
if err != nil {
return err
}
}
authConfig.Auth = ""
authConfig.ServerAddress = k
configFile.AuthConfigs[k] = authConfig
}
}
return nil
}

// decodeAuth decodes a base64 encoded string and returns username and password
func decodeAuth(authStr string) (string, string, error) {
if authStr == "" {
return "", "", nil
}

decLen := base64.StdEncoding.DecodedLen(len(authStr))
decoded := make([]byte, decLen)
authByte := []byte(authStr)
n, err := base64.StdEncoding.Decode(decoded, authByte)
if err != nil {
return "", "", err
}
if n > decLen {
return "", "", errors.Errorf("Something went wrong decoding auth config")
}
arr := strings.SplitN(string(decoded), ":", 2)
if len(arr) != 2 {
return "", "", errors.Errorf("Invalid auth configuration file")
}
password := strings.Trim(arr[1], "\x00")
return arr[0], password, nil
}
2 changes: 1 addition & 1 deletion internal/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func SaveImage(imagePath string, image kubernetes.ContainerImage) error {

if image.LegacyAuth {
cf = configfile.New("")
err = cf.LegacyLoadFromReader(bytes.NewReader(image.Auth))
err = LegacyLoadFromReader(bytes.NewReader(image.Auth), cf)
} else {
cf, err = config.LoadFromReader(bytes.NewReader(image.Auth))
}
Expand Down
4 changes: 2 additions & 2 deletions internal/registry/registry_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ var _ = Describe("Registry", func() {
})
})

Describe("Storing image from DockerHub - legacy .dockercfg", func() {
Describe("Storing image from GHCR - legacy .dockercfg", func() {
It("should work correctly", func() {
testRegistry("legacy-hub", "docker.io/ckotzbauer/integration-test-image:1.0.0", true)
testRegistry("legacy-ghcr", "ghcr.io/ckotzbauer-kubernetes-bot/sbom-git-operator-integration-test:1.0.0", true)
})
})
})

0 comments on commit 6519b66

Please sign in to comment.