func withDynamicResolver()

in sources/host-ctr/cmd/host-ctr/main.go [914:990]


func withDynamicResolver(ctx context.Context, ref string, registryConfig *RegistryConfig) containerd.RemoteOpt {
	defaultResolver := func(_ *containerd.Client, _ *containerd.RemoteContext) error { return nil }
	if registryConfig != nil {
		defaultResolver = func(_ *containerd.Client, c *containerd.RemoteContext) error {
			resolver := docker.NewResolver(docker.ResolverOptions{
				Hosts: registryHosts(registryConfig, docker.NewDockerAuthorizer()),
			})
			c.Resolver = resolver
			return nil
		}
	}

	switch {
	// For private ECR registries, we need to use the Amazon ECR resolver.
	// Currently we're unable to support image registry configuration with the ECR resolver.
	// FIXME Track upstream `amazon-ecr-containerd-resolver` support for image registry configuration.
	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 {
			log.G(ctx).Warn("ecr-public: failed to get authorization token, falling back to default resolver (unauthenticated pull)")
			return defaultResolver
		}
		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 defaultResolver
		}
		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 defaultResolver
		}
		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 defaultResolver
		}
		// 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: registryHosts(registryConfig, 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 defaultResolver
	}
}