ImageProcessor: keeping Azure Storage account credentials secret and set config at runtime? - web-config

I am using the AzureBlobCache config and would like to set the CacheStorageAccount parameter (and other parameters) at runtime because I don't want to commit my storage account credentials into source control in the config file.
I am deploying to Azure App Service and would like to set my CacheStorageAccount in Azure App Service's AppSettings so it could read at runtime instead of reading from the config file.
How can/should I achieve this? Should I modify the web.config in Global.asax?

Managed to find the solution. I set this in the Global.asax Application_Start() event to overwrite the settings in the config files.
var appSettings = ConfigurationManager.AppSettings;
var config = ImageProcessorConfiguration.Instance;
var cachedStorageAccount = appSettings["CachedStorageAccount"];
if (!string.IsNullOrEmpty(cachedStorageAccount))
{
config.ImageCacheSettings["CachedStorageAccount"] = cachedStorageAccount;
}

Related

Where is a file created via Terraform code stored in Terraform Cloud?

I've been using Terraform for some time but I'm new to Terraform Cloud. I have a piece of code that if you run it locally it will create a .tf file under a folder that I tell him but if I run it with Terraform CLI on Terraform cloud this won't happen. I'll show it to you so it will be more clear for everyone.
resource "genesyscloud_tf_export" "export" {
directory = "../Folder/"
resource_types = []
include_state_file = false
export_as_hcl = true
log_permission_errors = true
}
So basically when I launch this code with terraform apply in local, it creates a .tf file with everything I need. Where? It goes up one folder and under the folder "Folder" it will store this file.
But when I execute the same code on Terraform Cloud obviously this won't happen. Does any of you have any workaround with this kind of troubles? How can I manage to store this file for example in a github repo when executing github actions? Thanks beforehand
The Terraform Cloud remote execution environment has an ephemeral filesystem that is discarded after a run is complete. Any files you instruct Terraform to create there during the run will therefore be lost after the run is complete.
If you want to make use of this information after the run is complete then you will need to arrange to either store it somewhere else (using additional resources that will write the data to somewhere like Amazon S3) or export the relevant information as root module output values so you can access it via Terraform Cloud's API or UI.
I'm not familiar with genesyscloud_tf_export, but from its documentation it sounds like it will create either one or two files in the given directory:
genesyscloud.tf or genesyscloud.tf.json, depending on whether you set export_as_hcl. (You did, so I assume it'll generate genesyscloud.tf.
terraform.tfstate if you set include_state_file. (You didn't, so I assume that file isn't important in your case.
Based on that, I think you could use the hashicorp/local provider's local_file data source to read the generated file into memory once the MyPureCloud/genesyscloud provider has created it, like this:
resource "genesyscloud_tf_export" "export" {
directory = "../Folder"
resource_types = []
include_state_file = false
export_as_hcl = true
log_permission_errors = true
}
data "local_file" "export_config" {
filename = "${genesyscloud_tf_export.export.directory}/genesyscloud.tf"
}
You can then refer to data.local_file.export_config.content to obtain the content of the file elsewhere in your module and declare that it should be written into some other location that will persist after your run is complete.
This genesyscloud_tf_export resource type seems unusual in that it modifies data on local disk and so its result presumably can't survive from one run to the next in Terraform Cloud. There might therefore be some problems on the next run if Terraform thinks that genesyscloud_tf_export.export.directory still exists but the files on disk don't, but hopefully the developers of this provider have accounted for that somehow in the provider logic.

How to Get Azure Access Token using DefaultAzureCredential without storing secrets

I am trying to setup my environment to be able to to access Azure resources from outside Azure.
While looking at different options I cam across mainly below options of many others
Option 1:
Creating a Service Principal with the Azure CLI and use client secrets for Token retrieval and accessing Resources
Get Client secrets Run Time
Option 2:
Using DefaultAzureCredential (Azure.Identity) for Token retrieval and accessing Resources
DefaultAzureCredential
I am currently trying out DefaultAzureCredential option to be able to access Azure resources such as ADF, Blob storage etc.
I am able to do this using the Visual Studio credentials (VS 2019). However challenge remains to perform same action via a Pipeline running outside Azure. I do not want to save any secrets in the code. Does this means that I cannot use environment variables for the Purpose?
If indeed this is still possible then need help with the code.
Environment:
. Net Framework 4.8/Core 3.1
Desired Flow:
Use Visual Studio Credentials for local Development and Test.
Use Environment Variables OR other tasks supported by DefaultAzureCredential via DevOps Pipeline task.
Code:
var tokenCredential = new DefaultAzureCredential();
var accessToken = await tokenCredential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { ResourceId + "/.default" }) { }
);
I was able to solve this using DefaultAzureCredential. We followed the below approach to solve this
Added code to read the secrets from appsetting.json
Add secrets to environment variables
Use DefaultAzureCredential* to reach to correct override.
Add replace token task in Build/Release pipelines to replace client secret variables with secrets from pipeline parameters.
Code when executed from Visual studio does not find actual value to secret variables from appsetting.json and then uses VisualStudio Credentials.
Read values
string AZURE_CLIENT_SECRET = ConfigurationHelper.GetByName("AZURE_CLIENT_SECRET");
string AZURE_CLIENT_ID = ConfigurationHelper.GetByName("AZURE_CLIENT_ID");
string AZURE_TENANT_ID = ConfigurationHelper.GetByName("AZURE_TENANT_ID");
// Check whether the environment variable exists.
if (AZURE_CLIENT_SECRET != "{{AZURE_CLIENT_SECRET}}"
&& AZURE_CLIENT_ID != "{{AZURE_CLIENT_ID}}" &&
AZURE_TENANT_ID != "{{AZURE_TENANT_ID}}")
{
Environment.SetEnvironmentVariable("AZURE_CLIENT_SECRET", AZURE_CLIENT_SECRET);
Environment.SetEnvironmentVariable("AZURE_CLIENT_ID", AZURE_CLIENT_ID);
Environment.SetEnvironmentVariable("AZURE_TENANT_ID", AZURE_TENANT_ID);
Console.WriteLine("Setting Environment Variables");
}
Call DefaultAzureCredential
var objDefaultAzureCredentialOptions = new DefaultAzureCredentialOptions
{
ExcludeEnvironmentCredential = false,
ExcludeManagedIdentityCredential = true,
ExcludeSharedTokenCacheCredential = true,
ExcludeVisualStudioCredential = false,
ExcludeVisualStudioCodeCredential = false,
ExcludeAzureCliCredential = true,
ExcludeInteractiveBrowserCredential = true
};
var tokenCredential = new DefaultAzureCredential(objDefaultAzureCredentialOptions);
ValueTask<AccessToken> accessToken = tokenCredential.GetTokenAsync(
new TokenRequestContext(scopes: new[] { "https://management.azure.com/.default" }));
If environment variables are present in the active session then the code uses environment variables

