diff --git a/cmd/vela-worker/exec.go b/cmd/vela-worker/exec.go index 27893c11..6f7f562f 100644 --- a/cmd/vela-worker/exec.go +++ b/cmd/vela-worker/exec.go @@ -91,6 +91,9 @@ func (w *Worker) exec(index int, config *library.Worker) error { return err } + // set the outputs container ID + w.Config.Executor.OutputCtn.ID = fmt.Sprintf("outputs_%s", p.ID) + // create logger with extra metadata // // https://pkg.go.dev/github.com/sirupsen/logrus#WithFields @@ -165,8 +168,6 @@ func (w *Worker) exec(index int, config *library.Worker) error { return err } - w.Config.Executor.OutputCtn.ID = fmt.Sprintf("outputs_%s", p.ID) - // setup the executor // // https://godoc.org/github.com/go-vela/worker/executor#New diff --git a/docker-compose.yml b/docker-compose.yml index d756b38d..851544d1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,6 +33,7 @@ services: VELA_SERVER_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' WORKER_ADDR: 'http://worker:8080' WORKER_CHECK_IN: 2m + VELA_EXECUTOR_OUTPUTS_IMAGE: 'alpine:latest' restart: always ports: - "8081:8080" diff --git a/executor/engine.go b/executor/engine.go index f81b72d0..356c4ecb 100644 --- a/executor/engine.go +++ b/executor/engine.go @@ -86,7 +86,7 @@ type Engine interface { PlanStage(context.Context, *pipeline.Stage, *sync.Map) error // ExecStage defines a function that // runs a stage. - ExecStage(context.Context, *pipeline.Stage, *sync.Map) error + ExecStage(context.Context, *pipeline.Stage, *sync.Map, map[string]string, map[string]string) error // DestroyStage defines a function that // cleans up the stage after execution. DestroyStage(context.Context, *pipeline.Stage) error diff --git a/executor/linux/build.go b/executor/linux/build.go index 962cbee6..688e9e8a 100644 --- a/executor/linux/build.go +++ b/executor/linux/build.go @@ -138,7 +138,7 @@ func (c *client) PlanBuild(ctx context.Context) error { c.Logger.Info("creating volume") // create the runtime volume for the pipeline - c.workspacePath, c.err = c.Runtime.CreateVolume(ctx, c.pipeline) + c.err = c.Runtime.CreateVolume(ctx, c.pipeline) if c.err != nil { return fmt.Errorf("unable to create volume: %w", c.err) } @@ -355,6 +355,18 @@ func (c *client) AssembleBuild(ctx context.Context) error { continue } + // verify secret image is allowed to run + if c.enforceTrustedRepos { + priv, err := image.IsPrivilegedImage(s.Origin.Image, c.privilegedImages) + if err != nil { + return err + } + + if priv && !c.repo.GetTrusted() { + return fmt.Errorf("attempting to use privileged image (%s) as untrusted repo", s.Origin.Image) + } + } + c.Logger.Infof("creating %s secret", s.Origin.Name) // create the service c.err = c.secret.create(ctx, s.Origin) @@ -382,92 +394,6 @@ func (c *client) AssembleBuild(ctx context.Context) error { return fmt.Errorf("unable to create outputs container: %w", c.err) } - // enforce repo.trusted is set for pipelines containing privileged images - // if not enforced, allow all that exist in the list of runtime privileged images - // this configuration is set as an executor flag - if c.enforceTrustedRepos { - // group steps services stages and secret origins together - containers := c.pipeline.Steps - - containers = append(containers, c.pipeline.Services...) - - for _, stage := range c.pipeline.Stages { - containers = append(containers, stage.Steps...) - } - - for _, secret := range c.pipeline.Secrets { - containers = append(containers, secret.Origin) - } - - // assume no privileged images are in use - containsPrivilegedImages := false - privImages := []string{} - - // verify all pipeline containers - for _, container := range containers { - // TODO: remove hardcoded reference - if container.Image == "#init" { - continue - } - - // skip over non-plugin secrets origins - if container.Empty() { - continue - } - - c.Logger.Infof("verifying privileges for container %s", container.Name) - - // update the init log with image info - // - // https://pkg.go.dev/github.com/go-vela/types/library#Log.AppendData - _log.AppendData([]byte(fmt.Sprintf("Verifying privileges for image %s...\n", container.Image))) - - for _, pattern := range c.privilegedImages { - // check if image matches privileged pattern - privileged, err := image.IsPrivilegedImage(container.Image, pattern) - if err != nil { - // wrap the error - c.err = fmt.Errorf("unable to verify privileges for image %s: %w", container.Image, err) - - // update the init log with image info - // - // https://pkg.go.dev/github.com/go-vela/types/library#Log.AppendData - _log.AppendData([]byte(fmt.Sprintf("ERROR: %s\n", c.err.Error()))) - - // return error and destroy the build - // ignore checking more images - return c.err - } - - if privileged { - // pipeline contains at least one privileged image - containsPrivilegedImages = privileged - - privImages = append(privImages, container.Image) - } - } - - // update the init log with image info - // - // https://pkg.go.dev/github.com/go-vela/types/library#Log.AppendData - _log.AppendData([]byte(fmt.Sprintf("Privileges verified for image %s\n", container.Image))) - } - - // ensure pipelines containing privileged images are only permitted to run by trusted repos - if (containsPrivilegedImages) && !(c.repo != nil && c.repo.GetTrusted()) { - // update error including privileged image - c.err = fmt.Errorf("unable to assemble build. pipeline contains privileged images and repo is not trusted. privileged image: %v", privImages) - - // update the init log with image info - // - // https://pkg.go.dev/github.com/go-vela/types/library#Log.AppendData - _log.AppendData([]byte(fmt.Sprintf("ERROR: %s\n", c.err.Error()))) - - // return error and destroy the build - return c.err - } - } - // inspect the runtime build (eg a kubernetes pod) for the pipeline buildOutput, err := c.Runtime.InspectBuild(ctx, c.pipeline) if err != nil { @@ -744,16 +670,14 @@ func (c *client) ExecBuild(ctx context.Context) error { } // merge env from outputs - err = _step.MergeEnv(opEnv) - if err != nil { - return fmt.Errorf("failed to merge environment") - } + // + //nolint:errcheck // only errors with empty environment input, which does not matter here + _step.MergeEnv(opEnv) // merge env from masked outputs - err = _step.MergeEnv(maskEnv) - if err != nil { - return fmt.Errorf("failed to merge mask environment") - } + // + //nolint:errcheck // only errors with empty environment input, which does not matter here + _step.MergeEnv(maskEnv) // add masked outputs to secret map so they can be masked in logs for key := range maskEnv { @@ -817,7 +741,7 @@ func (c *client) ExecBuild(ctx context.Context) error { c.Logger.Infof("executing %s stage", stage.Name) // execute the stage - c.err = c.ExecStage(stageCtx, stage, stageMap) + c.err = c.ExecStage(stageCtx, stage, stageMap, opEnv, maskEnv) if c.err != nil { return fmt.Errorf("unable to execute stage: %w", c.err) } diff --git a/executor/linux/build_test.go b/executor/linux/build_test.go index 449dd91d..7f977633 100644 --- a/executor/linux/build_test.go +++ b/executor/linux/build_test.go @@ -222,837 +222,6 @@ func TestLinux_CreateBuild(t *testing.T) { } } -func TestLinux_AssembleBuild_EnforceTrustedRepos(t *testing.T) { - // setup types - set := flag.NewFlagSet("test", 0) - set.String("clone-image", "target/vela-git:latest", "doc") - compiler, _ := native.New(cli.NewContext(nil, set, nil)) - - _build := testBuild() - - // setting mock build for testing dynamic environment tags - _buildWithMessageAlpine := testBuild() - _buildWithMessageAlpine.SetMessage("alpine") - - // test repo is not trusted by default - _untrustedRepo := testRepo() - _user := testUser() - _metadata := testMetadata() - // to be matched with the image used by testdata/build/steps/basic.yml - _privilegedImagesStepsPipeline := []string{"alpine"} - // to be matched with the image used by testdata/build/services/basic.yml - _privilegedImagesServicesPipeline := []string{"postgres"} - // to be matched with the image used by testdata/build/stages/basic.yml - _privilegedImagesStagesPipeline := []string{"alpine"} - // create trusted repo - _trustedRepo := testRepo() - _trustedRepo.SetTrusted(true) - - gin.SetMode(gin.TestMode) - - s := httptest.NewServer(server.FakeHandler()) - - _client, err := vela.NewClient(s.URL, "", nil) - if err != nil { - t.Errorf("unable to create Vela API client: %v", err) - } - - tests := []struct { - name string - failure bool - runtime string - build *library.Build - repo *library.Repo - pipeline string - privilegedImages []string - enforceTrustedRepos bool - }{ - { - name: "docker-enforce trusted repos enabled: privileged steps pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged steps pipeline with untrusted repo", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged steps pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged steps pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged steps pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged steps pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged steps pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged steps pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged steps pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged steps pipeline with untrusted repo and dynamic image:tag", - failure: true, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged steps pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged steps pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged steps pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged steps pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged steps pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged steps pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged services pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged services pipeline with untrusted repo", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged services pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged services pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged services pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged services pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged services pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged services pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged services pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged services pipeline with untrusted repo and dynamic image:tag", - failure: true, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged services pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged services pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged services pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged services pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged services pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged services pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/services/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged stages pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged stages pipeline with untrusted repo", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged stages pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged stages pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged stages pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged stages pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged stages pipeline with trusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged stages pipeline with untrusted repo", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/basic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged stages pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged stages pipeline with untrusted repo and dynamic image:tag", - failure: true, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged stages pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged stages pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged stages pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged stages pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged stages pipeline with trusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _trustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged stages pipeline with untrusted repo and dynamic image:tag", - failure: false, - runtime: constants.DriverDocker, - build: _buildWithMessageAlpine, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/img_environmentdynamic.yml", - privilegedImages: []string{}, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged steps pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged steps pipeline with untrusted repo and init step name", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged steps pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged steps pipeline with untrusted repo and init step name", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged steps pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged steps pipeline with untrusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged steps pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged steps pipeline with untrusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/steps/name_init.yml", - privilegedImages: _privilegedImagesStepsPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged stages pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged stages pipeline with untrusted repo and init step name", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged stages pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged stages pipeline with untrusted repo and init step name", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged stages pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged stages pipeline with untrusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged stages pipeline with trusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged stages pipeline with untrusted repo and init step name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/stages/name_init.yml", - privilegedImages: _privilegedImagesStagesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos enabled: privileged services pipeline with trusted repo and init service name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: privileged services pipeline with untrusted repo and init service name", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged services pipeline with trusted repo and init service name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos enabled: non-privileged services pipeline with untrusted repo and init service name", - failure: true, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: true, - }, - { - name: "docker-enforce trusted repos disabled: privileged services pipeline with trusted repo and init service name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: privileged services pipeline with untrusted repo and init service name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged services pipeline with trusted repo and init service name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _trustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - { - name: "docker-enforce trusted repos disabled: non-privileged services pipeline with untrusted repo and init service name", - failure: false, - runtime: constants.DriverDocker, - build: _build, - repo: _untrustedRepo, - pipeline: "testdata/build/services/name_init.yml", - privilegedImages: _privilegedImagesServicesPipeline, // this matches the image from test.pipeline - enforceTrustedRepos: false, - }, - } - - // run test - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - _pipeline, _, err := compiler. - Duplicate(). - WithBuild(_build). - WithRepo(test.repo). - WithMetadata(_metadata). - WithUser(_user). - Compile(test.pipeline) - if err != nil { - t.Errorf("unable to compile pipeline %s: %v", test.pipeline, err) - } - - var _runtime runtime.Engine - - switch test.runtime { - case constants.DriverDocker: - _runtime, err = docker.NewMock() - if err != nil { - t.Errorf("unable to create docker runtime engine: %v", err) - } - } - - _engine, err := New( - WithBuild(test.build), - WithPipeline(_pipeline), - WithRepo(test.repo), - WithRuntime(_runtime), - WithUser(_user), - WithVelaClient(_client), - WithPrivilegedImages(test.privilegedImages), - WithEnforceTrustedRepos(test.enforceTrustedRepos), - ) - if err != nil { - t.Errorf("unable to create executor engine: %v", err) - } - - err = _engine.CreateBuild(context.Background()) - if err != nil { - t.Errorf("CreateBuild returned err: %v", err) - } - - // override mock handler PUT build update - // used for dynamic substitute testing - _engine.build.SetMessage(test.build.GetMessage()) - - err = _engine.AssembleBuild(context.Background()) - - if test.failure { - if err == nil { - t.Errorf("AssembleBuild should have returned err") - } - - return // continue to next test - } - - if err != nil { - t.Errorf("AssembleBuild returned err: %v", err) - } - }) - } -} - func TestLinux_PlanBuild(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) @@ -1488,6 +657,7 @@ func TestLinux_AssembleBuild(t *testing.T) { WithRuntime(_runtime), WithUser(_user), WithVelaClient(_client), + WithOutputCtn(testOutputsCtn()), withStreamRequests(streamRequests), ) if err != nil { @@ -1736,6 +906,7 @@ func TestLinux_ExecBuild(t *testing.T) { WithRuntime(_runtime), WithUser(_user), WithVelaClient(_client), + WithOutputCtn(testOutputsCtn()), withStreamRequests(streamRequests), ) if err != nil { @@ -2660,6 +1831,7 @@ func TestLinux_DestroyBuild(t *testing.T) { WithRuntime(_runtime), WithUser(_user), WithVelaClient(_client), + WithOutputCtn(testOutputsCtn()), ) if err != nil { t.Errorf("unable to create %s executor engine: %v", test.name, err) @@ -2724,3 +1896,11 @@ func TestLinux_DestroyBuild(t *testing.T) { }) } } + +func testOutputsCtn() *pipeline.Container { + return &pipeline.Container{ + ID: "outputs_test", + Environment: make(map[string]string), + Detach: true, + } +} diff --git a/executor/linux/service.go b/executor/linux/service.go index 22ea9260..2e1ed1ae 100644 --- a/executor/linux/service.go +++ b/executor/linux/service.go @@ -13,6 +13,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" + "github.com/go-vela/worker/internal/image" "github.com/go-vela/worker/internal/message" "github.com/go-vela/worker/internal/service" ) @@ -121,6 +122,18 @@ func (c *client) ExecService(ctx context.Context, ctn *pipeline.Container) error // https://pkg.go.dev/github.com/sirupsen/logrus#Entry.WithField logger := c.Logger.WithField("service", ctn.Name) + // verify service is allowed to run + if c.enforceTrustedRepos { + priv, err := image.IsPrivilegedImage(ctn.Image, c.privilegedImages) + if err != nil { + return err + } + + if priv && !c.repo.GetTrusted() { + return fmt.Errorf("attempting to use privileged image (%s) as untrusted repo", ctn.Image) + } + } + // load the service from the client // // https://pkg.go.dev/github.com/go-vela/worker/internal/service#Load diff --git a/executor/linux/stage.go b/executor/linux/stage.go index 0db62038..5221b14e 100644 --- a/executor/linux/stage.go +++ b/executor/linux/stage.go @@ -96,7 +96,7 @@ func (c *client) PlanStage(ctx context.Context, s *pipeline.Stage, m *sync.Map) } // ExecStage runs a stage. -func (c *client) ExecStage(ctx context.Context, s *pipeline.Stage, m *sync.Map) error { +func (c *client) ExecStage(ctx context.Context, s *pipeline.Stage, m *sync.Map, opEnv, maskEnv map[string]string) error { // update engine logger with stage metadata // // https://pkg.go.dev/github.com/sirupsen/logrus#Entry.WithField @@ -156,6 +156,30 @@ func (c *client) ExecStage(ctx context.Context, s *pipeline.Stage, m *sync.Map) return fmt.Errorf("unable to plan step %s: %w", _step.Name, err) } + // merge env from outputs + // + //nolint:errcheck // only errors with empty environment input, which does not matter here + _step.MergeEnv(opEnv) + + // merge env from masked outputs + // + //nolint:errcheck // only errors with empty environment input, which does not matter here + _step.MergeEnv(maskEnv) + + // add masked outputs to secret map so they can be masked in logs + for key := range maskEnv { + sec := &pipeline.StepSecret{ + Target: key, + } + _step.Secrets = append(_step.Secrets, sec) + } + + // perform any substitution on dynamic variables + err = _step.Substitute() + if err != nil { + return err + } + logger.Infof("executing %s step", _step.Name) // execute the step err = c.ExecStep(ctx, _step) @@ -163,6 +187,12 @@ func (c *client) ExecStage(ctx context.Context, s *pipeline.Stage, m *sync.Map) return fmt.Errorf("unable to exec step %s: %w", _step.Name, err) } + // poll outputs + opEnv, maskEnv, c.err = c.outputs.poll(ctx, c.OutputCtn) + if c.err != nil { + return fmt.Errorf("unable to exec outputs container: %w", c.err) + } + // failed steps within the stage should set the stop value to true unless // the continue rule is set to true. if _step.ExitCode != 0 && !_step.Ruleset.Continue { diff --git a/executor/linux/stage_test.go b/executor/linux/stage_test.go index f79e2155..05b921a1 100644 --- a/executor/linux/stage_test.go +++ b/executor/linux/stage_test.go @@ -589,13 +589,14 @@ func TestLinux_ExecStage(t *testing.T) { WithRuntime(test.runtime), WithUser(_user), WithVelaClient(_client), + WithOutputCtn(testOutputsCtn()), withStreamRequests(streamRequests), ) if err != nil { t.Errorf("unable to create %s executor engine: %v", test.name, err) } - err = _engine.ExecStage(context.Background(), test.stage, stageMap) + err = _engine.ExecStage(context.Background(), test.stage, stageMap, nil, nil) if test.failure { if err == nil { diff --git a/executor/linux/step.go b/executor/linux/step.go index fc0a4922..ad5056f3 100644 --- a/executor/linux/step.go +++ b/executor/linux/step.go @@ -6,6 +6,7 @@ import ( "bufio" "bytes" "context" + "fmt" "io" "strings" "time" @@ -13,6 +14,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" + "github.com/go-vela/worker/internal/image" "github.com/go-vela/worker/internal/message" "github.com/go-vela/worker/internal/step" "github.com/sirupsen/logrus" @@ -118,6 +120,18 @@ func (c *client) ExecStep(ctx context.Context, ctn *pipeline.Container) error { return nil } + // verify step is allowed to run + if c.enforceTrustedRepos { + priv, err := image.IsPrivilegedImage(ctn.Image, c.privilegedImages) + if err != nil { + return err + } + + if priv && !c.repo.GetTrusted() { + return fmt.Errorf("attempting to use privileged image (%s) as untrusted repo", ctn.Image) + } + } + // update engine logger with step metadata // // https://pkg.go.dev/github.com/sirupsen/logrus#Entry.WithField diff --git a/executor/local/build.go b/executor/local/build.go index f5000ee7..54d7d876 100644 --- a/executor/local/build.go +++ b/executor/local/build.go @@ -108,7 +108,7 @@ func (c *client) PlanBuild(ctx context.Context) error { fmt.Fprintln(c.stdout, _pattern, string(network)) // create the runtime volume for the pipeline - _, err = c.Runtime.CreateVolume(ctx, c.pipeline) + err = c.Runtime.CreateVolume(ctx, c.pipeline) if err != nil { c.err = err return fmt.Errorf("unable to create volume: %w", err) @@ -328,7 +328,7 @@ func (c *client) ExecBuild(ctx context.Context) error { } // execute the stage - c.err = c.ExecStage(stageCtx, stage, stageMap) + c.err = c.ExecStage(stageCtx, stage, stageMap, nil, nil) if c.err != nil { return fmt.Errorf("unable to execute stage: %w", c.err) } diff --git a/executor/local/stage.go b/executor/local/stage.go index abed1868..9088ef3b 100644 --- a/executor/local/stage.go +++ b/executor/local/stage.go @@ -74,7 +74,7 @@ func (c *client) PlanStage(ctx context.Context, s *pipeline.Stage, m *sync.Map) } // ExecStage runs a stage. -func (c *client) ExecStage(ctx context.Context, s *pipeline.Stage, m *sync.Map) error { +func (c *client) ExecStage(ctx context.Context, s *pipeline.Stage, m *sync.Map, opEnv, maskEnv map[string]string) error { // close the stage channel at the end defer func() { errChan, ok := m.Load(s.Name) diff --git a/executor/local/stage_test.go b/executor/local/stage_test.go index 9df4a425..1c1b5901 100644 --- a/executor/local/stage_test.go +++ b/executor/local/stage_test.go @@ -325,7 +325,7 @@ func TestLocal_ExecStage(t *testing.T) { t.Errorf("unable to create executor engine: %v", err) } - err = _engine.ExecStage(context.Background(), test.stage, stageMap) + err = _engine.ExecStage(context.Background(), test.stage, stageMap, nil, nil) if test.failure { if err == nil { diff --git a/internal/image/image.go b/internal/image/image.go index ee0c3015..e2d5b353 100644 --- a/internal/image/image.go +++ b/internal/image/image.go @@ -52,34 +52,40 @@ func ParseWithError(_image string) (string, error) { // IsPrivilegedImage digests the provided image with a // privileged pattern to see if the image meets the criteria // needed to allow a Docker Socket mount. -func IsPrivilegedImage(image, privileged string) (bool, error) { - // parse the image provided into a - // named, fully qualified reference - // - // https://pkg.go.dev/github.com/distribution/reference#ParseAnyReference - _refImg, err := reference.ParseAnyReference(image) - if err != nil { - return false, err - } +func IsPrivilegedImage(image string, privilegedSet []string) (bool, error) { + for _, pattern := range privilegedSet { + // parse the image provided into a + // named, fully qualified reference + // + // https://pkg.go.dev/github.com/distribution/reference#ParseAnyReference + _refImg, err := reference.ParseAnyReference(image) + if err != nil { + return false, err + } - // ensure we have the canonical form of the named reference - // - // https://pkg.go.dev/github.com/distribution/reference#ParseNamed - _canonical, err := reference.ParseNamed(_refImg.String()) - if err != nil { - return false, err - } + // ensure we have the canonical form of the named reference + // + // https://pkg.go.dev/github.com/distribution/reference#ParseNamed + _canonical, err := reference.ParseNamed(_refImg.String()) + if err != nil { + return false, err + } - // add default tag "latest" when tag does not exist - _refImg = reference.TagNameOnly(_canonical) + // add default tag "latest" when tag does not exist + _refImg = reference.TagNameOnly(_canonical) - // check if the image matches the privileged pattern - // - // https://pkg.go.dev/github.com/distribution/reference#FamiliarMatch - match, err := reference.FamiliarMatch(privileged, _refImg) - if err != nil { - return false, err + // check if the image matches the privileged pattern + // + // https://pkg.go.dev/github.com/distribution/reference#FamiliarMatch + match, err := reference.FamiliarMatch(pattern, _refImg) + if err != nil { + return false, err + } + + if match { + return match, nil + } } - return match, nil + return false, nil } diff --git a/internal/image/image_test.go b/internal/image/image_test.go index d38d4f87..e76ffc81 100644 --- a/internal/image/image_test.go +++ b/internal/image/image_test.go @@ -154,52 +154,52 @@ func TestImage_ParseWithError(t *testing.T) { func TestImage_IsPrivilegedImage(t *testing.T) { // setup tests tests := []struct { - name string - image string - pattern string - want bool + name string + image string + patterns []string + want bool }{ { - name: "test privileged image without tag", - image: "docker.company.com/foo/bar", - pattern: "docker.company.com/foo/bar", - want: true, + name: "test privileged image without tag", + image: "docker.company.com/foo/bar", + patterns: []string{"docker.company.com/foo/bar"}, + want: true, }, { - name: "test privileged image with tag", - image: "docker.company.com/foo/bar:v0.1.0", - pattern: "docker.company.com/foo/bar", - want: true, + name: "test privileged image with tag", + image: "docker.company.com/foo/bar:v0.1.0", + patterns: []string{"docker.company.com/foo/bar"}, + want: true, }, { - name: "test privileged image with tag", - image: "docker.company.com/foo/bar", - pattern: "docker.company.com/foo/bar:v0.1.0", - want: false, + name: "test privileged image with tag", + image: "docker.company.com/foo/bar", + patterns: []string{"docker.company.com/foo/bar:v0.1.0"}, + want: false, }, { - name: "test privileged with bad image", - image: "!@#$%^&*()", - pattern: "docker.company.com/foo/bar", - want: false, + name: "test privileged with bad image", + image: "!@#$%^&*()", + patterns: []string{"docker.company.com/foo/bar"}, + want: false, }, { - name: "test privileged with bad pattern", - image: "docker.company.com/foo/bar", - pattern: "!@#$%^&*()", - want: false, + name: "test privileged with bad pattern", + image: "docker.company.com/foo/bar", + patterns: []string{"!@#$%^&*()", "docker.company.com/foo/baz"}, + want: false, }, { - name: "test privileged with on extended path image", - image: "docker.company.com/foo/bar", - pattern: "docker.company.com/foo", - want: false, + name: "test privileged with on extended path image", + image: "docker.company.com/foo/bar", + patterns: []string{"docker.company.com/foo", "docker.company.com/fab"}, + want: false, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _ := IsPrivilegedImage(test.image, test.pattern) + got, _ := IsPrivilegedImage(test.image, test.patterns) if got != test.want { t.Errorf("IsPrivilegedImage is %v want %v", got, test.want) } diff --git a/runtime/docker/container.go b/runtime/docker/container.go index ee6b0ad8..57b276df 100644 --- a/runtime/docker/container.go +++ b/runtime/docker/container.go @@ -139,21 +139,19 @@ func (c *client) RunContainer(ctx context.Context, ctn *pipeline.Container, b *p } // check if the image is allowed to run privileged - for _, pattern := range c.config.Images { - privileged, err := image.IsPrivilegedImage(ctn.Image, pattern) - if err != nil { - return err - } + privileged, err := image.IsPrivilegedImage(ctn.Image, c.config.Images) + if err != nil { + return err + } - if privileged { - hostConf.Privileged = true - } + if privileged { + hostConf.Privileged = true } // send API call to create the container // // https://godoc.org/github.com/docker/docker/client#Client.ContainerCreate - _, err := c.Docker.ContainerCreate( + _, err = c.Docker.ContainerCreate( ctx, containerConf, hostConf, diff --git a/runtime/docker/volume.go b/runtime/docker/volume.go index 87db4c3b..f48e3306 100644 --- a/runtime/docker/volume.go +++ b/runtime/docker/volume.go @@ -20,7 +20,7 @@ import ( ) // CreateVolume creates the pipeline volume. -func (c *client) CreateVolume(ctx context.Context, b *pipeline.Build) (string, error) { +func (c *client) CreateVolume(ctx context.Context, b *pipeline.Build) error { c.Logger.Tracef("creating volume for pipeline %s", b.ID) // create options for creating volume @@ -34,14 +34,12 @@ func (c *client) CreateVolume(ctx context.Context, b *pipeline.Build) (string, e // send API call to create the volume // // https://godoc.org/github.com/docker/docker/client#Client.VolumeCreate - v, err := c.Docker.VolumeCreate(ctx, opts) + _, err := c.Docker.VolumeCreate(ctx, opts) if err != nil { - return "", err + return err } - logrus.Infof("VOLUME MOUNT LOCATION: %s", v.Mountpoint) - - return v.Mountpoint, nil + return nil } // InspectVolume inspects the pipeline volume. diff --git a/runtime/engine.go b/runtime/engine.go index 43308a30..0dabe0cc 100644 --- a/runtime/engine.go +++ b/runtime/engine.go @@ -85,7 +85,7 @@ type Engine interface { // CreateVolume defines a function that // creates the pipeline volume. - CreateVolume(context.Context, *pipeline.Build) (string, error) + CreateVolume(context.Context, *pipeline.Build) error // InspectVolume defines a function that // inspects the pipeline volume. InspectVolume(context.Context, *pipeline.Build) ([]byte, error) diff --git a/runtime/kubernetes/container.go b/runtime/kubernetes/container.go index 00c82d3e..9be88840 100644 --- a/runtime/kubernetes/container.go +++ b/runtime/kubernetes/container.go @@ -164,15 +164,14 @@ func (c *client) SetupContainer(ctx context.Context, ctn *pipeline.Container) er container.VolumeMounts = volumeMounts // check if the image is allowed to run privileged - for _, pattern := range c.config.Images { - privileged, err := image.IsPrivilegedImage(ctn.Image, pattern) - if err != nil { - return err - } - container.SecurityContext.Privileged = &privileged + privileged, err := image.IsPrivilegedImage(ctn.Image, c.config.Images) + if err != nil { + return err } + container.SecurityContext.Privileged = &privileged + if c.PipelinePodTemplate != nil && c.PipelinePodTemplate.Spec.Container != nil { securityContext := c.PipelinePodTemplate.Spec.Container.SecurityContext diff --git a/runtime/kubernetes/volume.go b/runtime/kubernetes/volume.go index 6c51b509..1f91731b 100644 --- a/runtime/kubernetes/volume.go +++ b/runtime/kubernetes/volume.go @@ -16,7 +16,7 @@ import ( ) // CreateVolume creates the pipeline volume. -func (c *client) CreateVolume(ctx context.Context, b *pipeline.Build) (string, error) { +func (c *client) CreateVolume(ctx context.Context, b *pipeline.Build) error { c.Logger.Tracef("creating volume for pipeline %s", b.ID) // create the workspace volume for the pod @@ -85,7 +85,7 @@ func (c *client) CreateVolume(ctx context.Context, b *pipeline.Build) (string, e // TODO: extend c.config.Volumes to include container-specific volumes (container.Volumes) - return "", nil + return nil } // InspectVolume inspects the pipeline volume.