Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions cmd/drone-docker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,21 @@ func main() {
Usage: "docker password",
EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD",
},
cli.StringFlag{
Name: "docker.baseimageusername",
Usage: "Docker username for base image registry",
EnvVar: "PLUGIN_DOCKER_USERNAME,PLUGIN_BASE_IMAGE_USERNAME,DOCKER_BASE_IMAGE_USERNAME",
},
cli.StringFlag{
Name: "docker.baseimagepassword",
Usage: "Docker password for base image registry",
EnvVar: "PLUGIN_DOCKER_PASSWORD,PLUGIN_BASE_IMAGE_PASSWORD,DOCKER_BASE_IMAGE_PASSWORD",
},
cli.StringFlag{
Name: "docker.baseimageregistry",
Usage: "Docker registry for base image registry",
EnvVar: "PLUGIN_DOCKER_REGISTRY,PLUGIN_BASE_IMAGE_REGISTRY,DOCKER_BASE_IMAGE_REGISTRY",
},
cli.StringFlag{
Name: "docker.email",
Usage: "docker email",
Expand Down Expand Up @@ -367,6 +382,9 @@ func run(c *cli.Context) error {
Experimental: c.Bool("daemon.experimental"),
RegistryType: registryType,
},
BaseImageRegistry: c.String("docker.baseimageregistry"),
BaseImageUsername: c.String("docker.baseimageusername"),
BaseImagePassword: c.String("docker.baseimagepassword"),
}

if c.Bool("tags.auto") {
Expand Down
74 changes: 66 additions & 8 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"time"

"github.com/drone-plugins/drone-docker/internal/docker"
"github.com/drone-plugins/drone-plugin-lib/drone"
)

