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
}
}