【问题标题】:403 forbidden When call Azure rest api from a web role instance403 禁止从 Web 角色实例调用 Azure rest api
【发布时间】:2013-11-08 02:49:07
【问题描述】:

我有一个很奇怪的问题。我发布了一个 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->certificate 创建云服务。
  3. 发布项目。
  4. 远程登录网络角色实例。
  5. 在本地创建一个控制台应用程序,然后将调试文件夹复制到远程实例并在远程应用程序中运行 exe。您可以发现应用程序在本地可以完美运行,但在 Azure 实例中,它似乎可以找到证书,但仍然出现 403 禁止错误。

控制台应用代码:

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

【问题讨论】:

    标签: azure


    【解决方案1】:

    我在使用您提供的 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");
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 我认为这不是问题,我使用 var certificate = new X509Certificate2(@"C:\Cer.cer");这在本地和角色实例中(我将该cer复制到角色实例)代码可以在本地传递,在角色实例中返回403。我不知道为什么会这样。
      【解决方案3】:

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

      但是看起来这不是问题的根本原因。您能否确保门户中的Management Certificates 部分下存在相同的证书(以 cer 文件格式将其第一次导出并上传到那里),并且角色中安装的证书具有附加的私有属性。这两个原因是造成 403 错误的主要原因。

      【讨论】:

      • 谢谢你的帖子。 1,同样的应用程序可以在本地运行,所以我认为证书是没有问题的。 2,奇怪的是,应用程序显示,在角色实例中,它可以在我的代码中找到证书,但仍然无法通过身份验证。很奇怪
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-30
      • 1970-01-01
      • 2017-12-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-27
      相关资源
      最近更新 更多