How to update Azure App Configuration Settings using Code (.Net Core) - asp.net-core-2.0

I have an Azure app registered on Azure portal which is created in .NET Core 2.0 This app reads some config value from the Application settings section from the portal as shown in below image.
Now at some stage I want to update those config value from code. I have searched for many article but not found how to update Azure Application settings from code. Can any one have an idea or suggestion that How can I update Azure Application settings using .NET Core 2.0 C#?

This can be accomplished using Azure.ApplicationModel.Configuration nuget package.
In particular, the SetConfigurationSetting method seems to do what you are after.
string connectionString = "<connection_string>";
var client = new ConfigurationClient(connectionString);
ConfigurationSetting setting = client.SetConfigurationSetting("some_key","new_value");
Note: This package is in preview

You could use c# to call the REST API Web Apps - Update Application Settings manually.
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/config/appsettings?api-version=2019-08-01
For more details about how to call Azure REST API in c#, you could refer to this link.

If you want to use c# to do it, you could try with Microsoft.Azure.Management.Fluent package, the below is the sample code, you could have a try.
string tenantId = "*******";
string clientSecret = "********";
string clientId = "********";
string subscriptionId = "*******";
var azureCredentials = new AzureCredentials(new
ServicePrincipalLoginInformation
{
ClientId = clientId,
ClientSecret=clientSecret
}, tenantId, AzureEnvironment.AzureGlobalCloud) ;
var _azure = Azure
.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.Authenticate(azureCredentials)
.WithSubscription(subscriptionId);
var appResourceId = "/subscriptions/**********/resourcegroups/*******/providers/Microsoft.Web/sites/***"; //Get From WebApp -> Properties -> Resource ID
var webapp = _azure.WebApps.GetById(appResourceId);
webapp.Update()
.WithAppSetting("test", "testvalue")
.Apply();

The library has been changed to Azure.Data.AppConfiguration.
Azure.ApplicationModel.Configuration is depracated

This is an addendum to George Chen's answer.
To avoid the "Operation returned an invalid status code 'Forbidden' exception after calling _azure.WebApps.GetById(appResourceId), you need to ensure the service principal associated with the Azure Credential has contributor access to the subscription the web app is in. For more details refer to https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal.

Related

Api-version must be specified when using azure keyvault SecretClient .net sdk

I am trying to set a secret in azure keyvault using managed identity. There are two problems which I am facing right now. Hope someone can help me with it.
Code:
var client = new SecretClient(new Uri("keyvaulturl"),
new DefaultAzureCredential(new DefaultAzureCredentialOptions()
{ ExcludeManagedIdentityCredential = true }));
await client.SetSecretAsync(new KeyVaultSecret(keyName,
serializer.SerializeObject(someobject)));
Problem 1:
DefaultAzureCrendetialOption is not working for managed identity but when I am setting ExcludeManagedIdentityCredential to true it is able to fallback to the next authentication provider (must be azure cli). I am not sure why this is happening because couple of days before the same code was working and I was able to set and retrieve keyvault secrets using the same code.(ofcourse without using any DefaultAzureCredentialOptions parameters).
Please note this problem only happens in my local env and managed identity works fine when deployed in azure.
Problem 2:
When setting ExcludeManagedIdentityCredential to true for local development, I started seeing another problem where it is giving me error that api-version is missing. I dont understand why and where do I need to specify the api version when using azure .net sdk.
Error:
Service request failed.
Status: 400 (Bad Request)
Content:
{"error":{"code":"BadParameter","message":"api-version must be specified"}}
Problem 1:
Managed Identity cannot be used to authenticate locally-running applications by design. Try to read the Important tip in the document.
Managed Identity cannot be used to authenticate locally-running
applications. Your application must be deployed to an Azure
service that supports Managed Identity.
Problem 2:
Please change the version of Azure Key Vault secret client library with the latest varsion.
dotnet add package Azure.Security.KeyVault.Secrets
I tried DefaultAzureCredential with environment variables in my local.
string keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
var kvUri = "https://" + keyVaultName + ".vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
KeyVaultSecret secret = new KeyVaultSecret("testdefault", "123456");
KeyVaultSecret result = await client.SetSecretAsync(secret);
Console.WriteLine(result.Name);

Authenticate Azure Management SDK in .NET Core?

