为什么我使用 Azure 服务管理 API 时收到 403?

Why I'm I getting a 403 using Azure Service Management API?

我想使用 Azure API 管理 (management.core.windows.net) 来重启角色实例(参考 Microsoft 文档:https://docs.microsoft.com/en-us/rest/api/compute/cloudservices/rest-reboot-role-instance)但我收到 403 作为响应.

要求:

https://management.core.windows.net/{subscription-id}/services/hostedservices/{hosted-service}/deploymentslots/staging/roleinstances/{role-instance-name}?comp=reboot`

Headers:
- Authorization: Bearer {token}
- Content-Type: application/xml
- x-ms-version: 2010-10-28
- Content-Length: 0

Body: Empty

响应正文:

<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Code>ForbiddenError</Code>
    <Message>The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.</Message>
</Error>

我通过调用(参考 Microsoft 文档:https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow#service-to-service-access-token-request)获得身份验证 - Bearer Token:

https://login.microsoftonline.com/{tenant_id}/oauth2/token

Headers:
- Content-Type: application/x-www-form-urlencoded

Body: 
- grant_type: client_credentials,
- client_id: {client_id}
- client_secret: {client_secret}
- resource: https://management.core.windows.net/

有什么想法吗?请求或 Azure 门户端是否缺少任何配置? management.core.windows.net 是否已弃用,因为我可以使用 management.azure.com

备注:


解决方案

问题与证书配置有关

$cert = New-SelfSignedCertificate -Subject "CN=Azure Management API" -CertStoreLocation "cert:\LocalMachine\My" -KeyLength 2048 -KeySpec "KeyExchange" -NotAfter (Get-Date).AddMonths(360)
$password = ConvertTo-SecureString -String "strong-password-here" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath ".\azure-management-api.pfx" -Password $password
Export-Certificate -Type CERT -Cert $cert -FilePath .\azure-management-api.cer

注意证书的重要性.pfx

代码

   var cert = new X509Certificate2( File.ReadAllBytes( "your-certificate-path.pfx" ), "your_password" );
            var httpClientHandler = new HttpClientHandler
            {
                UseProxy = false,
                ClientCertificateOptions = ClientCertificateOption.Manual
            };
            httpClientHandler.ClientCertificates.Add( cert );
            var httpClient = new HttpClient( httpClientHandler );
            httpClient.DefaultRequestHeaders.Add( "Accept", "application/xml" );
            httpClient.DefaultRequestHeaders.Add( "Host", "management.core.windows.net" );
            httpClient.DefaultRequestHeaders.Add( "x-ms-version", "2010-10-28" );
            var uri = $"https://management.core.windows.net/{subscriptionId}/services/hostedservices";
            Console.WriteLine( $"GET {uri} [{httpClient.DefaultRequestVersion}]" );
            foreach ( var header in httpClient.DefaultRequestHeaders )
            {
                Console.WriteLine( $"{header.Key} {header.Value.First()}" );
            }
            var response = httpClient.GetAsync( uri )
                .GetAwaiter()
                .GetResult();
            var content = response.Content.ReadAsStringAsync()
                .GetAwaiter()
                .GetResult();
            Console.WriteLine( $"{(int)response.StatusCode} {response.StatusCode}" );
            Console.WriteLine( content );
            httpClient.Dispose();
            httpClientHandler.Dispose();

根据您的描述,您想管理Azure云服务。 Azure 云服务是 Azure classic resource. So we need to use Azure service management API to manage it. If we want to call the API, we need to do X509 client certificates authentication. For more details, please refer to the document

详细步骤如下

  1. 将证书上传到 Azure 一种。创建证书

    $cert = New-SelfSignedCertificate -DnsName yourdomain.cloudapp.net -CertStoreLocation "cert:\LocalMachine\My" -KeyLength 2048 -KeySpec "KeyExchange"
    $password = ConvertTo-SecureString -String "your-password" -Force -AsPlainText
    Export-PfxCertificate -Cert $cert -FilePath ".\my-cert-file.pfx" -Password $password
    Export-Certificate -Type CERT -Cert $cert -FilePath .\my-cert-file.cer
    

    b 将 .cer 文件上传到 Azure(订阅 -> 您的订阅 -> 管理证书)

  2. 代码(例如,我在订阅中列出了云服务)

 static async Task Main(string[] args)
 {
   var _clientHandler = new HttpClientHandler();
                _clientHandler.ClientCertificates.Add(GetStoreCertificate("the cert's thumbprint" ));
                _clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
                String uri = string.Format("https://management.core.windows.net/{0}/services/hostedservices", "subscription id");
                using (var _client = new HttpClient(_clientHandler))
                using (var request = new HttpRequestMessage(HttpMethod.Get, uri)) {
  
                    request.Headers.Add("x-ms-version", "2014-05-01");
                    request.Headers.Add("Accept", "application/xml");
                    //request.Headers.Add("Content-Type", "application/xml");
                    using (HttpResponseMessage httpResponseMessage = await _client.SendAsync(request)) {
                        string xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
                        Console.WriteLine(httpResponseMessage.StatusCode);
                        Console.WriteLine(xmlString);
                    }

                }
}
private static X509Certificate2 GetStoreCertificate(string thumbprint)
        {


            X509Store store = new X509Store("My", StoreLocation.LocalMachine);
            try
            {
                store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
                X509Certificate2Collection certificates = store.Certificates.Find(
                  X509FindType.FindByThumbprint, thumbprint, false);
                if (certificates.Count == 1)
                {
                    return certificates[0];
                }
            }
            finally
            {
                store.Close();
            }

            throw new ArgumentException(string.Format(
              "A Certificate with Thumbprint '{0}' could not be located.",
              thumbprint));
        }