support dockerhub credentials when pulling with kaniko-ecr (#27)

This commit is contained in:
Colin Hoglund 2021-09-16 00:42:03 -04:00 committed by GitHub
parent e86d4583a7
commit 609d203bed
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 153 additions and 24 deletions

@ -2,18 +2,20 @@ package main
import (
"context"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"io/ioutil"
"os"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ecr"
"github.com/aws/aws-sdk-go-v2/service/ecrpublic"
"github.com/aws/smithy-go"
kaniko "github.com/drone/drone-kaniko"
"github.com/drone/drone-kaniko/cmd/artifact"
"github.com/drone/drone-kaniko/pkg/docker"
"github.com/joho/godotenv"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -53,6 +55,16 @@ func main() {
Value: "Dockerfile",
EnvVar: "PLUGIN_DOCKERFILE",
},
cli.StringFlag{
Name: "docker-username",
Usage: "docker username",
EnvVar: "PLUGIN_USERNAME,DOCKER_USERNAME",
},
cli.StringFlag{
Name: "docker-password",
Usage: "docker password",
EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD",
},
cli.StringFlag{
Name: "context",
Usage: "build context",
@ -168,14 +180,27 @@ func run(c *cli.Context) error {
repo := c.String("repo")
registry := c.String("registry")
region := c.String("region")
accessKey := c.String("access-key")
noPush := c.Bool("no-push")
// only setup auth when pushing or credentials are defined
if !noPush || accessKey != "" {
if err := setupECRAuth(accessKey, c.String("secret-key"), registry); err != nil {
return err
}
dockerConfig, err := createDockerConfig(
c.String("docker-username"),
c.String("docker-password"),
c.String("access-key"),
c.String("secret-key"),
registry,
noPush,
)
if err != nil {
return err
}
jsonBytes, err := json.Marshal(dockerConfig)
if err != nil {
return err
}
if err := ioutil.WriteFile(dockerConfigPath, jsonBytes, 0644); err != nil {
return err
}
// only create repository when pushing and create-repository is true
@ -233,30 +258,37 @@ func run(c *cli.Context) error {
return plugin.Exec()
}
func setupECRAuth(accessKey, secretKey, registry string) error {
if registry == "" {
return fmt.Errorf("registry must be specified")
func createDockerConfig(dockerUsername, dockerPassword, accessKey, secretKey, registry string, noPush bool) (*docker.Config, error) {
dockerConfig := docker.NewConfig()
if dockerUsername != "" {
dockerConfig.SetAuth(docker.RegistryV1, dockerUsername, dockerPassword)
}
// If IAM role is used, access key & secret key are not required
if accessKey != "" && secretKey != "" {
err := os.Setenv(accessKeyEnv, accessKey)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to set %s environment variable", accessKeyEnv))
// only setup auth when pushing or credentials are defined
if !noPush || accessKey != "" {
if registry == "" {
return nil, fmt.Errorf("registry must be specified")
}
err = os.Setenv(secretKeyEnv, secretKey)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to set %s environment variable", secretKeyEnv))
// If IAM role is used, access key & secret key are not required
if accessKey != "" && secretKey != "" {
err := os.Setenv(accessKeyEnv, accessKey)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to set %s environment variable", accessKeyEnv))
}
err = os.Setenv(secretKeyEnv, secretKey)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to set %s environment variable", secretKeyEnv))
}
}
dockerConfig.SetCredHelper(ecrPublicDomain, "ecr-login")
dockerConfig.SetCredHelper(registry, "ecr-login")
}
jsonBytes := []byte(fmt.Sprintf(`{"credStore": "ecr-login", "credHelpers": {"%s": "ecr-login", "%s": "ecr-login"}}`, ecrPublicDomain, registry))
err := ioutil.WriteFile(dockerConfigPath, jsonBytes, 0644)
if err != nil {
return errors.Wrap(err, "failed to create docker config file")
}
return nil
return dockerConfig, nil
}
func createRepository(region, repo, registry string) error {

@ -0,0 +1,31 @@
package main
import (
"reflect"
"testing"
"github.com/drone/drone-kaniko/pkg/docker"
)
func TestCreateDockerConfig(t *testing.T) {
got, err := createDockerConfig(
"docker-username",
"docker-password",
"access-key",
"secret-key",
"ecr-registry",
false,
)
if err != nil {
t.Error("failed to create docker config")
}
want := docker.NewConfig()
want.SetAuth(docker.RegistryV1, "docker-username", "docker-password")
want.SetCredHelper(docker.RegistryECRPublic, "ecr-login")
want.SetCredHelper("ecr-registry", "ecr-login")
if !reflect.DeepEqual(want, got) {
t.Errorf("not equal:\n want: %#v\n got: %#v", want, got)
}
}

34
pkg/docker/config.go Normal file

@ -0,0 +1,34 @@
package docker
import (
"encoding/base64"
"fmt"
)
type (
Auth struct {
Auth string `json:"auth"`
}
Config struct {
Auths map[string]Auth `json:"auths"`
CredHelpers map[string]string `json:"credHelpers"`
}
)
func NewConfig() *Config {
return &Config{
Auths: map[string]Auth{},
CredHelpers: map[string]string{},
}
}
func (c *Config) SetAuth(registry, username, password string) {
authBytes := []byte(fmt.Sprintf("%s:%s", username, password))
encodedString := base64.StdEncoding.EncodeToString(authBytes)
c.Auths[registry] = Auth{Auth: encodedString}
}
func (c *Config) SetCredHelper(registry, helper string) {
c.CredHelpers[registry] = helper
}

25
pkg/docker/config_test.go Normal file

@ -0,0 +1,25 @@
package docker
import (
"encoding/json"
"testing"
)
func TestConfig(t *testing.T) {
c := NewConfig()
c.SetAuth(RegistryV1, "test", "password")
c.SetCredHelper(RegistryECRPublic, "ecr-login")
bytes, err := json.Marshal(c)
if err != nil {
t.Error("json marshal failed")
}
want := `{"auths":{"https://index.docker.io/v1/":{"auth":"dGVzdDpwYXNzd29yZA=="}},"credHelpers":{"public.ecr.aws":"ecr-login"}}`
got := string(bytes)
if want != got {
t.Errorf("unexpected json output:\n want: %s\n got: %s", want, got)
}
}

7
pkg/docker/constants.go Normal file

@ -0,0 +1,7 @@
package docker
const (
RegistryV1 string = "https://index.docker.io/v1/"
RegistryV2 string = "https://index.docker.io/v2/"
RegistryECRPublic string = "public.ecr.aws"
)