How Environment variable names reflect the structure of an appsettings.json

I am using ASP.NET Core 5.0 and I have a Web API app deployed to internal cloud where few settings like DB are controlled via environment variables on the host cloud. In my Startup.cs I have the below code
string projectDbConnection = Configuration.GetSection("ProjectDatabaseSettings").GetValue<string>("PROJECT_DB_CONNECTION");
string projectDbName = Configuration.GetSection("ProjectDatabaseSettings").GetValue<string>("PROJECT_DB_NAME");
Here as I understand, when running locally in IIS Express it looks for appsettings.<Environment>.json and they take precedence over appsettings.json values.
But this app is always connecting to the wrong DB when I deployed to Cloud where I mentioned the PROJECT_DB_CONNECTION & PROJECT_DB_NAME as Environment variables for the app.
To make the app read from the Environment variables I had to change the above Code in Startup.cs as
string projectDbConnection = Configuration.GetValue<string>("PROJECT_DB_CONNECTION");
string projectDbName = Configuration.GetValue<string>("PROJECT_DB_NAME");
I am unable to understand the difference between the GetSection.GetValue and just GetValue and why I should use Configuration.GetValue() to direct app to read from Env variables.
what am I missing and when should we use what?
Naming of environment variables
There is kind of a naming convention in the environment variables for nested appsettings to env vars, see naming of environment variables.
Each element in the hierarchy is separated by a double underscore.
In your case it would work if you name the env variable: ProjectDatabaseSettings__PROJECT_DB_CONNECTION.
Config Order
Regarding to Microsoft Documentation there is a order in which the config sources are checked.
ChainedConfigurationProvider : Adds an existing IConfiguration as a source. In the default configuration case, adds the host configuration and setting it as the first source for the app configuration.
appsettings.json using the JSON configuration provider.
appsettings.Environment.json using the JSON configuration provider. For example, appsettings.Production.json and appsettings.Development.json.
App secrets when the app runs in the Development environment.
Environment variables using the Environment Variables configuration provider.
Command-line arguments using the Command-line configuration provider.
The usecase
This is useful when you are developing local using appsettings.json, but run in a cluster or cloud in production where it is more convenient to use environment variables (f.e.: in kubernetes environment variables are set via config maps).

