Azure Management Service API gives deployment configuration in some Encrypted format - azure

I am using this code to get the deployment configurations.
X509Store certificateStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
certificateStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = certificateStore.Certificates.Find(
X509FindType.FindByThumbprint, certThumb, false);
if (certs.Count == 0)
{
Console.WriteLine("Couldn't find the certificate with thumbprint:" + certThumb);
return;
}
certificateStore.Close();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
new Uri("https://management.core.windows.net/" + subID +
"/services/hostedservices/" + hostedServiceName +
"/deploymentslots/" + deploymentType));
request.Method = "GET";
request.ClientCertificates.Add(certs[0]);
request.ContentType = "application/xml";
request.Headers.Add("x-ms-version", "2009-10-01");
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Parse the web response.
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
// Display the raw response.
Console.WriteLine("Deployment Details:");
string deployment = reader.ReadToEnd();
// Close the resources no longer needed.
responseStream.Close();
}
But I am getting configuration in encrypted format.
But if run azure powershell it gives me the configuration in plain text.
$deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
$deployedConfig = $deployment.Configuration
Since I have to use service management API how can I do it?

This is the expected behavior. REST API returns the data in Base64 encoded format. Since Windows Azure PowerShell consumes the same REST API, they convert the data from Base64 format and present it in humanly readable format. This is what you would also need to do.
So in your code you would do something like this:
string clearText = System.Text.Encoding.UTF8.GetString(
Convert.FromBase64String(reader.ReadToEnd()));

Related

How to get a token for specific user assigned managed service identity for Azure App Service?

