使用证书身份验证调用Azure资源费率API时获取403 [英] Getting a 403 when calling Azure Resource Rate API using certificate auth

查看:53
本文介绍了使用证书身份验证调用Azure资源费率API时获取403的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个控制台应用程序,该应用程序可以调用 Azure资源费率API 使用证书身份验证.为此,我使用了以下分支 GitHub链接.

I am trying to create a console app that can call the Azure Resource Rate API using certificate authentication. For this, I used the following branch GitHub link.

我收到403错误.我已经将一个Web应用程序添加到了我的Azure AD.在清单中,我已使用以下PowerShell命令从已签名的证书中复制了密钥凭据;

I am getting a 403 error. I've added an Web App to my Azure AD. In the manifest, I've copied the key credentials from the certificate I've signed using the following PowerShell commands;

$cert=New-SelfSignedCertificate -Subject "CN=RateCardCert"
-CertStoreLocation "Cert:\CurrentUser\My"  -KeyExportPolicy Exportable -KeySpec Signature  
$bin = $cert.RawData $base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cert.GetCertHash() 
$base64Thumbprint = [System.Convert]::ToBase64String($bin) 
$keyid = [System.Guid]::NewGuid().ToString() 
$jsonObj = @ customKeyIdentifier=$base64Thumbprint;keyId=$keyid;type="AsymmetricX509Cert";usage="Verify";value=$base64Value} 
$keyCredentials=ConvertTo-Json @($jsonObj) | Out-File "keyCredentials.txt"

在控制台应用程序中,我使用以下函数来获取令牌;

In de console app, I use the following function to get the token;

public static string GetOAuthTokenFromAAD_ByCertificate(string TenanatID, string ClientID, string CertificateName)
    {
        //Creating the Authentication Context
        var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", TenanatID));
        //Console.WriteLine("new authContext made");
        //Creating the certificate object. This will be used to authenticate
        X509Certificate2 cert = null;
        //Console.WriteLine("empty 'cert' made, null");
        //The Certificate should be already installed in personal store of the current user under 
        //the context of which the application is running.
        X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);


        try
        {
            //Trying to open and fetch the certificate
            store.Open(OpenFlags.ReadOnly);
            var certCollection = store.Certificates;
            var certs = certCollection.Find(X509FindType.FindBySubjectName, CertificateName, false);
            //Checking if certificate found
            if (certs == null || certs.Count <= 0)
            {
                //Throwing error if certificate not found
                throw new Exception("Certificate " + CertificateName + " not found.");
            }
            cert = certs[0];
        }
        finally
        {
            //Closing the certificate store
            store.Close();
        }

        //Creating Client Assertion Certificate object
        var certCred = new ClientAssertionCertificate(ClientID, cert);

        //Fetching the actual token for authentication of every request from Azure using the certificate
        var token = authContext.AcquireToken("https://management.core.windows.net/", certCred);

        //Optional steps if you need more than just a token from Azure AD
        //var creds = new TokenCloudCredentials(subscriptionId, token.AccessToken);
        //var client = new ResourceManagementClient(creds); 

        //Returning the token
        return token.AccessToken;
    }

这是构成URL并放入请求的代码部分(xxxx部分已由我已在Azure AD中注册的Web应用的ClientID替换);

This is the part of the code that makes the URL and puts in the request (the xxxx part is replaced by the ClientID of the webapp that I've registered in Azure AD);

//Get the AAD User token to get authorized to make the call to the Usage API
        string token = GetOAuthTokenFromAAD_ByCertificate("<MyTenantName.onmicrosoft.com", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "RateCardCert");


            // Build up the HttpWebRequest
        string requestURL = String.Format("{0}/{1}/{2}/{3}",
                   ConfigurationManager.AppSettings["ARMBillingServiceURL"],
                   "subscriptions",
                   ConfigurationManager.AppSettings["SubscriptionID"],
                   "providers/Microsoft.Commerce/RateCard?api-version=2015-06-01-preview&$filter=OfferDurableId eq 'MS-AZR-0044P' and Currency eq 'EUR' and Locale eq 'nl-NL' and RegionInfo eq 'NL'");
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);

        // Add the OAuth Authorization header, and Content Type header
        request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
        request.ContentType = "application/json";

        // Call the RateCard API, dump the output to the console window
        try
        {
            // Call the REST endpoint
            Console.WriteLine("Calling RateCard service...");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Console.WriteLine(String.Format("RateCard service response status: {0}", response.StatusDescription));
            Stream receiveStream = response.GetResponseStream();

            // Pipes the stream to a higher level stream reader with the required encoding format. 
            StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
            var rateCardResponse = readStream.ReadToEnd();
            Console.WriteLine("RateCard stream received.  Press ENTER to continue with raw output.");
            Console.ReadLine();
            Console.WriteLine(rateCardResponse);
            Console.WriteLine("Raw output complete.  Press ENTER to continue with JSON output.");
            Console.ReadLine();

            // Convert the Stream to a strongly typed RateCardPayload object.  
            // You can also walk through this object to manipulate the individuals member objects. 
            RateCardPayload payload = JsonConvert.DeserializeObject<RateCardPayload>(rateCardResponse);

            Console.WriteLine(rateCardResponse.ToString());
            response.Close();
            readStream.Close();
            Console.WriteLine("JSON output complete.  Press ENTER to close.");
            Console.ReadLine();
        }
        catch(Exception e)
        {
            Console.WriteLine(String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : ""));
            Console.ReadLine();
        }

我就是不知道该做什么了,我在这里想念什么?

I just don't know what I have to do anymore, what am I missing here??

控制台的完整返回是:

正在致电价目表服务...远程服务器返回错误:(403)禁止.

Calling RateCard Service... The remote server returned an error: (403) Forbidden.

推荐答案

在评论中聊天之后,发现了问题:

After a chat in the comments the problem was found:

您正在调用Azure资源管理API,但是只授予了对Azure服务管理API的权限.您需要将应用程序的服务主体添加到订阅中的角色.找到您的订阅,然后找到访问控制(IAM)刀片,然后将您的应用添加到该角色中.您应该可以找到它的名字.

You are calling the Azure Resource Management API, but you gave permissions only on the Azure Service Management API. You need to add your app's service principal to a role in your subscription. Find your subscription, then the Access Control (IAM) blade, and then add your app to a role there. You should be able to find it with its name.

如果要限制服务主体的功能,还可以将其添加到资源组甚至特定资源上的角色.

You can also add the service principal to a role on a resource group or even specific resources if you want to limit its capabilities.

这篇关于使用证书身份验证调用Azure资源费率API时获取403的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