I'm running ASP.NET Core application (.Net Core 3.0) and have referenced nuGet package Microsoft.Azure.Management.WebSites. It seems like there are half a dozen ways to connect to Azure and I'm hoping that is the correct one for my environment.
I'm attempting to instantiate a WebSiteManagementClient so that I can modify some AppService settings (scale service plan up/down). To that end, I need an instance of ServiceClientCredentials. I can't seem to find a way to get the proper credentials together.
I've followed several different articles, all of them advocate a different method.
What's the easiest way to get authenticated against the Azure Management SDK?
Ideally, avoiding Azure Active Directory. I've attempted multiple times trying to set up an App Registration with the appropriate permissions, and I can't seem to get it together.
The app connecting and making the change will be an ASP.NET website running in Azure itself, if it makes a difference.
Thanks in advance!
Code so far:
using Microsoft.Azure.Management.WebSites;
var credentials = await GetCredentials(); // <-- ???
WebSiteManagementClient client = new WebSiteManagementClient(credentials);
client.SubscriptionId = "xxx-xxx-xxxx-xxxx";
Try this :
static void Main(string[] args)
{
string tenantId = "<your tenant ID>";
string clientId = "<your azure ad app ID>";
string clientSecret = "<azure ad app secret>";
string subscriptionId = "<your subscription ID>";
WebSiteManagementClient client = new WebSiteManagementClient(GetCredsFromServicePrincipal(tenantId, clientId, clientSecret));
client.SubscriptionId = subscriptionId;
foreach (var ap in client.app.List()) {
Console.WriteLine(ap.Id);
}
}
private static TokenCredentials GetCredsFromServicePrincipal(String tenantId,String clientId, String clientSecret)
{
var authority = #"https://login.microsoftonline.com/" + tenantId;
var authContext = new AuthenticationContext(authority);
var credential = new ClientCredential(clientId, clientSecret);
var authResult = authContext.AcquireTokenAsync("https://management.azure.com", credential).GetAwaiter().GetResult();
return new TokenCredentials(authResult.AccessToken);
}
Result (list all website ids):
As this sample use ServicePrincipal to access your azure website resources, so you should grant associated permissions it in your subscription "Access control (IAM)" balde, such as assigning "website contributor" and "web plan contributor" to it so it has permission to manage your website resources . Hope it helps.
The new Azure.Identity library seems to be the recommended way for authenticating services within Azure. In particular the DefaultAzureCredentials() class works seamlessly in local development scenarios and in deployed code without having to make any code changes.
This is easy to use with the newer management SDKs (the ones with names like Azure.ResourceManager...) because we can just write new DefaultAzureCredentials() and pass that to the management SDK when creating a new client.
Unfortunately, the older management SDKs (the ones with names like Microsoft.Azure.Management...) do not integrate with Azure.Identity "out-of-the-box". They also do not plan to add support for Azure.Identity to these older APIs because they are instead focusing on porting everything to the newer versions.
However, not every resource in Azure has a new version management API yet and so in some cases you're stuck using the old ones. Fortunately, there is a relatively straight forward way to bridge the gap and still use Azure.Identity with those older APIs.
There's a GitHub repo which contains an example of how to achieve this. I think it's by one of the developers on the Microsoft team, but isn't officially supported by Microsoft. There is no NuGet package for it and they recommend just copying the bits you need.
I actually found that the code in that sample repo was overly complex for my needs and in my case that all I needed was this. Note, I've copied this from my F# project without testing it, so I might have made a mistake in the conversion to C#, but hopefully it's close enough that you get the idea.
class AzureIdentityFluentCredentialAdapter : AzureCredentials
{
public AzureIdentityFluentCredentialAdapter(string tenantId)
: base(default(DeviceCredentialInformation), tenantId, AzureEnvironment.AzureGlobalCloud)
{
}
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var creds = DefaultAzureCredential() // Use the new Azure.Identity library to get access tokens
var accessToken = await creds.GetTokenAsync(
new TokenRequestContent(new [] { "https://management.azure.com/.default" }),
cancellationToken);
return await TokenCredentials(accessToken.Token)
.ProcessHttpRequestAsync(request, cancellationToken);
}
}
This example doesn't do any token caching, but for my purposes I wasn't too bothered about this. It's also hardcoded the scope that I request the token for because I knew I was only going to be using this with the Azure management API.

Calling azure resource manager storage API from window desktop app using user credentials