I am trying to get a msi token for a specific User defined identity. Our app service has 2 user defined identities and I want a token on behalf of one of the user assigned identity.
Here is the code:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&object_id=<ObjectId>&client_id=<clientId>");
req.Headers["Metadata"] = "true";
req.Method = "GET";
try
{
// Call /token endpoint
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
// Pipe response Stream to a StreamReader, and extract access token
StreamReader streamResponse = new StreamReader(response.GetResponseStream());
string stringResponse = streamResponse.ReadToEnd();
Dictionary<string, string> list =
JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);
string accessToken = list["access_token"];
System.IO.File.WriteAllText(#".\Log.txt", accessToken);
}
catch (Exception e)
{
string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
System.IO.File.WriteAllText(#".\Log.txt", errorText);
throw;
}
It is deployed in an azure app service. When I hit this section I see this error:
An attempt was made to access a socket in a way forbidden by its access permissions
I tried connecting to http://169.254.169.254 to get the token using kudu console. But this endpoint does not seem to accessible there.
I did try to use AzureServiceTokenProvider from Microsoft.Azure.Services.AppAuthentication for generating msi token but could not find any documentation about how to use it for multiple user assigned identities.
Edit:
Update 1:
I tried to use endpoint from MSI_ENDPOINT environment variable instead of 169.254.169.254. But it looks like MSI_ENDPOINT value is not set when I run the app service.
Here is the code I have tried:
var endpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
string apiVersion = "2018-02-01";
string resource = "https://management.azure.com/";
string objectId = "<objectid>";
string clientId = "<clientId>";
// Build request to acquire managed identities for Azure resources token
//HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
// "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&object_id=4aef1720-b3b1-4935-8d68-e330508907fa&client_id=558ecc75-8697-4419-bab9-aa2c87043cfd");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
String.Format(
"{0}?resource={1}&api-version={2}&object_id={3}&client_id={4}",
endpoint,
resource,
apiVersion,
objectId,
clientId));
req.Headers["Metadata"] = "true";
req.Method = "GET";
try
{
// Call /token endpoint
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
// Pipe response Stream to a StreamReader, and extract access token
StreamReader streamResponse = new StreamReader(response.GetResponseStream());
string stringResponse = streamResponse.ReadToEnd();
Dictionary<string, string> list =
JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);
string accessToken = list["access_token"];
System.IO.File.WriteAllText(#".\Log.txt", accessToken);
}
catch (Exception e)
{
string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
string log = "MSI_ENDPOINT : " + endpoint + "\n";
log += ("ErrorText : " + errorText + "\n");
System.IO.File.WriteAllText(#".\Log.txt", errorText);
throw;
}
Firstly, this link How to use managed identities for App Service and Azure Functions provides good documentation specific to MSI for App Services.
Here is quick sample code.. to get token for a specific user assigned managed service identity as you've asked in your question.
resource - The AAD resource URI of the resource for which a token should be obtained.
apiversion - The version of the token API to be used. "2017-09-01" is currently the only version supported.
clientId - The ID of the user-assigned identity to be used. If omitted, the system-assigned identity is used.
public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
Overall I see a few changes that you should notice in the sample code above:
Make use of MSI_ENDPOINT to construct URL at runtime
parameter should be clientid and not client_id
parameter object_id is not needed
api version should be "2017-09-01" as documentation in above link says that's the only one supported.
About your issue with MSI_ENDPOINT value not being set when you run the app service, please take a look at this note from same link in Microsoft Docs
Screenshot from documentation that is relevant for all parameters used

Two way SSL X509 Certificate location for secure service request in .Net Core MVC - Azure Services Hosted application

I've being working with x509 certificates in order to make secure requests to some data services. They require Two way SSL auth, so I've converted my "Sandbox" certificate (.crt) w/ my Private Key to a Password protected .p12 file.
Here's the first question: Where should I place this .p12 file so that it's readable by my application after deploying to Azure (Using DevOps) but still stored securely? Can I use an my Azure Key Vault?
The second issue is that in my Dev environment I haven't been able to establish the SSL binding after making the request (With a .p12 absolute path):
Here's the code I'm using:
void GetATMs()
{
string requestURL = "https://sandbox.api.visa.com/globalatmlocator/v1/localatms/atmsinquiry";
string userId = "MyUserId";
string password = "MyPassword";
string p12certificatePath = "C:\\Code\\projects\\project\\\\Clients\\PaymentGateways\\Visa\\Certs\\TC_keyAndCertBundle.p12";
string p12certificatePassword = "CertPassword";
string postData = #"{""wsRequestHeaderV2"": { ""requestTs"": ""2018-11-06T03:16:18.000Z"", ""applicationId"": ""VATMLOC"", ""requestMessageId"": ""ICE01-001"", ""userId"": ""CDISIUserID"", ""userBid"": ""10000108"", ""correlationId"": ""909420141104053819418"" }, ""requestData"": { ""culture"": ""en-US"", ""distance"": ""20"", ""distanceUnit"": ""mi"", ""metaDataOptions"": 0, ""location"": { ""address"": null, ""placeName"": ""700 Arch St, Pittsburgh, PA 15212"", ""geocodes"": null }, ""options"": { ""range"": { ""start"": 10, ""count"": 20 }, ""sort"": { ""primary"": ""city"", ""direction"": ""asc"" }, ""operationName"": ""or"", ""findFilters"": [ { ""filterName"": ""OPER_HRS"", ""filterValue"": ""C"" } ], ""useFirstAmbiguous"": true } } }";
HttpWebRequest request = WebRequest.Create(requestURL) as HttpWebRequest;
request.Method = "POST";
// Add headers
string authString = userId + ":" + password;
var authStringBytes = System.Text.Encoding.UTF8.GetBytes(authString);
string authHeaderString = Convert.ToBase64String(authStringBytes);
request.Headers["Authorization"] = "Basic " + authHeaderString;
// Add certificate
var certificate = new X509Certificate2(p12certificatePath, p12certificatePassword);
request.ClientCertificates.Add(certificate);
request.Accept = "application/json";
var data = Encoding.ASCII.GetBytes(postData);
request.ContentLength = data.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(data, 0, data.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
What am I missing here?
It fails the following way:
An unhandled exception occurred while processing the request.
Win32Exception: The credentials supplied to the package were not recognized
System.Net.SSPIWrapper.AcquireCredentialsHandle(SSPIInterface secModule, string package, CredentialUse intent, SCHANNEL_CRED scc)
HttpRequestException: The SSL connection could not be established, see inner exception.
System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
WebException: The SSL connection could not be established, see inner exception. The credentials supplied to the package were not recognized
System.Net.HttpWebRequest.GetResponse()
We have a Wildcard SSL for our domain. Are they different? Can it be registered in the Visa dashboard and used for make secure request as it is signed by a trusted CA authority?
Well, yes. As per, #dagope Recommendation, I've uploaded my certificate to key-management on Azure and access it through the SDK. This is also a best practice for key/certificate management on Azure.

send message to Azure service bus by Azure scheduler using post

i want to send message to Azure service bus by Azure scheduler using post
like demo in this page
http://www.prasadthinks.com/
but i don't know how to set 'authorization' property in Http Header.
As far as I know, the 'authorization' property must contains the service bus's access token.
You could use your shared access policies's key-name and key to generate the access token by using codes.
More details, you could refer to below codes.
string keyName = "keyname";
string key = "key";
var sasToken = createToken("http://yourservicebusname.servicebus.windows.net/queuename", keyName, key);
createToken function:
private static string createToken(string resourceUri, string keyName, string key)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 7200); //EXPIRES in 2h
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
//this is the auth token
var sasToken = String.Format(CultureInfo.InvariantCulture,
"SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
return sasToken;
}
The result is like below:
This is the 'authorization' property, you could copy it.But this token has two hours limit.
The azure scheduler job setting like below:
Besides, the azure scheduler job have already support send the message to the service bus, you don't need to create the sas token by yourself, you could just add the keyName and key in its authentication settings.
More details, you could refer to below images:

Windows Azure Cloud App - Could not create SSL/TLS secure channel

I am trying to pull JSON from a customer's website, but I get this error.
The code works my local machine.
For other sites, both on my local machine and on the server, the code works.
The site is https://www.vapedepot.ca/wc-api/v1
Does he have a special SSL cert where I need to change my code? Here is my code:
string GetJson(string url)
{
string resultData = string.Empty;
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
myHttpWebRequest.Accept = "application/json";
myHttpWebRequest.Timeout = 6000;
//myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
string userP = m_UserName + ":" + m_Password;
byte[] authBytes = Encoding.UTF8.GetBytes(userP).ToArray();
myHttpWebRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(authBytes));
WebResponse httpResponse = myHttpWebRequest.GetResponse();
Stream responseStream = httpResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
resultData = reader.ReadToEnd();
responseStream.Close();
httpResponse.Close();
return resultData;
}
He is using CloudFlare and the SSL uses ecdsa.
I had the same issue. I swapped to using RestSharp to make my secure web requests and it resolved my issue.

Creating Azure Traffic Manager through REST API - unexpected behaviour

I created Traffic Manager throught its REST API using 2011-10-01 MS verion.
Resources I followed -
Create Profile -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758254.aspx
Create Definition -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758257.aspx
Traffic Manager got created successfully. All happies.
But after 30mins of time, traffic manager is going to INACTIVE status and all its endpoints are GONE. It shows there are no endpoints associated with it.
I am not sure what is happening around. Is it Azure problem? or is it REST API problem? or is it my way of creating Traffic manager problem.
PS - I followed this sample for making REST API calls - http://msdn.microsoft.com/en-us/library/windowsazure/gg651127.aspx
Any help would be highly appreciated.
UPDATE1
Parameters
SubscriptionID - a Valid GUID from publishsettings
Certificate - I cross checked a valid certificate present in the local cert store
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name - JASH23.CLOUDAPP.NET
There is no error at REST API calls level. Everything worked seamlessly.
Profile Creation -
// 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;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// 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];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Profile xmlns=""http://schemas.microsoft.com/windowsazure""><DomainName>" + ProfileDomain + "</DomainName><Name>" + ProfileName + "</Name></Profile>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
Definition Creation-
// 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;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// 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];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles/" + ProfileName + "/definitions");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Definition xmlns=""http://schemas.microsoft.com/windowsazure""><DnsOptions><TimeToLiveInSeconds>300</TimeToLiveInSeconds></DnsOptions><Monitors><Monitor><IntervalInSeconds>30</IntervalInSeconds><TimeoutInSeconds>10</TimeoutInSeconds><ToleratedNumberOfFailures>3</ToleratedNumberOfFailures><Protocol>HTTP</Protocol><Port>80</Port><HttpOptions><Verb>GET</Verb><RelativePath>/</RelativePath><ExpectedStatusCode>200</ExpectedStatusCode></HttpOptions></Monitor></Monitors><Policy><LoadBalancingMethod>RoundRobin</LoadBalancingMethod><Endpoints><Endpoint><DomainName>" + PrimaryService + "</DomainName><Status>Enabled</Status></Endpoint><Endpoint><DomainName>" + SecondaryService + "</DomainName><Status>Enabled</Status></Endpoint></Endpoints></Policy></Definition>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
UPDATE2
Once the TM went into Inactive State, I checked the profile definition using REST API. In there I was not able to find any endpoints. They are missing.
<Definitions xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Definition>
<DnsOptions>
<TimeToLiveInSeconds>300</TimeToLiveInSeconds>
</DnsOptions>
<Status>Enabled</Status>
<Version>1</Version>
<Monitors>
<Monitor>
<IntervalInSeconds>30</IntervalInSeconds>
<TimeoutInSeconds>10</TimeoutInSeconds>
<ToleratedNumberOfFailures>3</ToleratedNumberOfFailures>
<Protocol>HTTP</Protocol>
<Port>80</Port>
<HttpOptions>
<Verb>GET</Verb>
<RelativePath>/</RelativePath>
<ExpectedStatusCode>200</ExpectedStatusCode>
</HttpOptions>
</Monitor>
</Monitors>
<Policy>
<LoadBalancingMethod>Performance</LoadBalancingMethod>
<Endpoints/>
<MonitorStatus>Inactive</MonitorStatus>
</Policy>
</Definition>
</Definitions>
UPDATE3
This sporadic behavior is ONLY happening with the specific cloud services and TM profile/definitiona. When I create new set of cloud services and TM profile, then everything seems to be working fine. I tested this multiple times. So the only problem is with following parameters.
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name -JASH23.CLOUDAPP.NET
TM Domain - ramitm.trafficmanager.net
TM profilename - ramitm
This seems like some DNS Problems for very fast REST API Operations. I was not able to get the crux of the problem, but this is how I solved it.
Previously I was getting this problem for this patter - Create -> Delete -> Re-Create
Now I made it this way - Create -> Delete -> Delay -> Re-Create
I think by introducing delay component, I am giving enough time for Azure to settle down all the DNS and infrastructure and there by update them. So after introducing delay, I was not experiencing the problem. Delay can be 5 - 10 mins.

Resources