Add custom docker registry authentication (#665)
* Add custom docker registry authentication Uses DOCKER_USERNAME and DOCKER_PASSWORD as secrets provided into the act cli. Closes #527 Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de> * Add test to check if pull authentication is filled in * Update debug message to be more descriptive Co-authored-by: Ryan (hackercat) <me@hackerc.at> Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de> Co-authored-by: Ryan (hackercat) <me@hackerc.at>
This commit is contained in:
parent
616d7fcaeb
commit
710a3ac94c
|
@ -2,6 +2,8 @@ package container
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -17,6 +19,8 @@ type NewDockerPullExecutorInput struct {
|
|||
Image string
|
||||
ForcePull bool
|
||||
Platform string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// NewDockerPullExecutor function to create a run executor for the container
|
||||
|
@ -54,9 +58,13 @@ func NewDockerPullExecutor(input NewDockerPullExecutorInput) common.Executor {
|
|||
return err
|
||||
}
|
||||
|
||||
reader, err := cli.ImagePull(ctx, imageRef, types.ImagePullOptions{
|
||||
Platform: input.Platform,
|
||||
})
|
||||
imagePullOptions, err := getImagePullOptions(ctx, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader, err := cli.ImagePull(ctx, imageRef, imagePullOptions)
|
||||
|
||||
_ = logDockerResponse(logger, reader, err != nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -65,6 +73,30 @@ func NewDockerPullExecutor(input NewDockerPullExecutorInput) common.Executor {
|
|||
}
|
||||
}
|
||||
|
||||
func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput) (types.ImagePullOptions, error) {
|
||||
imagePullOptions := types.ImagePullOptions{
|
||||
Platform: input.Platform,
|
||||
}
|
||||
if input.Username != "" && input.Password != "" {
|
||||
logger := common.Logger(ctx)
|
||||
logger.Debugf("using authentication for docker pull")
|
||||
|
||||
authConfig := types.AuthConfig{
|
||||
Username: input.Username,
|
||||
Password: input.Password,
|
||||
}
|
||||
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return imagePullOptions, err
|
||||
}
|
||||
|
||||
imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
}
|
||||
|
||||
return imagePullOptions, nil
|
||||
}
|
||||
|
||||
func cleanImage(image string) string {
|
||||
imageParts := len(strings.Split(image, "/"))
|
||||
if imageParts == 1 {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -27,3 +28,19 @@ func TestCleanImage(t *testing.T) {
|
|||
assert.Equal(t, table.imageOut, imageOut)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetImagePullOptions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{})
|
||||
assert.NilError(t, err, "Failed to create ImagePullOptions")
|
||||
assert.Equal(t, options.RegistryAuth, "", "RegistryAuth should be empty if no username or password is set")
|
||||
|
||||
options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{
|
||||
Image: "",
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
})
|
||||
assert.NilError(t, err, "Failed to create ImagePullOptions")
|
||||
assert.Equal(t, options.RegistryAuth, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", "Username and Password should be provided")
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ import (
|
|||
// NewContainerInput the input for the New function
|
||||
type NewContainerInput struct {
|
||||
Image string
|
||||
Username string
|
||||
Password string
|
||||
Entrypoint []string
|
||||
Cmd []string
|
||||
WorkingDir string
|
||||
|
@ -126,6 +128,8 @@ func (cr *containerReference) Pull(forcePull bool) common.Executor {
|
|||
Image: cr.input.Image,
|
||||
ForcePull: forcePull,
|
||||
Platform: cr.input.Platform,
|
||||
Username: cr.input.Username,
|
||||
Password: cr.input.Password,
|
||||
})
|
||||
}
|
||||
func (cr *containerReference) Copy(destPath string, files ...*FileEntry) common.Executor {
|
||||
|
|
|
@ -118,6 +118,8 @@ func (rc *RunContext) startJobContainer() common.Executor {
|
|||
Entrypoint: []string{"/usr/bin/tail", "-f", "/dev/null"},
|
||||
WorkingDir: rc.Config.ContainerWorkdir(),
|
||||
Image: image,
|
||||
Username: rc.Config.Secrets["DOCKER_USERNAME"],
|
||||
Password: rc.Config.Secrets["DOCKER_PASSWORD"],
|
||||
Name: name,
|
||||
Env: envList,
|
||||
Mounts: mounts,
|
||||
|
|
|
@ -247,6 +247,8 @@ func (sc *StepContext) newStepContainer(ctx context.Context, image string, cmd [
|
|||
Entrypoint: entrypoint,
|
||||
WorkingDir: rc.Config.ContainerWorkdir(),
|
||||
Image: image,
|
||||
Username: rc.Config.Secrets["DOCKER_USERNAME"],
|
||||
Password: rc.Config.Secrets["DOCKER_PASSWORD"],
|
||||
Name: createContainerName(rc.jobContainerName(), step.ID),
|
||||
Env: envList,
|
||||
Mounts: mounts,
|
||||
|
|
Loading…
Reference in New Issue