I want to use the configuration setup for my .NET Core Web API. I installed the Microsoft.Extensions.Configuration package for the DI container.
First of all I have 4 config files
appsettings.json
Whenever all three environments use the same config value, this is the file where to put it
appsettings.Development.json
Basic config values for development purposes only. E.g. database connection points to localhost and token secret is "secret", example:
.
{
"Database": {
"ConnectionString": "Server=localhost;Port=3306;Database=db;Uid=root;Pwd=admin;Pooling=true;"
}
}
appsettings.Staging.json
Almost the same as the development file
appsettings.Production.json
Things are different here. I can't put sensitive information to that file, e.g. token secret. These values should come from the environment variable
So in my code I can access the config values via dependency injection
public class MyClass
{
public MyClass(IConfiguration configuration)
{
string databaseConnectionString = configuration["Database:ConnectionString"];
}
}
but what if the code runs in production mode? The information doesn't exist in the production file so I would have to read from the environment variables.
Would I have to create an environment variable called Database:ConnectionString and .NET Core maps all the system environment variables into the configuration file during startup if they don't exist? Or how would I pass in sensitive data to the configuration?
With the default builder, ASP.NET Core will load the configuration from multiple sources, where later sources have the chance to overwrite earlier ones. The default sources in non-development environments are the following:
General JSON configuration from appsettings.json
Environment-specific JSON configuration from appsettings.<Environment>.json
Environment variables, e.g. ConnectionStrings:DefaultConnection or ConnectionStrings__DefaultConnection (both map to the same configuration path)
Command-line arguments
So you have the ability to overwrite the configuration from the JSON files by default using both environment variables and command line arguments.
When it comes to production use, there are also other means to protect the secrets. For example, you could simply edit the appsettings.Production.json during deployment, so that the values will never leave the machine itself.
There are several solutions for this. But obviously you want to keep things such as connection strings away from version controlled files.
If running locally i would sugest using the user secrets functionality in visual studio.
However you can also set environment variables from the cli. This is an example from the documentation about configuration:
set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run
Of course when running in azure the key vault is a good place to put these kinds of secrets and also has great integration into .Net.
Related
I have some tiered ABP.IO application template project deployment questions - but they may be ASP.NET Core deployment questions.
Background
I'm a bit confused as to whether I need to create appsettings.Production.json files to mirror the appsettings.json files in my class library projects (MyProduct.Application, MyProduct.Application.Contracts, etc.) AND my four ASP.NET projects (MyProduct.HttpApi.Host, MyProduct.IdentityServer, MyProduct.Web, and MyProduct.Web.Public) OR whether I just need to create them for ONLY the four ASP.NET projects and make sure that the settings that are in the class library projects are represented in the ones for the ASP.NET projects.
Questions
Should I create appsettings.Production.json files in my class
library/DLL projects?
If yes to 1, will the launchSettings.json file be the right place to
ensure that the libraries are built with the production
configuration?
If yes to 2, are there any considerations when deploying to
production? I know I need to use an environment variable on the
server.
If no to 1 or 2, how do I build my libraries to use the production
configuration?
Is it possible to replace the client secrets wherever they may
appear? It would seem like it would be necessary but there's no help
on this in the documentation. Are there any considerations toward
doing this? Is a simple search and replace of all the default
secrets sufficient or are there code changes necessary?
Is it possible to replace all references to localhost with the FQDN
of the respective site (Host/API, IdentityServer, Web, Web.Public)?
The application template would require this, correct? I am doing an
IIS deployment currently - not a Docker or Kubernetes deployment.
What else am I missing?
Thanks for taking the time to comment. If you have a resource to share with me, please do. I cannot find a deployment guide or checklist on the ABP Framework site, ABP Commercial site, Community Forum, or Discord channel.
UPDATE
I have been through these two resources and I am a lot more educated about configuration in ASP.NET Core but I still cannot find the answer to my question about configuring class libraries in production. 1 - https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0 2 - https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-6.0
FINAL UPDATE
Eventually I just had to figure things out but Omer's answers make a lot of sense in hindsight.
My solution was to add the appsettings.Production.json files to each of the deployable projects as suggested below. You can read Omer's answer for details. I pretty much did everything that Omer suggested but I had not thought about the one shot seeding of the Identity Server database tables. That was truly helpful. My final hurdle was figuring out a way to perform DB Migrations on my local DB instance and my remote servers with just a click.
Through various posts, I eventually figured out that I could use the Launch Profile editor buried under the Debug section of the DbMigrator project properties, to create myself two Launch Profiles. I have one for local development and one for production - although through this mechanism, I don't see why you couldn't create one for each part of your staging pipeline.
It should be noted that I deleted the default profile which was named using the project name/namespace.
Here is the Launch Profile editor screen for the Development profile:
And here is the Launch Profile editor screen for the Production profile:
Of primary importance is the ASPNETCORE_ENVIRONMENT=Development environment variable in development and the ASPNETCORE_ENVIRONMENT=Production environment variable in production.
Exiting the editor produces the Properties folder and the contained
launchSettings.json file.
You could create this folder and file yourself without going through the editor. Here is the text of that file:
{
"profiles": {
"EnvironmentConfiguration.Cli (Development)": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"EnvironmentConfiguration.Cli (Production)": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}
}
Now when I want to run a schema migration, I can simply select the DbMigrator project as the startup project...
...and I will have two launch profiles in my debug menu:
Does anyone know of a better way?
I am using ABP with Blazor Wasm and IdentityServer is not seperated. So I am publishing only .Host and .Blazor projects.
No, you only need them for published projects (.Host, .Web, .Blazor etc)
Should I create appsettings.Production.json files in my class
library/DLL projects?
Libraries are not standalone projects. They are used by other projects (By .Host project or they can be used by another library project) So, they will take these configuration settings from live application (.Host, .Web, .Blazor etc)
If no to 1 or 2, how do I build my libraries to use the production
configuration?
These keys are using by IdentityServer and I think they are seeded to Database on initial migration. If you want to change them, you need to change them from appsettings.json files and change value in database also. By the way, it is encrypted and you need to change value in DB with new encrypted value. (https://support.abp.io/QA/Questions/441/About-changing-client-secrets)
Is it possible to replace the client secrets wherever they may
appear? It would seem like it would be necessary but there's no help on this in the documentation. Are there any considerations toward doing this? Is a simple search and replace of all the default secrets sufficient or are there code changes necessary?
Change "localhost" values to your FQDN in all appsettings.json files. Also there should be some changes in database for IdentityServer. Because in the initial migration, it is written on DB.
[dbo].[IdentityServerClientCorsOrigins].[Origin]
[dbo].[IdentityServerClientPostLogoutRedirectUris].[PostLogoutRedirectUri] [dbo].[IdentityServerClientRedirectUris].[RedirectUri]
Is it possible to replace all references to localhost with the FQDN
of the respective site (Host/API, IdentityServer, Web, Web.Public)?
The application template would require this, correct? I am doing an
IIS deployment currently - not a Docker or Kubernetes deployment.
Do not forget to install SSL. If you are using Cloudflare disable SSL from Cloudflare (If you have also in server) Because it may conflict.
Another important thing is to remove Webdav if you are using IIS. Because Webdav occurs error for put request. (https://stackoverflow.com/a/59235862/2178028)
Also, I dont know why but for the first publish of Blazor projects, it gives 403 error for .dll files in ISS. Then I follow this link (https://www.eugenechiang.com/2021/12/12/failed-to-find-a-valid-digest-in-the-integrity-attribute-for-resource-in-blazor-app/) and problem is solved.
What else am I missing?
actually configuration of development mode different from production mode so to handle this you must use appsetting.production.json
answer for first question is no, because all projects use ui project settings by dependency injection
In my application I hold my connection strings in appsettings.json... I don't have default web.config file.. my purpose is to learn how to manage environments in asp.net core. If I will make web.config transform it will automatically change appsettings.json?
As far as I know, the web.config will not change the appsettings.json. But the appsetting.json contains an environment feature.
Asp.net core has JsonConfigurationProvider enabled by default.
Form official document:
The default JsonConfigurationProvider loads configuration in the following order:
appsettings.json appsettings.Environment.json : For example, the
appsettings.Production.json and appsettings.Development.json files.
The environment version of the file is loaded based on the
IHostingEnvironment.EnvironmentName. For more information, see Use
multiple environments in ASP.NET Core. appsettings.Environment.json
values override keys in appsettings.json. For example, by default:
In development, appsettings.Development.json configuration overwrites
values found in appsettings.json. In production,
appsettings.Production.json configuration overwrites values found in
appsettings.json. For example, when deploying the app to Azure. If a
configuration value must be guaranteed, see GetValue. The preceding
example only reads strings and doesn’t support a default value.
Using the default configuration, the appsettings.json and
appsettings.Environment.json files are enabled with reloadOnChange:
true. Changes made to the appsettings.json and
appsettings.Environment.json file after the app starts are read by the
JSON configuration provider.
This means if you set the environment variable by using web.config or server's environment variable, this provider will load the appsttings.environment.json's value and these value will override the appsettings.json to achieve the transform like old web.config.
Shortly my scenario is to test a remote API if there was any changes in the called APIs, like some parameter removed or something like that.
To get this info I need to have a token.
My problem is, I can't store it in the Database and use windowsCredentials, because in the AzurePipeline the build agents has no access and connection to the Database. And if I pass the token through variables in the pipeline then I won't have the token when I run the code in local.
appSetting is stored in Git so it is not safe.
Any idea on this?
Thanks!
UserSecrets + Environment variables are the key here. Appsettings.json is for configuration that is non-sensitive, but there is a concept called user secrets (see link below) that will allow you to have stored an appsettings.json equivalent just on your machine and not in git. When specifying info in it it should override or add onto anything in your appsettings.json.
If that info is also needed for production, then environment variables should be used. Instead of a file, single configurations can be specified/overridden using environment variables.
This is all accomplished ONLY if the aspnet core web server configuration is setup to accept from all of these places. The default setup from the template should accomplish this but read the links below to make sure that your setup works.
All the configuration and best practices can be found here.
Non sensitive info/Defaults: appsettings.json
Sensitive info for devs/dev specific info: UserSecrets
Sensitive info for prod: Environment variables
I am using database connector component, with vault component to store the database credentials. Now as per the documentation of both components i have created different properties file for each environment to store the encrypted credentials for diff env.
Following is the structure of my mule project
Now the problem with this structure is that i have to build new deployable zip file whenever i have to update the database credentials for any environment.
I need a solution where i can keep all credentials encrypted and centralized and i don't have to create a build every time after updated the credentials, We can afford to restart the server, but building new zip and deploying is really cumbersome.
Second problem we have this approach is a developer needs to know the production db to update it in properties file, this is also a security issue.
Please suggest alternate approach for credentials management for mule projects.
I'm going to recommend you do NOT try to change the secure solution provided to you by MuleSoft. To alleviate the need for packaging and deployment, you would have to extract the properties files outside of the deployment and this would be a huge risk. Regardless of where you store the property files within the deployment if you change the files, you have to package and re-deploy. I see the only solution to your problem as moving the files outside of the deployment and securely storing them. Mule has provided a solution while it may be cumbersome, they are securing these files first with encryption and secondly within the server container. You can move out the property files but you have to provide a custom implementation and you will be assuming great risk to your protected resources.
Set a VM arguement e.g. environment.type=local for local machine on your anypoint studio.
Read this variable in wherever you are reading your properties file in a way that environment type is read dynamically such as below.
" location="classpath:properties/sample-app-${environment.type}.properties" doc:name="Secure Property Placeholder"/>
In order to set the environment type on your production server(or wherever you are using mule runtime), open \conf\wrapper.conf and add the arguement wrapper.java.additional.=-Dserver.type=production. If you already have any property in this file, you may need to set the value of n appropriately. For example 13 or 14.
This way you don't need to generate different deployment artefacts for different environment because correct properties file is picked by using environment specific VM arguement.
I have different projects that are consuming many WCF services. I am using VSTS to automate deployments. Those services target different URLs (endpoint addresses) based on the environment where they are going to be deployed.
I am trying to use web deploy with VSTS release management as suggested in this link:WebDeploy with VSTS, which proposes to create:
Parmeters.xml
Then, add new task "Replace Tokens" with the specified variable for each environment.
However, i don't guess this will work for me, because it generate tokens only for app settings keys (which is not my case).
Is there is a work around or any other suggestion that could help me to do the configuration part?
"Replace Tokens" task can works with any config file in your project and what content to be replaced is also controlled by you.
For example, if you want to replace a URL in "myconfig.config" file. You can set the URL in the config file to "#{targeturl}#", and add a "Replace Tokens" task in your definition with the following settings: (You can change the token prefix and suffix, but remember to update it accordingly in the config file since the task find the strings to replace base on it)
And then create a variable "targeturl" in the definition with the actual URL value:
Now, when you start the build/release, the string "#{targeturl}#" in "myconfig.config" file will be replaced with "www.test.com".