I want to get all uploaded certificate on storage in azure to use these certificate associate with VM when I creating VM's using rest-api to.
Is it necessary, the certificate should available on local machine?
If yes, is there any way to install certificate locally, when the web site/ portal in open on any machine.
You need to install the certificate on each machine that uses REST api to be able to function.
The point of the private and public keys are to maintain security. I dont think this would be something you would want to put on a website for anyone to be able to install.
That being said, if you are making the REST call via a website, then only the server hosting the application needs to have the certificate installed.
I build a webrequest that has the REST URL in it, like this one, then build the response.
private HttpWebResponse CallAzure(HttpWebRequest request, string postData)
{
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certificateStore.Open(OpenFlags.ReadOnly);
var certs = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);
if (request.Method.ToUpper() == "POST")
{
var xDoc = new XmlDocument();
xDoc.LoadXml(postData);
var requestStream = request.GetRequestStream();
var streamWriter = new StreamWriter(requestStream, Encoding.UTF8);
xDoc.Save(streamWriter);
streamWriter.Close();
requestStream.Close();
}
request.ClientCertificates.Add(certs[0]);
request.ContentType = "application/xml";
request.Headers.Add("x-ms-version", "2012-03-01");
ServicePointManager.Expect100Continue = false;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
request.ServicePoint.Expect100Continue = false;
var response = request.GetResponse();
return (HttpWebResponse)response;
}
I have found it easiest to install the certificate via PowerShell.
If you want to generate your own publishsettingfile here is a very easy app to do it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.IO;
namespace CreatePublishSettingsFile
{
class Program
{
private static string subscriptionId = "[your subscription id]";
private static string subscriptionName = "My Awesome Subscription";
private static string certificateThumbprint = "[certificate thumbprint. the certificate must have private key]";
private static StoreLocation certificateStoreLocation = StoreLocation.CurrentUser;
private static StoreName certificateStoreName = StoreName.My;
private static string publishFileFormat = #"<?xml version=""1.0"" encoding=""utf-8""?>
<PublishData>
<PublishProfile
PublishMethod=""AzureServiceManagementAPI""
Url=""https://management.core.windows.net/""
ManagementCertificate=""{0}"">
<Subscription
Id=""{1}""
Name=""{2}"" />
</PublishProfile>
</PublishData>";
static void Main(string[] args)
{
X509Store certificateStore = new X509Store(certificateStoreName, certificateStoreLocation);
certificateStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = certificateStore.Certificates;
var matchingCertificates = certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
if (matchingCertificates.Count == 0)
{
Console.WriteLine("No matching certificate found. Please ensure that proper values are specified for Certificate Store Name, Location and Thumbprint");
}
else
{
var certificate = matchingCertificates[0];
certificateData = Convert.ToBase64String(certificate.Export(X509ContentType.Pkcs12, string.Empty));
if (string.IsNullOrWhiteSpace(subscriptionName))
{
subscriptionName = subscriptionId;
}
string publishSettingsFileData = string.Format(publishFileFormat, certificateData, subscriptionId, subscriptionName);
string fileName = Path.GetTempPath() + subscriptionId + ".publishsettings";
File.WriteAllBytes(fileName, Encoding.UTF8.GetBytes(publishSettingsFileData));
Console.WriteLine("Publish settings file written successfully at: " + fileName);
}
Console.WriteLine("Press any key to terminate the program.");
Console.ReadLine();
}
}
}
Related
I can create a custom domain using the Azure Management REST API, and I can create an App Service Managed certificate, which is associated with the custom domain (I think). Maybe not. However, under custom domains in my app service, it shows that I need to add a binding.
Here is the certificate:
https://management.azure.com/subscriptions/xxx-xxx-479a-bb9f-4c7e01d9a379/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/xxx20211028195113/hostNameBindings/my.site?api-version=2016-08-01
and
https://management.azure.com/subscriptions/xxx-xxx-479a-bb9f-4c7e01d9a379/resourceGroups/MyResourceGroup/providers/Microsoft.Web/certificates/my.site?api-version=2021-02-01
I used the first end-point to create the custom domain, and the second end-point to create the certificate. I'm not sure how to bind the certificate to the custom domain. I expected the call to create certificate to do that for me since I included the serverFarm in the request body, but it didn't work.
I want to use the Azure Management API to bind the certificate to the custom domain. How can I do that? which endpoint should I use and what values need to be set in the request body?
Any help would be appreciated. Thanks.
For my full code reference, see my other post here:
C# .Net Azure Management REST API - Add App Service Managed Certificate - Response = Not Found
EDIT: Showing the Complete Answer
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MyShoppingCart.Helpers.ManagementLibrarySample
{
public class ManagementLibrarySample
{
static string _ClientId = Startup.StaticConfig.GetValue<string>("Azure:ClientId");
static string _ClientKey = Startup.StaticConfig.GetValue<string>("Azure:ClientSecret");
static string _TenantId = Startup.StaticConfig.GetValue<string>("Azure:TenantId");
static string _SubscriptionId = Startup.StaticConfig.GetValue<string>("Azure:SubscriptionId");
static string _ResourceGroupName = Startup.StaticConfig.GetValue<string>("Azure:ResourceGroupName");
static string _AlternateResourceGroupName = Startup.StaticConfig.GetValue<string>("Azure:AlternateResourceGroupName");
static string _AppName = Startup.StaticConfig.GetValue<string>("Azure:AppName");
static string _AppServicePlanName = Startup.StaticConfig.GetValue<string>("Azure:AppServicePlanName");
static Uri _baseURI = new Uri($"https://management.azure.com/");
private static string GetAccessToken()
{
var context = new AuthenticationContext("https://login.windows.net/" + _TenantId);
ClientCredential clientCredential = new ClientCredential(_ClientId, _ClientKey);
var tokenResponse = context.AcquireTokenAsync(_baseURI.ToString(), clientCredential).Result;
return tokenResponse.AccessToken;
}
public static async Task<bool> CreateCustomDomainAndCertificate(string sHostName)
{
bool ret = false;
HttpResponseMessage responseMessage = await CreateCustomDomain(sHostName);
if (responseMessage.IsSuccessStatusCode)
{
responseMessage = await CreateAppManagedCertificate(sHostName);
/*
it can take a good 5 minutes to create the certificate
but you get the 202 status code right away.
You cannot bind the certificate to the custom domain
name until after the certificate actually exists.
*/
if ((long)responseMessage.StatusCode == 202)// Accepted
{
DateTime dtStart = DateTime.Now;
while ((long)responseMessage.StatusCode != 200 && DateTime.Now < dtStart.AddMinutes(10))
{//Wait until the certificate has been created, up to 10 minutes
Thread.Sleep(60000);//1 minute
responseMessage = await BindCertificateToCustomDomain(sHostName);
}
if ((long)responseMessage.StatusCode == 200)
ret = true;
}
}
return ret;
}
private static async Task<HttpResponseMessage> CreateCustomDomain(string sHostName)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
string requestURl = _baseURI + $"subscriptions/{_SubscriptionId}/resourceGroups/{_ResourceGroupName}/providers/Microsoft.Web/sites/{_AppName}/hostNameBindings/{sHostName}?api-version=2016-08-01";
string body = $"{{\"properties\": {{\"azureResourceName\": \"{_AppName}\"}}}}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
return await client.PutAsync(requestURl, stringContent);
}
}
private static async Task<HttpResponseMessage> CreateAppManagedCertificate(string sHostName)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
string requestURl = _baseURI + $"subscriptions/{_SubscriptionId}/resourceGroups/{_ResourceGroupName}/providers/Microsoft.Web/certificates/{sHostName}?api-version=2021-02-01";
string serverFarm = $"/subscriptions/{_SubscriptionId}/resourceGroups/{_AlternateResourceGroupName}/providers/Microsoft.Web/serverfarms/{_AppServicePlanName}";
string body = $"{{\"location\": \"West US\", \"properties\": {{\"canonicalName\": \"{sHostName}\", \"hostNames\": [\"{sHostName}\"], \"serverFarmId\": \"{serverFarm}\"}}}}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
return await client.PutAsync(requestURl, stringContent);
}
}
private static async Task<HttpResponseMessage> BindCertificateToCustomDomain(string sHostName)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
string requestURl = _baseURI + $"subscriptions/{_SubscriptionId}/resourceGroups/{_ResourceGroupName}/providers/Microsoft.Web/sites/{_AppName}?api-version=2016-08-01";
string serverFarm = $"/subscriptions/{_SubscriptionId}/resourceGroups/{_AlternateResourceGroupName}/providers/Microsoft.Web/serverfarms/{_AppServicePlanName}";
string body = $"{{\"location\": \"West US\", \"properties\": {{\"HostNameSslStates\": [ {{ \"SslState\" : \"1\", \"ToUpdate\" : \"True\", \"Name\": \"{sHostName}\"}}]}}, \"kind\": \"app\", \"location\": \"West US\", \"tags\" : {{\"hidden-related:{serverFarm}\": \"empty\"}}}}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
return await client.PutAsync(requestURl, stringContent);
}
}
}
}
How can I use the Management API to secure the custom domain with the
app service managed certificate?
Thanks #David.Warwick for the confirmation,
As we have discussed to achieve the above requirement we have to use the below Rest API .
You can try with PUT method for binding SSL certificate with Custom domain.
https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{snapshotName}?api-version={api-version}
For more information please refer this SO THREAD
I am migrating our legacy application into Azure Cloud . In the existing application we are securing our Jetty Server while starting so for that we are using jks file to secure our Jetty server .
Now we are moving into Azure Cloud so we have to fetch the .jks file from Azure keyvault . So how to fetch the complete .jks file from Azure keyvault . I am able to fetch the secrets from Keyvault but unable to fetch the certificate (which i uploaded in Azure keyvault). I am not sure whether we have any API which gives the certificate file.
Below code i am using to fetch the secrets & certificates:
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
import com.microsoft.azure.keyvault.models.CertificateBundle;
import com.microsoft.azure.keyvault.models.SecretBundle;
public class DemoTest {
private static String vaultBase = "https://abc.vault.azure.net/";
private static String ClientId = "*******************";
private static String clientKey = "*****************";
public static void main(String[] args) {
KeyVaultClient keyVaultClient = GetKeyVaultClient();
SecretBundle getSecret=keyVaultClient.getSecret(vaultBase, "mysecretkey");
SecretBundle getSecret1=keyVaultClient.getSecret(vaultBase, "DB-PASSWORD-POC");
SecretBundle getSecret2=keyVaultClient.getSecret(vaultBase, "certificate-value");
// SecretBundle getSecret2=keyVaultClient.getSecret(vaultBase, "DB-PASSWORD-DEV");
CertificateBundle getCertificate=keyVaultClient.getCertificate(vaultBase, "abcprod");
CertificateBundle bundle = keyVaultClient.getCertificate("https://abc.vault.azure.net/certificates/abcprod/********386c9403bab8337ce21d27495");
System.out.println(getSecret.value());
System.out.println(getSecret1.value());
System.out.println(getSecret2.value());
// System.out.println(getCertificate.contentType());
// System.out.println(getCertificate.id());
// System.out.println(getCertificate.kid());
// System.out.println(getCertificate.toString());
// System.out.println(getCertificate.attributes().toString());
// System.out.println(getCertificate.keyIdentifier().name());
// System.out.println(getCertificate.sid());
// System.out.println(getCertificate.certificateIdentifier().baseIdentifier());
// System.out.println(bundle.cer());
// System.out.println(bundle);
}
private static KeyVaultClient GetKeyVaultClient() {
return new KeyVaultClient(new KeyVaultCredentials() {
#Override
public String doAuthenticate(String authorization, String resource, String scope) {
String token = null;
try {
AuthenticationResult authResult = getAccessToken(authorization, resource);
token = authResult.getAccessToken();
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
});
}
public static AuthenticationResult getAccessToken(String authorization, String resource) throws InterruptedException, ExecutionException, MalformedURLException {
AuthenticationResult result = null;
//Starts a service to fetch access token.
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
AuthenticationContext context = new AuthenticationContext(authorization, false, service);
Future<AuthenticationResult> future = null;
//Acquires token based on client ID and client secret.
if (ClientId != null && clientKey != null) {
ClientCredential credentials = new ClientCredential(ClientId, clientKey);
future = context.acquireToken(resource, credentials, null);
}
result = future.get();
} finally {
service.shutdown();
}
if (result == null) {
throw new RuntimeException("Authentication results were null.");
}
return result;
}
}
We are securing our jetty server with this code :
public class ABCSubscriber {
private static final int Port = 9090;
private static final String KeyStoreType = "jks";
private static final String KeyStoreFile = "/home/abc/xyz/subscriber.jks";
private static final String KeyStorePassword = "******";
private static final String KeyPassword = "*******";
private static final String ContextPath = "/";
private static final String URLPattern = "/*";
public static void main(String[] args) throws Exception {
Server server = new Server();
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(Port);
http_config.setRequestHeaderSize(8192);
// HTTP connector
ServerConnector http = new ServerConnector(server,
new HttpConnectionFactory(http_config));
http.setPort(9091);
http.setIdleTimeout(30000);
// SSL Context Factory
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreType(KeyStoreType);
sslContextFactory.setKeyStorePath(KeyStoreFile);
sslContextFactory.setKeyStorePassword(KeyStorePassword);
sslContextFactory.setKeyManagerPassword(KeyPassword);
// sslContextFactory.setTrustStorePath(ncm.getKSFile());
// sslContextFactory.setTrustStorePassword("changeit");
sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
// SSL Connector
ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
sslConnector.setPort(Port);
server.addConnector(sslConnector);
/**Disable and enable protocols*/
String[] includeProtocols = {"TLSv1.1","TLSv1.2"};
sslContextFactory.addExcludeProtocols("TLSv1.0");
sslContextFactory.setIncludeProtocols(includeProtocols);
/**End Disable and enable protocols*/
// HTTPS Configuration
ServerConnector https = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
https.setPort(Port);
https.setIdleTimeout(30000);
//server.setConnectors(new Connector[] { http, https });
server.setConnectors(new Connector[] { https });
ServletContextHandler ctxt = new ServletContextHandler(0);
ctxt.setContextPath(ContextPath);
server.setHandler(ctxt);
ctxt.addServlet(new ServletHolder(new ABCServlet()), "/*");
try {
server.start();
} catch ( Exception e ) {
e.getLocalizedMessage();
};
server.join();
}
}
So , Is there any way to get the certificate file from Azure keyvault? If not then how can we use certificate to secure the server ?
Can anyone please help me on this ?
Thanks in Advance !!!
You need to download the private key of the certificate as a secret. Getting the secret using the more obvious GetCertificate will only return the public key part of the certificate.
I know this is C# in the code example below, but that is how I get the certificate out of Key Vault, I hope you can get an idea on how to do the same in Java:
/// <summary>
/// Helper method to get a certificate
///
/// Source https://github.com/heaths/azsdk-sample-getcert/blob/master/Program.cs
/// </summary>
/// <param name="certificateClient"></param>
/// <param name="secretClient"></param>
/// <param name="certificateName"></param>
/// <returns></returns>
private static X509Certificate2 GetCertificateAsync(CertificateClient certificateClient,
SecretClient secretClient,
string certificateName)
{
KeyVaultCertificateWithPolicy certificate = certificateClient.GetCertificate(certificateName);
// Return a certificate with only the public key if the private key is not exportable.
if (certificate.Policy?.Exportable != true)
{
return new X509Certificate2(certificate.Cer);
}
// Parse the secret ID and version to retrieve the private key.
string[] segments = certificate.SecretId.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
if (segments.Length != 3)
{
throw new InvalidOperationException($"Number of segments is incorrect: {segments.Length}, URI: {certificate.SecretId}");
}
string secretName = segments[1];
string secretVersion = segments[2];
KeyVaultSecret secret = secretClient.GetSecret(secretName, secretVersion);
// For PEM, you'll need to extract the base64-encoded message body.
// .NET 5.0 preview introduces the System.Security.Cryptography.PemEncoding class to make this easier.
if ("application/x-pkcs12".Equals(secret.Properties.ContentType, StringComparison.InvariantCultureIgnoreCase))
{
byte[] pfx = Convert.FromBase64String(secret.Value);
return new X509Certificate2(pfx);
}
throw new NotSupportedException($"Only PKCS#12 is supported. Found Content-Type: {secret.Properties.ContentType}");
}
}
}
Here is the Java code equivalent to answer posted by #Tore Nestenius
public byte[] getPkcsFromAzureKeyVault(String certificateName) throws InvalidDataException {
String keyVaultName = System.getenv("KEY_VAULT_NAME");
String keyVaultUri = "https://" + keyVaultName + ".vault.azure.net";
CertificateClient certificateClient = new CertificateClientBuilder().vaultUrl(keyVaultUri)
.credential(new DefaultAzureCredentialBuilder().build()).buildClient();
KeyVaultCertificateWithPolicy certPol = certificateClient.getCertificate(certificateName);
SecretClient secretClient = new SecretClientBuilder().vaultUrl(keyVaultUri)
.credential(new DefaultAzureCredentialBuilder().build()).buildClient();
KeyVaultSecret secret = secretClient.getSecret(certPol.getProperties().getName(),
certPol.getProperties().getVersion());
if ("application/x-pkcs12".equalsIgnoreCase(secret.getProperties().getContentType())) {
return Base64.getDecoder().decode(secret.getValue());
}
throw new InvalidDataException();
}
I did not find any way to set the access tier of a blob when I upload it, I know I can set a blob's access tier after I uploaded it, but I just want to know if I can upload the blob and set it's access tier in only one step. And if there is any golang API to do that?
I googled it but I got nothing helpful till now.
Here is what I did now, I mean upload it and then set it's access tier.
// Here's how to upload a blob.
blobURL := containerURL.NewBlockBlobURL(fileName)
ctx := context.Background()
_, err = azblob.UploadBufferToBlockBlob(ctx, data, blobURL, azblob.UploadToBlockBlobOptions{})
handleErrors(err)
//set tier
_, err = blobURL.SetTier(ctx, azblob.AccessTierCool, azblob.LeaseAccessConditions{})
handleErrors(err)
But I want to upload a blob and set it's tier in one step, not two steps as I do now.
The short answer is No. According to the offical REST API reference, the blob operation you want is that to do via two REST APIs Put Blob and Set Blob Tier. Actually, all SDK APIs for different languages are implemented by wrapping the related REST APIs.
Except for Page Blob, you can set the header x-ms-access-tier in your operation request to do your want, as below.
For Block Blob, the operations in two steps are necessary, and can not be merged.
It is now possible using the new x-ms-access-tier header:
x-ms-access-tier
REST API with auth
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace WhateverYourNameSpaceIs
{
class Program
{
private const string StorageKey = #"PutYourStorageKeyHere";
private const string StorageAccount = "PutYourStorageAccountHere";
private const string ContainerName = "PutYourContainerNameHere";
private const string Method = "PUT";
private const string ContentType = MediaTypeNames.Image.Jpeg;
private static readonly string BlobStorageTier = StorageTier.Cool;
private static readonly List<Tuple<string, string>> HttpContentHeaders = new List<Tuple<string, string>>()
{
new Tuple<string, string>("x-ms-access-tier", BlobStorageTier),
new Tuple<string, string>("x-ms-blob-type", "BlockBlob"),
new Tuple<string, string>("x-ms-date", DateTime.UtcNow.ToString("R")),
new Tuple<string, string>("x-ms-version", "2018-11-09"),
new Tuple<string, string>("Content-Type", ContentType),
};
static async Task Main()
{
await UploadBlobToAzure("DestinationFileNameWithoutPath", "LocalFileNameWithPath");
}
static async Task<int> UploadBlobToAzure(string blobName, string fileName)
{
int returnValue = (int)AzureCopyStatus.Unknown;
try
{
using var client = new HttpClient();
using var content = new ByteArrayContent(File.ReadAllBytes(fileName));
HttpContentHeaders.ForEach(x => content.Headers.Add(x.Item1, x.Item2));
var stringToSign = $"{Method}\n\n\n{content.Headers.ContentLength.Value}\n\n{ContentType}\n\n\n\n\n\n\n";
foreach (var httpContentHeader in HttpContentHeaders.Where(x => x.Item1 != "Content-Type").OrderBy(x => x.Item1))
stringToSign += $"{httpContentHeader.Item1.ToLower()}:{httpContentHeader.Item2}\n";
stringToSign += $"/{StorageAccount}/{ContainerName}/{blobName}";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(StorageKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", $"{StorageAccount}:{signature}");
var httpResponse = await client.PutAsync($"https://{StorageAccount}.blob.core.windows.net/{ContainerName}/{blobName}", content);
returnValue = (int)httpResponse.StatusCode;
}
catch (IOException ioException)
{
Console.WriteLine(ioException.ToString());
returnValue = (int)AzureCopyStatus.FileNotFound;
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
returnValue = (int)AzureCopyStatus.Error;
}
return returnValue;
}
internal enum AzureCopyStatus
{
Unknown = -1,
Error = 0,
FileNotFound = 2
}
internal static class StorageTier
{
internal static string Cool = "Cool";
internal static string Hot = "Hot";
}
}
}
I want to list and change the tags and their values for the Azure Virtual Machines using .NET SDK.
Please let me know the way for this.
Thank You.
Since I don't have a Virtual Machine handy, I am posting code for updating tags for a Resource Group.
First, please ensure that Azure AD application is properly set up. You may find this link useful for that purpose: https://msdn.microsoft.com/en-us/library/azure/ee460782.aspx.
Next, I created a simple console application. What you would need to do is get Microsoft.Azure.ResourceManager 1.0.0-preview and Active Directory Authentication Library 2.22.302111727 Nuget packages in your application.
After that, things are pretty simple. Please see the code below:
using System;
using System.Linq;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Threading;
using Microsoft.Azure.Management.Resources;
using Microsoft.Rest;
namespace AzureARMDemo
{
class Program
{
private static string ClientId = "<your-application-client-id>";//This is the PowerShell Client Id
private static string TenantId = "<tenant-id>";
private static string LoginEndpoint = "https://login.microsoftonline.com/";
private static string ServiceManagementApiEndpoint = "https://management.core.windows.net/";
private static string RedirectUri = "urn:ietf:wg:oauth:2.0:oob";
private static string SubscriptionId = "<your-azure-subscription-id>";
private static string AzureResourceManagerEndpoint = "https://management.windows.net";
private static string ResourceGroupNameToUpdate = "<resource-group-name-to-update>";
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
var credentials = new TokenCredentials(token);
var resourceManagerClient = new ResourceManagementClient(new Uri(AzureResourceManagerEndpoint), credentials)
{
SubscriptionId = SubscriptionId,
};
Console.WriteLine("Listing resource groups. Please wait....");
Console.WriteLine("----------------------------------------");
var resourceGroup = resourceManagerClient.ResourceGroups.List().FirstOrDefault(r => r.Name == ResourceGroupNameToUpdate);
if (resourceGroup != null)
{
var tags = resourceGroup.Tags;
if (!tags.ContainsKey("Key1"))
{
tags.Add("Key1", "Value1");
}
else
{
tags["Key1"] = tags["Key1"] + " Updated";
}
Console.WriteLine("Updating resource group. Please wait....");
Console.WriteLine("----------------------------------------");
resourceManagerClient.ResourceGroups.Patch(ResourceGroupNameToUpdate, resourceGroup);
Console.WriteLine("Resource group updated.");
Console.WriteLine("-----------------------");
}
//var resourceGroups = resourceManagerClient.ResourceGroups.List();
//foreach (resourceGroup in resourceGroups)
//{
// Console.WriteLine("Resource Group Name: " + resourceGroup.Name);
// Console.WriteLine("Resource Group Id: " + resourceGroup.Id);
// Console.WriteLine("Resource Group Location: " + resourceGroup.Location);
// Console.WriteLine("----------------------------------------");
//}
Console.WriteLine("Press any key to terminate the application");
Console.ReadLine();
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext(LoginEndpoint + TenantId);
var thread = new Thread(() =>
{
result = context.AcquireToken(
ServiceManagementApiEndpoint,
ClientId,
new Uri(RedirectUri));
});
thread.SetApartmentState(ApartmentState.STA);
thread.Name = "AquireTokenThread";
thread.Start();
thread.Join();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
}
}
I want to list all the hosted services using Azure service Management REST Api. And the msdn hlep explains a way to list hosted services. I have attached the example code given in msdn.
In the code they have used Version, Thumbprint and SubscriptionId.
In windows azure portal we can see a subcription has a subcription Id. And a certificate has a Thumbprint. There may be many hosted services in one subcription so many certificates as well. So what is the thumbprint the following code has mentioned..?
Should it checked with all the thumbprints of a subcription , to list all the hosted services in a subcription.
Why can't we get all the hosted services just using the subcriptionId (is it not secured?) Or is there a common certificate(so there is a thumbprint) for a subcription?
Please guide me,
Thanks.
namespace Microsoft.WindowsAzure.ServiceManagementRESTAPI.Samples
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.Xml.Linq;
public class Program
{
// Set these constants with your values to run the sample.
private const string Version = "2011-10-01";
private const string Thumbprint = "management-certificate-thumbprint";
private const string SubscriptionId = "subscription-id";
static void Main(string[] args)
{
try
{
// Obtain the certificate with the specified thumbprint
X509Certificate2 certificate = GetStoreCertificate(Thumbprint);
ListHostedServicesExample(SubscriptionId, certificate, Version);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in Main:");
Console.WriteLine(ex.Message);
}
Console.Write("Press any key to continue:");
Console.ReadKey();
}
public static void ListHostedServicesExample(
string subscriptionId,
X509Certificate2 certificate,
string version)
{
string uriFormat = "https://management.core.windows.net/{0}/" +
"services/hostedservices";
Uri uri = new Uri(String.Format(uriFormat, subscriptionId));
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "GET";
request.Headers.Add("x-ms-version", version);
request.ClientCertificates.Add(certificate);
request.ContentType = "application/xml";
XDocument responseBody = null;
HttpStatusCode statusCode;
HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
// GetResponse throws a WebException for 400 and 500 status codes
response = (HttpWebResponse)ex.Response;
}
statusCode = response.StatusCode;
if (response.ContentLength > 0)
{
using (XmlReader reader = XmlReader.Create(response.GetResponseStream()))
{
responseBody = XDocument.Load(reader);
}
}
response.Close();
if (statusCode.Equals(HttpStatusCode.OK))
{
XNamespace wa = "http://schemas.microsoft.com/windowsazure";
XElement hostedServices = responseBody.Element(wa + "HostedServices");
Console.WriteLine(
"Hosted Services for Subscription ID {0}:{1}{2}",
subscriptionId,
Environment.NewLine,
hostedServices.ToString(SaveOptions.OmitDuplicateNamespaces));
}
else
{
Console.WriteLine("Call to List Hosted Services returned an error:");
Console.WriteLine("Status Code: {0} ({1}):{2}{3}",
(int)statusCode, statusCode, Environment.NewLine,
responseBody.ToString(SaveOptions.OmitDuplicateNamespaces));
}
return;
}
/// <summary>
/// Gets the certificate matching the thumbprint from the local store.
/// Throws an ArgumentException if a matching certificate is not found.
/// </summary>
/// <param name="thumbprint">The thumbprint of the certificate to find.</param>
/// <returns>The certificate with the specified thumbprint.</returns>
private static X509Certificate2 GetStoreCertificate(string thumbprint)
{
List<StoreLocation> locations = new List<StoreLocation>
{
StoreLocation.CurrentUser,
StoreLocation.LocalMachine
};
foreach (var location in locations)
{
X509Store store = new X509Store("My", location);
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));
}
}
}
The certificate that you would want to use is the "Management Certificate". Here's the process for doing that:
Create a self-signed certificate on your computer (pfx file format). You may find this link useful: http://consultingblogs.emc.com/gracemollison/archive/2010/02/19/creating-and-using-self-signed-certificates-for-use-with-azure-service-management-api.aspx
Install that certificate in your local certificate store (preferably CurrentUser\My).
Export that certificate from your local certificate store on your computer in .cer file format.
Upload this certificate under management certificates section in the portal. To do so, login into Windows Azure portal (https://manage.windowsazure.com) and then click on "SETTINGS" tab and then click on "UPLOAD" button to choose and upload this file.
A few things to keep in mind:
You can have as many as 10 management certificates per subscription.
If you want your colleagues to use the same certificate, please share the pfx file created in step 1 and have them install the certificate in the certificate store of their local computer. Please don't give them .cer file created in step 3 as it does not have certificate's private data.
Hope this helps.