Docker auth (#891)
* feat: read docker credentials from local docker config * fix: url.Parse requires protocol Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de> * fix: docker decides by the existence of . or : if... ... the image is in a custom registry or not. Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de> * fix: make docker hostname detection more robust * test: mock docker config for getImagePullOptions test By default github actions have a docker config set with a token to pull images from docker hub. Co-authored-by: Markus Wolf <markus.wolf@new-work.se> Co-authored-by: Markus Wolf <markus.wolf@new-work.se>
This commit is contained in:
parent
5bdb9ed0fd
commit
b910a42edf
1
go.sum
1
go.sum
|
@ -408,6 +408,7 @@ github.com/docker/docker v20.10.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05b
|
|||
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM=
|
||||
github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/docker/cli/cli/config/credentials"
|
||||
"github.com/docker/docker/api/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func LoadDockerAuthConfig(image string) (types.AuthConfig, error) {
|
||||
config, err := config.Load(config.Dir())
|
||||
if err != nil {
|
||||
log.Warnf("Could not load docker config: %v", err)
|
||||
return types.AuthConfig{}, err
|
||||
}
|
||||
|
||||
if !config.ContainsAuth() {
|
||||
config.CredentialsStore = credentials.DetectDefaultStore(config.CredentialsStore)
|
||||
}
|
||||
|
||||
hostName := "index.docker.io"
|
||||
index := strings.IndexRune(image, '/')
|
||||
if index > -1 && (strings.ContainsAny(image[:index], ".:") || image[:index] == "localhost") {
|
||||
hostName = image[:index]
|
||||
}
|
||||
|
||||
authConfig, err := config.GetAuthConfig(hostName)
|
||||
if err != nil {
|
||||
log.Warnf("Could not get auth config from docker config: %v", err)
|
||||
return types.AuthConfig{}, err
|
||||
}
|
||||
|
||||
return types.AuthConfig(authConfig), nil
|
||||
}
|
|
@ -77,6 +77,7 @@ func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput)
|
|||
imagePullOptions := types.ImagePullOptions{
|
||||
Platform: input.Platform,
|
||||
}
|
||||
|
||||
if input.Username != "" && input.Password != "" {
|
||||
logger := common.Logger(ctx)
|
||||
logger.Debugf("using authentication for docker pull")
|
||||
|
@ -91,6 +92,21 @@ func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput)
|
|||
return imagePullOptions, err
|
||||
}
|
||||
|
||||
imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
} else {
|
||||
authConfig, err := LoadDockerAuthConfig(input.Image)
|
||||
if err != nil {
|
||||
return imagePullOptions, err
|
||||
}
|
||||
if authConfig.Username == "" && authConfig.Password == "" {
|
||||
return imagePullOptions, nil
|
||||
}
|
||||
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return imagePullOptions, err
|
||||
}
|
||||
|
||||
imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/cli/config"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
assert "github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -35,9 +37,11 @@ func TestCleanImage(t *testing.T) {
|
|||
func TestGetImagePullOptions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
config.SetDir("/non-existent/docker")
|
||||
|
||||
options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{})
|
||||
assert.Nil(t, err, "Failed to create ImagePullOptions")
|
||||
assert.Equal(t, options.RegistryAuth, "", "RegistryAuth should be empty if no username or password is set")
|
||||
assert.Equal(t, "", options.RegistryAuth, "RegistryAuth should be empty if no username or password is set")
|
||||
|
||||
options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{
|
||||
Image: "",
|
||||
|
@ -45,5 +49,13 @@ func TestGetImagePullOptions(t *testing.T) {
|
|||
Password: "password",
|
||||
})
|
||||
assert.Nil(t, err, "Failed to create ImagePullOptions")
|
||||
assert.Equal(t, options.RegistryAuth, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", "Username and Password should be provided")
|
||||
assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", options.RegistryAuth, "Username and Password should be provided")
|
||||
|
||||
config.SetDir("testdata/docker-pull-options")
|
||||
|
||||
options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{
|
||||
Image: "nektos/act",
|
||||
})
|
||||
assert.Nil(t, err, "Failed to create ImagePullOptions")
|
||||
assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZFxuIiwic2VydmVyYWRkcmVzcyI6Imh0dHBzOi8vaW5kZXguZG9ja2VyLmlvL3YxLyJ9", options.RegistryAuth, "RegistryAuth should be taken from local docker config")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "dXNlcm5hbWU6cGFzc3dvcmQK"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue