我正在尝试从各种容器映像注册表中获取映像清单信息。为了进行身份验证,我已经通过 Docker 实现了令牌规范(https://docs.docker.com/registry/spec/auth/token/),它似乎正在与 Docker Hub(公共和私有存储库)、Azure容器注册服务和谷歌容器注册服务。AWS Elastic Container Registry Service 似乎需要对 GetAuthorizationToken API 进行额外调用,该 API 返回要在基本 Http 身份验证中使用的用户名和密码。我的理解是否正确(根据 Docker 令牌规范)我无法使用固定的用户名和密码对,然后使用 WWW-Authenticate 质询标头我可以获得不记名令牌来获取访问令牌?
我现在面临的挑战是,我需要根据它是 AWS ECR 还是其他注册表服务来对我的代码进行特殊情况下的身份验证。
到目前为止我的 C# 代码:
class Program
{
internal sealed class BearerToken
{
public string token;
public string access_token;
public string scope;
public string expires_in;
public string issued_at;
public string refresh_token;
}
private static HttpClient httpClient = new HttpClient()
{
Timeout = TimeSpan.FromSeconds(100)
};
static void Main(string[] args)
{
string imagename = "hello-world:latest";
Uri manifestUri = new Uri("https://619296171463.dkr.ecr.us-east-2.amazonaws.com/v2/hello-world/manifests/latest");
// aws access key id
//string username = "AWSACCESSKEYID";
// aws secret access key
//string password = "AWSSECRETACCESSKEY";
// aws ecr get-login output
string username = "AWS";
string password = "24HRSLONGPASSWORDSTRING";
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, manifestUri);
requestMessage.Headers.Add("Accept", "application/vnd.docker.distribution.manifest.v2+json");
HttpResponseMessage responseMessage = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None).GetAwaiter().GetResult();
if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
{
/*string authorizationHeaderChallenge = responseMessage.Headers.WwwAuthenticate.ToString();
string[] challengeItems = authorizationHeaderChallenge.Split(new char[] { ' ' }, 2);
string authScheme = challengeItems[0];
string authParamFormat = @"(?<key>\w+)=([""'])(?<value>.*)([""'])";
Regex authParamRegEx = new Regex(authParamFormat);
var authParamsItems = challengeItems[1].Split(',');
Dictionary<string, string> authParams = new Dictionary<string, string>();
foreach (var authParam in authParamsItems)
{
var match = authParamRegEx.Match(authParam);
authParams[match.Groups["key"].Value] = match.Groups["value"].Value;
}
UriBuilder uriBuilder = new UriBuilder($"{authParams["realm"]}");
//string query = $"{"scope"}={"repository:containerimageinfoproject/demo-image:pull"}&{ "service"}={authParams["service"]}";
string query = $"{"service"}={authParams["service"]}";
uriBuilder.Query = query;
Uri authorizationEndPoint = uriBuilder.Uri;*/
string authenticationTokenValue = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}"));
requestMessage = new HttpRequestMessage(HttpMethod.Get, manifestUri);
requestMessage.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authenticationTokenValue);
responseMessage = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None).GetAwaiter().GetResult();
string response = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
/*BearerToken bearerToken = JsonConvert.DeserializeObject<BearerToken>(response);
requestMessage = new HttpRequestMessage(HttpMethod.Get, manifestUri);
requestMessage.Headers.Add("Accept", "application/vnd.docker.distribution.manifest.v2+json");
requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken.token);
responseMessage = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None).GetAwaiter().GetResult();*/
}
}
}
在这里,如果我使用 (username, password) = (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) 那么我会不断得到:
{StatusCode:401,ReasonPhrase:'未授权',版本:1.1,内容:System.Net.Http.StreamContent,标头:{ Docker-Distribution-Api-Version:registry/2.0 连接:keep-alive 日期:星期三,8 月 1 日2018 年 21:40:37 GMT WWW-Authenticate: Basic realm="https://619296171463.dkr.ecr.us-east-2.amazonaws.com/",service="ecr.amazonaws.com" 内容长度: 15 内容类型:文本/纯文本;字符集=utf-8 }}
而如果我使用 (username, password) = ("AWS", "LONGPASSWORD_GENERATED_USING_AWS_ECR_GETLOGIN"),我可以获得图像清单。