dotnet / Docker.DotNet

:whale: .NET (C#) Client Library for Docker API
https://www.nuget.org/packages/Docker.DotNet/
MIT License
2.23k stars 381 forks source link

Can't load image from private ECR registry #633

Closed Schwimo closed 1 year ago

Schwimo commented 1 year ago

Output of dotnet --info:

.NET SDK:
 Version:   7.0.203
 Commit:    5b005c19f5

Laufzeitumgebung:
 OS Name:     Windows
 OS Version:  10.0.22621
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\7.0.203\

Host:
  Version:      7.0.5
  Architecture: x64
  Commit:       8042d61b17

What version of Docker.DotNet?:

3.125.14

Steps to reproduce the issue:

var progress = new Progress<JSONMessage>();
progress.ProgressChanged += Progress_ProgressChanged;

// Get the ECR authorization token            
var response = await ecrClient.GetAuthorizationTokenAsync(new GetAuthorizationTokenRequest());

// Extract the authorization token and registry URL
var token = response.AuthorizationData[0].AuthorizationToken;
var registryUrl = response.AuthorizationData[0].ProxyEndpoint;

var imagesCreateParameters = new ImagesCreateParameters
{
    FromImage = dockerImage,  // my-private-ecr-registry/repo-name
    Tag = "latest"
};

var auth = new AuthConfig
{
    Username = "AWS",
    Password = token,
    ServerAddress = registryUrl,
};

await client.Images.CreateImageAsync(imagesCreateParameters, auth, progress);

What actually happened?: I received an token. But the following error occurs: repository does not exist or may require 'docker login': denied: Your Authorization Token is invalid.

What did you expect to happen?:

Additional information: When I ececute docker pull image_name locally from a terminal, it works.

Serraniel commented 1 year ago

I am currently experimenting with this SDK and Amazon ECR, too. The Amazon Auth token is a bas64 string in format username:password.

I managed to pass the authorization by using the BasicAuthCredentials with following code:

            var token = Encoding.UTF8.GetString(
                Convert.FromBase64String(response.AuthorizationData.FirstOrDefault()?.AuthorizationToken ?? ""));
            var partials = token.Split(':');

            return new BasicAuthCredentials(StrToSecureString(partials[0]), StrToSecureString(partials[1]));

However, I fail to fetch a list of images from the registry, I get an exception

Docker.DotNet.DockerApiException: "Docker API responded with status code=NotFound, response=404 page not found"

Schwimo commented 1 year ago

Thanks @Serraniel Didn't think about the base64 string format. Now it works.

As far as I understood, the BasicAuthCredentials are used if your docker engine needs other credentials. They are not used for a container registry. It works with passing the converted token within the auth config.

I did the following:

// Get the ECR authorization token            
var getAuthorizationTokenRequest = new GetAuthorizationTokenRequest();
var response = await ecrClient.GetAuthorizationTokenAsync(getAuthorizationTokenRequest);

var base64Token = Convert.FromBase64String(response.AuthorizationData[0].AuthorizationToken);
// The token now contains the login name and the token in this format:
// AWS:Token
var token = Encoding.UTF8.GetString(base64Token);
// That's why we split it here
var partials = token.Split(':');

// Extract the authorization token and registry URL
//var token = response.AuthorizationData[0].AuthorizationToken;
var registryUrl = response.AuthorizationData[0].ProxyEndpoint;

var imagesCreateParameters = new ImagesCreateParameters
{
    FromImage = dockerImage + ":latest"
};

var auth = new AuthConfig
{
    Username = partials[0],
    Password = partials[1],
    ServerAddress = registryUrl,
};

await client.Images.CreateImageAsync(imagesCreateParameters, auth, progress);