How do I set environment properties in AWS codestar?

I created a spring project in AWS codestar.
I would like to pass environment properties to my application (e.g. DATA_SOURCE_URL). I can do it in elastic beanstalk in "Configuration" -> "Software" "modify" and adding the properties. But whenever a new deployment is triggered this configuration gets reseted.
I was wondering what is the way of setting environment properties when using AWS codestar.
As it may help other people that search a solution
I finally get it to work by using the Saved Configuration function in Beanstalk, and calling it via the cloud formation template.yml : EBConfigurationTemplate (from the autogenerated template.yml by codestar)
EBConfigurationTemplate:
[...]
SourceConfiguration:
ApplicationName: !Ref 'EBApplication'
TemplateName: "Saved Configuration Name"
After that my django application was able to read the os.environ['ENV_VAR_NAME']
as well as django.config that was able to connect to an RDS (Non-managed by beanstalk) to do the migration as a container_command

Need ServiceConfiguration.cscfg to populate web.config sessionstate and connection strings

I need to propagate connection string changes for entity framework, asp.net membership (which are both in the connectionstrings section of web.config) and session state (which is in sessonstate's sqlconnectionstring) in web.config when I adjust these settings in windows azure's service configuration.
During development we test our app as a standard asp.net webforms app, but once it is deployed it is running in azure. So we need to allow for the site running in both non-azure and an azure context. That's why we're just relying upon the values in web.config for now.Since these connection strings are not called directly in my code writing a utility class which grabs from azure service config if that is available or otherwise grabs from web.config is not a possibility for these values.
I realize that editing web.config would cause a disruption in service - and i only plan to do this during off hours.
I believe that the best approach is to wrap your configuration information in a service. Then, in the service, use RoleEnvironment to determine which settings to use. For example
public static class Config
{
public static string ConnStr
{
get
{
if (RoleEnvironment.IsAvailable)
return RoleEnvironment.GetConfigurationSettingValue("ConnStr");
return ConfigurationManager.AppSettings["ConnStr"];
}
}
}
If that doesn't work, and you need to change the actual web.config (for instance, using named connection strings), then you'll need to modify the config at runtime. In your role start, do something like the following:
var config = WebConfigurationManager.OpenWebConfiguration(null);
var connStrs = WebConfigurationManager.OpenWebConfiguration(null).GetSection("connectionStrings") as ConnectionStringsSection;
connStrs.ConnectionStrings["ConnStr"].ConnectionString = RoleEnvironment.GetConfigurationSettingValue("ConnStr");
config.Save();
To handle when the configuration changes after the role is running, just call the same code as above from the RoleEnvironment.Changing event.
Good luck,
Erick