403禁止从Web角色实例调用Azure rest api时

时间:2013-11-08 02:49:07

标签: azure

我有一个非常奇怪的问题。我发布了一个webrole到azure云服务。在这个项目中,它需要webrole调用Azure Rest API,我可以在本地模拟器中获取响应,但是,如果我将其发布到Azure,我会得到403禁止错误。我确信我已将证书安装到Azure。

可以通过以下步骤重现此错误:

  1. 首先使用以下链接创建证书:http://msdn.microsoft.com/en-us/library/windowsazure/gg651127.aspx
  2. 使用webrole创建云服务,Azure门户中的证书,云服务证书和webrole-> property->证书。
  3. 发布项目。
  4. 远程登录Web角色实例。
  5. 在本地创建一个控制台应用程序,然后将调试文件夹复制到远程实例并在远程应用程序中运行exe。你可以发现应用程序可以在本地运行完美,但在Azure实例中,似乎它可以找到证书,但仍然得到403禁止错误。
  6. 控制台应用代码:

    static void Main(string[] args)
        {
            try
            {
                // X.509 certificate variables.
                X509Store certStore = null;
                X509Certificate2Collection certCollection = null;
                X509Certificate2 certificate = null;
    
                // Request and response variables.
                HttpWebRequest httpWebRequest = null;
                HttpWebResponse httpWebResponse = null;
    
                // Stream variables.
                Stream responseStream = null;
                StreamReader reader = null;
    
                // URI variable.
                Uri requestUri = null;
    
                // Specify operation to use for the service management call.
                // This sample will use the operation for listing the hosted services.
                string operation = "hostedservices";
    
                // The ID for the Windows Azure subscription.
                string subscriptionId = "";
    
                // The thumbprint for the certificate. This certificate would have been
                // previously added as a management certificate within the Windows Azure management portal.
                string thumbPrint = "";
    
                // Open the certificate store for the current user.
                certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                certStore.Open(OpenFlags.ReadOnly);
    
                // Find the certificate with the specified thumbprint.
                certCollection = certStore.Certificates.Find(
                                     X509FindType.FindByThumbprint,
                                     thumbPrint,
                                     false);
    
                // Close the certificate store.
                certStore.Close();
    
                // Check to see if a matching certificate was found.
                if (0 == certCollection.Count)
                {
                    throw new Exception("No certificate found containing thumbprint " + thumbPrint);
                }
    
                // A matching certificate was found.
                certificate = certCollection[0];
                Console.WriteLine("Using certificate with thumbprint: " + thumbPrint);
    
                // Create the request.
                requestUri = new Uri("https://management.core.windows.net/"
                                     + subscriptionId 
                                     + "/services/" 
                                     + operation);
    
                httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
    
                // Add the certificate to the request.
                httpWebRequest.ClientCertificates.Add(certificate);
    
                // Specify the version information in the header.
                httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
    
                // Make the call using the web request.
                httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
    
                // Display the web response status code.
                Console.WriteLine("Response status code: " + httpWebResponse.StatusCode);
    
                // Display the request ID returned by Windows Azure.
                 if (null != httpWebResponse.Headers)
                 {
                     Console.WriteLine("x-ms-request-id: "
                     + httpWebResponse.Headers["x-ms-request-id"]);
                 }
    
                // Parse the web response.
                responseStream = httpWebResponse.GetResponseStream();
                reader = new StreamReader(responseStream);
                // Display the raw response.
                Console.WriteLine("Response output:");
                Console.WriteLine(reader.ReadToEnd());
    
                // Close the resources no longer needed.
                httpWebResponse.Close(); 
                responseStream.Close(); 
                reader.Close();
            }
            catch (Exception e)
            {
    
                Console.WriteLine("Error encountered: " + e.Message);
    
                // Exit the application with exit code 1.
                Console.ReadLine();
                System.Environment.Exit(1);
    
            }
            finally
            {
                // Exit the application.
                Console.ReadLine();
                System.Environment.Exit(0);
            }
        }
    

3 个答案:

答案 0 :(得分:7)

我使用您提供的azure create cert链接遇到了同样的问题。我发现在使用该方法创建证书时,私钥未被上传到云服务。即使该服务能够找到证书,但在提交请求时仍然是未经授权的。

使用以下方法创建私钥和公钥证书。在Visual Studio命令提示符中,创建.cer.pfx文件:

makecert -r -pe -n "CN=AzureManage" -sky exchange "AzureManage.cer" -sv "AzureManage.pvk"
pvk2pfx -pvk "AzureManage.pvk" -spc "AzureManage.cer" -pfx "AzureManage.pfx" -pi password

第一个命令创建私钥和公钥文件。系统将提示您输入密码几次。第二个命令将两者合并为一个pfx文件。如果您关闭-pi password,系统将提示您输入密码,而不是在终端中输入密码。

然后,您需要适当地导入文件:

  • 使用mmc将pfx导入本地计算机/个人证书存储区。
  • 将pfx上传到Azure云服务。
  • 将cer上载到Azure管理证书存储区。
  • 将pfx的指纹添加到Azure角色证书属性。

然后,您可以按如下方式使用Azure管理REST API:

X509Certificate2 GetCertificate(string thumbprint)
{
  var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
  store.Open(OpenFlags.ReadOnly);
  var certs = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);

  if (certs.Count == 0) return null;
  var cert = certs[0];
  store.Close();
  return cert;
}

HttpWebRequest request = WebRequest.CreateHttp(apiUrl);
request.ClientCertificates.Add(cert);
request.Headers.Add("x-ms-version", "2012-03-01");

答案 1 :(得分:1)

我相信你的问题在于这行代码:

certStore = new X509Store(StoreName.My, **StoreLocation.CurrentUser**);

我希望正确上传的证书(假设它是通过管理门户正确上传的.pfx)存储在LocalMachine商店中,而不是CurrentUser。

此外,为了从证书存储中读取证书,您的角色需要以完全信任的方式运行(可以在Visual Studio的角色项目属性中指定/验证)

答案 2 :(得分:0)

+1 @Igorek。我遇到了类似的问题。如果我在我的配置中指定证书应该安装在CurrentUser商店中,我发现对于Web角色,certifcate会安装在那里,但对于Worker角色,证书安装在LocalUser商店中。

然而,看起来这不是问题的根本原因。您是否可以确保门户网站Management Certificates部分下面有相同的证书(以cer文件格式将其导出并在那里上传),并且角色中安装的证书附加了私有属性。这两个原因是403错误的主要原因。