Reputation: 463
I want to use the Azure API Management (management.core.windows.net
) to reboot role instance (ref to Microsoft documentation: https://learn.microsoft.com/en-us/rest/api/compute/cloudservices/rest-reboot-role-instance) but I'm getting a 403 as a response.
Request:
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
Response Body:
<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>
I get the Authentication - Bearer Token by calling (ref to Microsoft documentation: https://learn.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow#service-to-service-access-token-request):
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/
Any idea? Any missing configuration on the request or Azure Portal side? Is the management.core.windows.net
deprecated since I can use the management.azure.com
?
Notes:
app registration
for this, with a secret used to give permissions as contributor
;management.azure.com
API works with the Bearer Token. I can access other resources such as https://management.azure.com/subscriptions/{subscription-id}/resourcegroups?api-version=2017-05-10
but I can't access the https://management.core.windows.net/{subscription-id}/services/hostedservices
resources.SOLUTION
The problem was related to the certificate configuration
$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
Attention to the importance of the certificate to be a .pfx
CODE
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();
Upvotes: 2
Views: 1037
Reputation: 23151
According to your description, you want to manage Azure cloud service. Azure cloud service is 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
The detailed steps are as below
Upload certificate to Azure a. create a certificate
$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 upload .cer
file to Azure(Subscriptions -> your subscription -> Management certificates)
Code (for example, I list cloud service in my subscription )
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));
}
Upvotes: 2