Expand Down Expand Up @@ -75,13 +76,16 @@ type (

// Plugin defines the Docker plugin parameters.
Plugin struct {
Login Login // Docker login configuration
Build Build // Docker build configuration
Daemon Daemon // Docker daemon configuration
Dryrun bool // Docker push is skipped
Cleanup bool // Docker purge is enabled
CardPath string // Card path to write file to
ArtifactFile string // Artifact path to write file to
Login Login // Docker login configuration
Build Build // Docker build configuration
Daemon Daemon // Docker daemon configuration
Dryrun bool // Docker push is skipped
Cleanup bool // Docker purge is enabled
CardPath string // Card path to write file to
ArtifactFile string // Artifact path to write file to
BaseImageRegistry string // Docker registry to pull base image
BaseImageUsername string // Docker registry username to pull base image
BaseImagePassword string // Docker registry password to pull base image
}

Card []struct {
Expand Down Expand Up @@ -154,7 +158,32 @@ func (p Plugin) Exec() error {
os.MkdirAll(dockerHome, 0600)

path := filepath.Join(dockerHome, "config.json")
err := os.WriteFile(path, []byte(p.Login.Config), 0600)
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return fmt.Errorf("Error writing config.json: %s", err)
}
err = os.WriteFile(path, []byte(p.Login.Config), 0600)
if err != nil {
return fmt.Errorf("Error writing config.json: %s", err)
}
file.Close()
}

// add base image docker credentials to the existing config file, else create new
if p.BaseImagePassword != "" {
json, err := setDockerAuth(p.Login.Username, p.Login.Password, p.Login.Registry,
p.BaseImageUsername, p.BaseImagePassword, p.BaseImageRegistry)
if err != nil {
return fmt.Errorf("Failed to set authentication in docker config %s", err)
}
os.MkdirAll(dockerHome, 0600)
path := filepath.Join(dockerHome, "config.json")
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return fmt.Errorf("Error opening config.json: %s", err)
}
defer file.Close()
_, err = file.Write(json)
if err != nil {
return fmt.Errorf("Error writing config.json: %s", err)
}
Expand Down Expand Up @@ -270,6 +299,35 @@ func (p Plugin) Exec() error {
return nil
}

// helper function to set the credentials
func setDockerAuth(username, password, registry, baseImageUsername,
baseImagePassword, baseImageRegistry string) ([]byte, error) {
var credentials []docker.RegistryCredentials
// add only docker registry to the config
dockerConfig := docker.NewConfig()
if password != "" {
pushToRegistryCreds := docker.RegistryCredentials{
Registry: registry,
Username: username,
Password: password,
}
// push registry auth
credentials = append(credentials, pushToRegistryCreds)
}

if baseImageRegistry != "" {
pullFromRegistryCreds := docker.RegistryCredentials{
Registry: baseImageRegistry,
Username: baseImageUsername,
Password: baseImagePassword,
}
// base image registry auth
credentials = append(credentials, pullFromRegistryCreds)
}
// Creates docker config for both the registries used for authentication
return dockerConfig.CreateDockerConfigJson(credentials)
}

// helper function to create the docker login command.
func commandLogin(login Login) *exec.Cmd {
if login.Email != "" {
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743
github.com/joho/godotenv v1.3.0
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.1
github.com/urfave/cli v1.22.2
golang.org/x/oauth2 v0.13.0
)
Expand All @@ -17,13 +18,15 @@ require (
cloud.google.com/go/compute v1.23.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
Expand Down
71 changes: 71 additions & 0 deletions internal/docker/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package docker

import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strings"
)

const (
v2HubRegistryURL string = "https://registry.hub.docker.com/v2/"
v1RegistryURL string = "https://index.docker.io/v1/" // Default registry
v2RegistryURL string = "https://index.docker.io/v2/" // v2 registry is not supported
)

type (
Auth struct {
Auth string `json:"auth"`
}

Config struct {
Auths map[string]Auth `json:"auths"`
CredHelpers map[string]string `json:"credHelpers,omitempty"`
}
)

type RegistryCredentials struct {
Registry string
Username string
Password string
}

func NewConfig() *Config {
return &Config{
Auths: make(map[string]Auth),
CredHelpers: make(map[string]string),
}
}

func (c *Config) SetAuth(registry, username, password string) {
authBytes := []byte(username + ":" + password)
encodedString := base64.StdEncoding.EncodeToString(authBytes)
c.Auths[registry] = Auth{Auth: encodedString}
}

func (c *Config) SetCredHelper(registry, helper string) {
c.CredHelpers[registry] = helper
}

func (c *Config) CreateDockerConfigJson(credentials []RegistryCredentials) ([]byte, error) {
for _, cred := range credentials {
if cred.Registry != "" && strings.Contains(cred.Registry, "docker") {

if cred.Username == "" {
return nil, fmt.Errorf("Username must be specified for registry: %s", cred.Registry)
}
if cred.Password == "" {
return nil, fmt.Errorf("Password must be specified for registry: %s", cred.Registry)
}
c.SetAuth(cred.Registry, cred.Username, cred.Password)
}
}

jsonBytes, err := json.Marshal(c)
if err != nil {
return nil, errors.New("failed to serialize docker config json")
}

return jsonBytes, nil
}
64 changes: 64 additions & 0 deletions internal/docker/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package docker

import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

const (
RegistryV1 string = "https://index.docker.io/v1/"
RegistryV2 string = "https://index.docker.io/v2/"
RegistryECRPublic string = "public.ecr.aws"
)

func TestConfig(t *testing.T) {
c := NewConfig()
assert.NotNil(t, c.Auths)
assert.NotNil(t, c.CredHelpers)

c.SetAuth(RegistryV1, "test", "password")
expectedAuth := Auth{Auth: "dGVzdDpwYXNzd29yZA=="}
assert.Equal(t, expectedAuth, c.Auths[RegistryV1])

c.SetCredHelper(RegistryECRPublic, "ecr-login")
assert.Equal(t, "ecr-login", c.CredHelpers[RegistryECRPublic])

tempDir, err := ioutil.TempDir("", "docker-config-test")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)

credentials := []RegistryCredentials{
{
Registry: "https://index.docker.io/v1/",
Username: "user1",
Password: "pass1",
},
{
Registry: "gcr.io",
Username: "user2",
Password: "pass2",
},
}

jsonBytes, err := c.CreateDockerConfigJson(credentials)
assert.NoError(t, err)

configPath := filepath.Join(tempDir, "config.json")
err = ioutil.WriteFile(configPath, jsonBytes, 0644)
assert.NoError(t, err)

data, err := ioutil.ReadFile(configPath)
assert.NoError(t, err)

var configFromFile Config
err = json.Unmarshal(data, &configFromFile)
assert.NoError(t, err)

assert.Equal(t, c.Auths, configFromFile.Auths)
assert.Equal(t, c.CredHelpers, configFromFile.CredHelpers)
}