diff --git a/.changelog/4847.txt b/.changelog/4847.txt new file mode 100644 index 00000000000..40149dd6364 --- /dev/null +++ b/.changelog/4847.txt @@ -0,0 +1,3 @@ +```release-note:improvement +plugin/aws/ecr-pull: Support entrypoint injection in ecr-pull builder +``` diff --git a/builtin/aws/alb/plugin.pb.go b/builtin/aws/alb/plugin.pb.go index 6383374d09c..b282735da45 100644 --- a/builtin/aws/alb/plugin.pb.go +++ b/builtin/aws/alb/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/aws/ami/plugin.pb.go b/builtin/aws/ami/plugin.pb.go index 7ddec49459f..f3264c04fa3 100644 --- a/builtin/aws/ami/plugin.pb.go +++ b/builtin/aws/ami/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/aws/ec2/plugin.pb.go b/builtin/aws/ec2/plugin.pb.go index 34fa5c310ee..0833d45cb1f 100644 --- a/builtin/aws/ec2/plugin.pb.go +++ b/builtin/aws/ec2/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/aws/ecr/mapper.go b/builtin/aws/ecr/mapper.go index 6eabc4569bd..416706c9d3c 100644 --- a/builtin/aws/ecr/mapper.go +++ b/builtin/aws/ecr/mapper.go @@ -12,9 +12,15 @@ func ECRImageMapper(src *Image) *docker.Image { return &docker.Image{ Image: src.Image, Tag: src.Tag, - Location: &docker.Image_Registry{ Registry: &docker.Image_RegistryLocation{}, }, } } + +func DockerToEcrImageMapper(src *docker.Image) *Image { + return &Image{ + Image: src.Image, + Tag: src.Tag, + } +} diff --git a/builtin/aws/ecr/plugin.pb.go b/builtin/aws/ecr/plugin.pb.go index 66675236a67..c2b119f8fcf 100644 --- a/builtin/aws/ecr/plugin.pb.go +++ b/builtin/aws/ecr/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/aws/ecr/pull/builder.go b/builtin/aws/ecr/pull/builder.go index 8d9f7910f90..28b595ded87 100644 --- a/builtin/aws/ecr/pull/builder.go +++ b/builtin/aws/ecr/pull/builder.go @@ -17,11 +17,19 @@ import ( "github.com/aws/aws-sdk-go/aws" awsecr "github.com/aws/aws-sdk-go/service/ecr" "github.com/aws/aws-sdk-go/service/lambda" + + "github.com/hashicorp/waypoint-plugin-sdk/component" "github.com/hashicorp/waypoint-plugin-sdk/docs" "github.com/hashicorp/waypoint-plugin-sdk/terminal" "github.com/hashicorp/waypoint/builtin/aws/ecr" "github.com/hashicorp/waypoint/builtin/aws/utils" + "encoding/base64" + "encoding/json" + + wpdocker "github.com/hashicorp/waypoint/builtin/docker" + wpdockerpull "github.com/hashicorp/waypoint/builtin/docker/pull" + validation "github.com/go-ozzo/ozzo-validation/v4" ) @@ -35,12 +43,22 @@ func (b *Builder) BuildFunc() interface{} { return b.Build } +// BuildFunc implements component.BuilderODR +func (b *Builder) BuildODRFunc() interface{} { + return b.BuildODR +} + // Config is the configuration structure for the registry. type Config struct { Region string `hcl:"region,optional"` Repository string `hcl:"repository,attr"` Tag string `hcl:"tag,attr"` ForceArchitecture string `hcl:"force_architecture,optional"` + DisableCEB bool `hcl:"disable_entrypoint,optional"` +} + +type authInfo struct { + Base64Token *string } func (b *Builder) Documentation() (*docs.Documentation, error) { @@ -99,6 +117,16 @@ build { docs.Default("`\"\"`"), ) + doc.SetField( + "disable_entrypoint", + "if set, the entrypoint binary won't be injected into the image", + docs.Summary( + "The entrypoint binary is what provides extended functionality", + "such as logs and exec. If it is not injected at build time", + "the expectation is that the image already contains it", + ), + ) + return doc, nil } @@ -150,7 +178,125 @@ func (b *Builder) Config() (interface{}, error) { // Build func (b *Builder) Build(ctx context.Context, ui terminal.UI, log hclog.Logger) (*ecr.Image, error) { + sg := ui.StepGroup() + ecrImage, buildAuthInfo, err := b.getErcImage(ctx, ui, log, sg) + if err != nil { + return nil, err + } + + if b.config.DisableCEB { + return ecrImage, nil + } + + repoUser, repoPass, err := credentialsFromEcr(*buildAuthInfo.Base64Token) + if err != nil { + return nil, err + } + + // Use the authorization token to create the base64 package that + // Docker requires to perform authentication. + authInfo := map[string]string{ + "username": repoUser, + "password": repoPass, + } + + authData, err := json.Marshal(authInfo) + if err != nil { + return nil, err + } + encodedAuth := base64.StdEncoding.EncodeToString(authData) + + pullBuilder := &wpdockerpull.Builder{} + raw, err := pullBuilder.Config() + if err != nil { + return nil, err + } + pullConfig := raw.(*wpdockerpull.BuilderConfig) + pullConfig.EncodedAuth = encodedAuth + pullConfig.Image = ecrImage.Image + pullConfig.Tag = ecrImage.Tag + pullConfig.DisableCEB = b.config.DisableCEB + + img, err := pullBuilder.Build(wpdockerpull.BuildArgs{ + Ctx: ctx, + UI: ui, + Log: log, + HasRegistry: true, + }) + + if err != nil { + return nil, err + } + return ecr.DockerToEcrImageMapper(img), nil +} + +// Build +func (b *Builder) BuildODR(ctx context.Context, ui terminal.UI, log hclog.Logger, src *component.Source, ai *wpdocker.AccessInfo) (*ecr.Image, error) { + sg := ui.StepGroup() + ecrImage, buildAuthInfo, err := b.getErcImage(ctx, ui, log, sg) + if err != nil { + return nil, err + } + + if b.config.DisableCEB { + return ecrImage, nil + } + + repoUser, repoPass, err := credentialsFromEcr(*buildAuthInfo.Base64Token) + if err != nil { + return nil, err + } + + // Use the authorization token to create the base64 package that + // Docker requires to perform authentication. + authInfo := map[string]string{ + "username": repoUser, + "password": repoPass, + } + + authData, err := json.Marshal(authInfo) + if err != nil { + return nil, err + } + encodedAuth := base64.StdEncoding.EncodeToString(authData) + pullBuilder := &wpdockerpull.Builder{} + raw, err := pullBuilder.Config() + if err != nil { + return nil, err + } + pullConfig := raw.(*wpdockerpull.BuilderConfig) + pullConfig.EncodedAuth = encodedAuth + pullConfig.Image = ecrImage.Image + pullConfig.Tag = ecrImage.Tag + pullConfig.DisableCEB = b.config.DisableCEB + + img, err := pullBuilder.BuildODR(ctx, ui, src, log, ai) + if err != nil { + return nil, err + } + return ecr.DockerToEcrImageMapper(img), nil +} + +// CredentialsFromEcr returns the username and password present in the encoded +// auth string. This encoded auth string is one that users can pass as authentication +// information to registry. +func credentialsFromEcr(encodedAuth string) (string, string, error) { + // Create a reader that base64 decodes our encoded auth and then splits off USER:PASS + dec, err := base64.StdEncoding.DecodeString(encodedAuth) + if err != nil { + return "", "", fmt.Errorf("invalid encoded auth string: %s", encodedAuth[:5]) + } + + userPassSplit := strings.SplitN(string(dec), ":", 2) + if len(userPassSplit) != 2 { + return "", "", fmt.Errorf("ecr credentials were invalid or did not container user:password. Number of elements in split: %d", len(userPassSplit)) + } + + return userPassSplit[0], userPassSplit[1], nil +} + +func (b *Builder) getErcImage(ctx context.Context, ui terminal.UI, log hclog.Logger, sg terminal.StepGroup) (*ecr.Image, *authInfo, error) { // If there is no region setup. Try and load it from environment variables. if b.config.Region == "" { b.config.Region = os.Getenv("AWS_REGION") @@ -161,12 +307,11 @@ func (b *Builder) Build(ctx context.Context, ui terminal.UI, log hclog.Logger) ( } if b.config.Region == "" { - return nil, status.Error( + return nil, nil, status.Error( codes.FailedPrecondition, "Please set your aws region in the deployment config, or set the environment variable 'AWS_REGION' or 'AWS_DEFAULT_REGION'") } - sg := ui.StepGroup() step := sg.Add("") defer func() { if step != nil { @@ -183,7 +328,7 @@ func (b *Builder) Build(ctx context.Context, ui terminal.UI, log hclog.Logger) ( if err != nil { log.Error("error connecting to AWS", "error", err) - return nil, err + return nil, nil, err } step.Done() @@ -195,6 +340,15 @@ func (b *Builder) Build(ctx context.Context, ui terminal.UI, log hclog.Logger) ( cfgTag := b.config.Tag cfgRepository := b.config.Repository + tokenResp, err := ecrsvc.GetAuthorizationTokenWithContext(ctx, &awsecr.GetAuthorizationTokenInput{}) + if err != nil { + log.Error("error getting authorization token", "error", err) + return nil, nil, err + } + // docs say the token is good for all registries the user has access to. so just grab the first token + token := tokenResp.AuthorizationData[0].AuthorizationToken + log.Debug("successfully retrieved authorization token") + // should be acceptable to filter images by TAGGED status imgs, err := ecrsvc.DescribeImages(&awsecr.DescribeImagesInput{ RepositoryName: aws.String(cfgRepository), @@ -204,12 +358,12 @@ func (b *Builder) Build(ctx context.Context, ui terminal.UI, log hclog.Logger) ( }) if err != nil { log.Error("error describing images", "error", err, "repository", cfgRepository) - return nil, err + return nil, nil, err } if len(imgs.ImageDetails) == 0 { log.Error("no tagged images found", "repository", cfgRepository) - return nil, status.Error(codes.FailedPrecondition, "No images found") + return nil, nil, status.Error(codes.FailedPrecondition, "No images found") } log.Debug("found images", "image count", len(imgs.ImageDetails)) @@ -248,11 +402,11 @@ func (b *Builder) Build(ctx context.Context, ui terminal.UI, log hclog.Logger) ( // if no image was found, return an error if output.Image == "" { log.Error("no matching image was found", "tag", cfgTag, "repository", cfgRepository) - return nil, status.Error(codes.FailedPrecondition, "No matching tags found") + return nil, nil, status.Error(codes.FailedPrecondition, "No matching tags found") } step.Update("Using image: " + output.Image + ":" + output.Tag) step.Done() - return &output, nil + return &output, &authInfo{Base64Token: token}, nil } diff --git a/builtin/aws/ecr/pull/components/builder/aws-ecr-pull-builder/parameters.hcl b/builtin/aws/ecr/pull/components/builder/aws-ecr-pull-builder/parameters.hcl index 172261aa4ff..1ac949b83c6 100644 --- a/builtin/aws/ecr/pull/components/builder/aws-ecr-pull-builder/parameters.hcl +++ b/builtin/aws/ecr/pull/components/builder/aws-ecr-pull-builder/parameters.hcl @@ -1,4 +1,11 @@ # This file was generated via `make gen/integrations-hcl` +parameter { + key = "disable_entrypoint" + description = "if set, the entrypoint binary won't be injected into the image\nThe entrypoint binary is what provides extended functionality such as logs and exec. If it is not injected at build time the expectation is that the image already contains it" + type = "bool" + required = false +} + parameter { key = "force_architecture" description = "**Note**: This is a temporary field that enables overriding the `architecture` output attribute. Valid values are: `\"x86_64\"`, `\"arm64\"`" diff --git a/builtin/aws/ecs/plugin.pb.go b/builtin/aws/ecs/plugin.pb.go index 1f66fcfd1c4..d08b7e75a7d 100644 --- a/builtin/aws/ecs/plugin.pb.go +++ b/builtin/aws/ecs/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/aws/lambda/function_url/plugin.pb.go b/builtin/aws/lambda/function_url/plugin.pb.go index edab33be244..35dc9d9abaa 100644 --- a/builtin/aws/lambda/function_url/plugin.pb.go +++ b/builtin/aws/lambda/function_url/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/aws/lambda/plugin.pb.go b/builtin/aws/lambda/plugin.pb.go index 5017cd9a47c..6ebec3811ec 100644 --- a/builtin/aws/lambda/plugin.pb.go +++ b/builtin/aws/lambda/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/azure/aci/plugin.pb.go b/builtin/azure/aci/plugin.pb.go index 99b70cad37c..3de0e1d62b1 100644 --- a/builtin/azure/aci/plugin.pb.go +++ b/builtin/azure/aci/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/docker/plugin.pb.go b/builtin/docker/plugin.pb.go index 83a582eb99a..8eaaa1c1f97 100644 --- a/builtin/docker/plugin.pb.go +++ b/builtin/docker/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/docker/pull/builder.go b/builtin/docker/pull/builder.go index 19d39a99112..8eae207043e 100644 --- a/builtin/docker/pull/builder.go +++ b/builtin/docker/pull/builder.go @@ -157,7 +157,7 @@ func (b *Builder) Config() (interface{}, error) { // We use the struct form of arguments so that we can access named // values (such as "HasRegistry"). -type buildArgs struct { +type BuildArgs struct { argmapper.Struct Ctx context.Context @@ -186,7 +186,7 @@ func (b *Builder) BuildODR( } // Build -func (b *Builder) Build(args buildArgs) (*wpdocker.Image, error) { +func (b *Builder) Build(args BuildArgs) (*wpdocker.Image, error) { // Pull all the args out to top-level values. This is mostly done // cause the struct was added later, but also because these are very common. ctx := args.Ctx diff --git a/builtin/exec/plugin.pb.go b/builtin/exec/plugin.pb.go index dd9d2bf2e63..b83b02dd810 100644 --- a/builtin/exec/plugin.pb.go +++ b/builtin/exec/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/files/plugin.pb.go b/builtin/files/plugin.pb.go index 0a9a186afca..43788ce74fb 100644 --- a/builtin/files/plugin.pb.go +++ b/builtin/files/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/google/cloudrun/plugin.pb.go b/builtin/google/cloudrun/plugin.pb.go index ba3b0715197..369aba9e7bd 100644 --- a/builtin/google/cloudrun/plugin.pb.go +++ b/builtin/google/cloudrun/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/k8s/apply/plugin.pb.go b/builtin/k8s/apply/plugin.pb.go index b21a31baf25..55e4fc794fd 100644 --- a/builtin/k8s/apply/plugin.pb.go +++ b/builtin/k8s/apply/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/k8s/helm/plugin.pb.go b/builtin/k8s/helm/plugin.pb.go index 5f332744364..6fde313edaf 100644 --- a/builtin/k8s/helm/plugin.pb.go +++ b/builtin/k8s/helm/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/k8s/plugin.pb.go b/builtin/k8s/plugin.pb.go index c4a47a15c42..10b06257d47 100644 --- a/builtin/k8s/plugin.pb.go +++ b/builtin/k8s/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/nomad/canary/plugin.pb.go b/builtin/nomad/canary/plugin.pb.go index 0dbd03fdc26..c169ac06e44 100644 --- a/builtin/nomad/canary/plugin.pb.go +++ b/builtin/nomad/canary/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/nomad/jobspec/plugin.pb.go b/builtin/nomad/jobspec/plugin.pb.go index aa00e86c5ea..f870ab0b046 100644 --- a/builtin/nomad/jobspec/plugin.pb.go +++ b/builtin/nomad/jobspec/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/nomad/plugin.pb.go b/builtin/nomad/plugin.pb.go index 94b7e5ae45e..7993dc7202b 100644 --- a/builtin/nomad/plugin.pb.go +++ b/builtin/nomad/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/builtin/pack/plugin.pb.go b/builtin/pack/plugin.pb.go index 6f992d445c4..7a376cc2506 100644 --- a/builtin/pack/plugin.pb.go +++ b/builtin/pack/plugin.pb.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 diff --git a/embedJson/gen/builder-aws-ecr-pull.json b/embedJson/gen/builder-aws-ecr-pull.json index f8ffe227056..ea6cd47f05f 100644 --- a/embedJson/gen/builder-aws-ecr-pull.json +++ b/embedJson/gen/builder-aws-ecr-pull.json @@ -5,6 +5,18 @@ "mappers": null, "name": "aws-ecr-pull", "optionalFields": [ + { + "Field": "disable_entrypoint", + "Type": "bool", + "Synopsis": "if set, the entrypoint binary won't be injected into the image", + "Summary": "The entrypoint binary is what provides extended functionality such as logs and exec. If it is not injected at build time the expectation is that the image already contains it", + "Optional": true, + "Default": "", + "EnvVar": "", + "Category": false, + "Example": "", + "SubFields": null + }, { "Field": "force_architecture", "Type": "string", diff --git a/website/content/partials/components/builder-aws-ecr-pull.mdx b/website/content/partials/components/builder-aws-ecr-pull.mdx index 3f2aa6bb5ec..a723334ac36 100644 --- a/website/content/partials/components/builder-aws-ecr-pull.mdx +++ b/website/content/partials/components/builder-aws-ecr-pull.mdx @@ -48,6 +48,15 @@ The tag of the image to pull. These parameters are used in the [`use` stanza](/waypoint/docs/waypoint-hcl/use) for this plugin. +#### disable_entrypoint + +If set, the entrypoint binary won't be injected into the image. + +The entrypoint binary is what provides extended functionality such as logs and exec. If it is not injected at build time the expectation is that the image already contains it. + +- Type: **bool** +- **Optional** + #### force_architecture **Note**: This is a temporary field that enables overriding the `architecture` output attribute. Valid values are: `"x86_64"`, `"arm64"`.