Skip to content

Commit

Permalink
host-ctr: add support for authenticated image pulls from ECR Public
Browse files Browse the repository at this point in the history
Add support for authenticated image pulls from ECR Public registries.
Unlike ECR private registries, we have to use Docker's registry API for
resolving ECR Public image references. This means having to manage
ECR Public registry auth credentials ourselves
  • Loading branch information
etungsten committed Feb 2, 2021
1 parent 55b1c90 commit f994c53
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 16 deletions.
78 changes: 66 additions & 12 deletions sources/host-ctr/cmd/host-ctr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/base64"
"io/ioutil"
"math/rand"
"os"
Expand All @@ -11,6 +12,9 @@ import (
"syscall"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecrpublic"
"github.com/awslabs/amazon-ecr-containerd-resolver/ecr"
"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
Expand All @@ -20,6 +24,7 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/remotes/docker"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -664,19 +669,68 @@ func tagImage(ctx context.Context, imageName string, newImageName string, client

// withDynamicResolver provides an initialized resolver for use with ref.
func withDynamicResolver(ctx context.Context, ref string) containerd.RemoteOpt {
if !strings.HasPrefix(ref, "ecr.aws/") {
// not handled here
return func(_ *containerd.Client, _ *containerd.RemoteContext) error { return nil }
}

return func(_ *containerd.Client, c *containerd.RemoteContext) error {
// Create the ECR resolver
resolver, err := ecr.NewResolver()
noOp := func(_ *containerd.Client, _ *containerd.RemoteContext) error { return nil }

switch {
// For ECR registries, we need to use the Amazon ECR resolver
case strings.HasPrefix(ref, "ecr.aws/"):
return func(_ *containerd.Client, c *containerd.RemoteContext) error {
// Create the Amazon ECR resolver
resolver, err := ecr.NewResolver()
if err != nil {
return errors.Wrap(err, "Failed to create ECR resolver")
}
log.G(ctx).WithField("ref", ref).Info("pulling with Amazon ECR Resolver")
c.Resolver = resolver
return nil
}
// For Amazon ECR Public registries, we should try and fetch credentials before resolving the image reference
case strings.HasPrefix(ref, "public.ecr.aws/"):
// Try to get credentials for authenticated pulls from ECR Public
session := session.Must(session.NewSession())
// The ECR Public API is only available in us-east-1 today
publicConfig := aws.NewConfig().WithRegion("us-east-1")
client := ecrpublic.New(session, publicConfig)
output, err := client.GetAuthorizationToken(&ecrpublic.GetAuthorizationTokenInput{})
if err != nil {
return errors.Wrap(err, "Failed to create ECR resolver")
log.G(ctx).Warn("ecr-public: failed to get authorization token, falling back to default resolver (unauthenticated pull)")
return noOp
}
log.G(ctx).WithField("ref", ref).Info("pulling with Amazon ECR Resolver")
c.Resolver = resolver
return nil
if output == nil || output.AuthorizationData == nil {
log.G(ctx).Warn("ecr-public: missing AuthorizationData in ECR Public GetAuthorizationToken response, falling back to default resolver (unauthenticated pull)")
return noOp
}
authToken, err := base64.StdEncoding.DecodeString(aws.StringValue(output.AuthorizationData.AuthorizationToken))
if err != nil {
log.G(ctx).Warn("ecr-public: unable to decode authorization token, falling back to default resolver (unauthenticated pull)")
return noOp
}
tokens := strings.SplitN(string(authToken), ":", 2)
if len(tokens) != 2 {
log.G(ctx).Warn("ecr-public: invalid credentials decoded from authorization token, falling back to default resolver (unauthenticated pull)")
return noOp
}
// Use the fetched authorization credentials to resolve the image
authOpt := docker.WithAuthCreds(func(host string) (string, string, error) {
// Double-check to make sure the we're doing this for an ECR Public registry
if host != "public.ecr.aws" {
return "", "", errors.New("ecr-public: expected image to start with public.ecr.aws")
}
return tokens[0], tokens[1], nil
})
authorizer := docker.NewDockerAuthorizer(authOpt)
resolverOpt := docker.ResolverOptions{
Hosts: docker.ConfigureDefaultRegistries(docker.WithAuthorizer(authorizer)),
}

return func(_ *containerd.Client, c *containerd.RemoteContext) error {
resolver := docker.NewResolver(resolverOpt)
log.G(ctx).WithField("ref", ref).Info("pulling from ECR Public")
c.Resolver = resolver
return nil
}
default:
// For all other registries
return noOp
}
}
3 changes: 1 addition & 2 deletions sources/host-ctr/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.12
require (
github.com/Microsoft/go-winio v0.4.15 // indirect
github.com/Microsoft/hcsshim v0.8.10 // indirect
github.com/aws/aws-sdk-go v1.35.25 // indirect
github.com/aws/aws-sdk-go v1.37.0
github.com/awslabs/amazon-ecr-containerd-resolver v0.0.0-20200922205237-bbd7175f7bd0
github.com/containerd/cgroups v0.0.0-20201109155418-13abef5d31ec // indirect
github.com/containerd/containerd v1.3.7
Expand All @@ -24,7 +24,6 @@ require (
github.com/willf/bitset v1.1.11 // indirect
go.etcd.io/bbolt v1.3.5 // indirect
go.opencensus.io v0.22.5 // indirect
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c // indirect
golang.org/x/text v0.3.4 // indirect
Expand Down
4 changes: 2 additions & 2 deletions sources/host-ctr/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU=
github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM=
github.com/aws/aws-sdk-go v1.32.13/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.35.25 h1:0+UC6ZquMOLvYABoz0olShCAe+M9oKllgPfr2hnv9zE=
github.com/aws/aws-sdk-go v1.35.25/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk=
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/awslabs/amazon-ecr-containerd-resolver v0.0.0-20200922205237-bbd7175f7bd0 h1:mxzIxXHpy2nmQH1FG/5y0Mr1LRk7RqzwBB+cKe0YwmQ=
github.com/awslabs/amazon-ecr-containerd-resolver v0.0.0-20200922205237-bbd7175f7bd0/go.mod h1:KuTNnZvgS7awNYUpeTkWpvz3GZoj6GNkwr/Mn2TCF8Y=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down

0 comments on commit f994c53

Please sign in to comment.