I want to call this API from azure resource manager to get the storage keys:
https://learn.microsoft.com/en-us/rest/api/storagerp/storageaccounts/listkeys
I want to use user authentication for this call and possibly .net sdk.
Is there any .net sdk(Nuget package) I can include in my c# project to call this API? I am seeing many solution which is using .net sdk but they are using AAD app secret, but I cannot use secret in the app since it is a desktop app. I think there should be a way to call these API with user auth and .net sdk.
The Microsoft.Azure.Services.AppAuthentication for .NET library may meet your requirement. It uses the developer's credentials to authenticate during local development. When the solution is later deployed to Azure, the library automatically switches to application credentials.
The Microsoft.Azure.Services.AppAuthentication library supports local development with Microsoft Visual Studio, Azure CLI, or Azure AD Integrated Authentication.
Sample:
using Microsoft.Azure.Management.Storage;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Rest;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com/").Result;
var Credentials = new TokenCredentials(accessToken);
var storageManagementClient = new StorageManagementClient(Credentials);
storageManagementClient.SubscriptionId = "subscription id";
var storageAccountKey = storageManagementClient.StorageAccounts.ListKeysAsync("resource grouop name", "storage account name");
string storage_Account_Key = storageAccountKey.Result.Keys[0].Value;
System.Console.WriteLine(storage_Account_Key);
}
}
}
For more details about the authentication, you could take a look at this link.

Add WebJobs to WebApp with Azure Fluent API

Is it possible to use the Azure Fluent API to add a WebJob to a WebApp? I'm not finding any documentation describing this.
I believe the answer is no, and that you are required to use the Azure Kudu WebJob API
More information about that can be found:
https://github.com/projectkudu/kudu/wiki/WebJobs-API
https://blogs.msdn.microsoft.com/benjaminperkins/2016/02/01/using-the-azure-webjob-api/
As Lachie said, it seems that there is no Fluent API support to add WebJobs, you could use WebJobs KUDU API to achieve it.
I do a demo for that. It works correctly in my site. The following is my detail steps:
Preparation:
1.The WebJob API require Basic Authentication using the publishing credentials, you could go to your webapp in azure portal to click Get publish profile and download it to get username and userpassword.
2.Zip the WebJob to be published file.
Steps:
1.Create a C# console project.
2.Add the following code in the Program.cs file.
string userName = "$name";
string userPassword = "pass";
string webAppName = "webappname";
string webJobName = "webjobname";
var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{userName}:{userPassword}"));
var file = File.ReadAllBytes(#"webjob zip file path");
MemoryStream stream = new MemoryStream(file);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Basic " + base64Auth);
client.DefaultRequestHeaders.Add("ContentType", "application/zip");
var baseUrl = new Uri($"https://{webAppName}.scm.azurewebsites.net/");
var requestURl = baseUrl + "api/continuouswebjobs/"+webJobName;
var httpContent = new StreamContent(stream);
httpContent.Headers.Add("Content-Disposition", "attachement;filename="+ webjob.exe);
var response2 = client.PutAsync(requestURl, httpContent).Result;
}
Note: The filename should be in the Content-Dispostion header. Here I deploy the continuous webjob, if you want to deploy trigger webjob, you could change continuouswebjobs to triggeredwebjobs.
3.Test from the local.
4.Check the published result on azure.

AzureCredentials not found in Azure .Net SDK

I must be missing something silly. I'm trying to authenticate my server backup app to have access to my Azure account so I can do things like programmatically create storage accounts, etc. If I understand right, you have to create a service principal. I think I got that taken care of, now I just need to add the code:
AzureCredentials credentials = AzureCredentials.FromServicePrincipal(client, key, tenant, AzureEnvironment.AZURE);
Azure azure = Azure.authenticate(credentials).withSubscription(subscriptionId);
Problem is references for "AzureCredentials" and "Azure", or "IAzure" all can't be found. I've installed the Azure SDK, added references as follows:
using Microsoft.WindowsAzure;
using Microsoft.Azure;
using Microsoft.WindowsAzure.Management;
using Microsoft.WindowsAzure.ActiveDirectory.Authentication;
...nothing! What am I missing?
EDIT: The suggested package in the answer below was correct, except the "Azure" reference still can't be found. I believe it is in "Microsoft.Azure.Management.Fluent", but when I try to add it, I'm getting this:
Failed to add reference. The package 'Microsoft.Azure.Management.AppService.Fluent' tried to add a framework reference to 'System.Xml.XDocument' which was not found in the GAC. This is possibly a bug in the package. Please contact the package owners for assistance. 0
You should use Microsoft.Azure.Management.ResourceManager.Fluent sdk and refer to document , you could try below code to login with ServicePrincipal :
AzureCredentials credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(...)
OR
var credentials = new AzureCredentials(new ServicePrincipalLoginInformation { ClientId = "xxxxxx", ClientSecret = "xxxxx" }, "tenantid", AzureEnvironment.AzureGlobalCloud);

Resources