Two connection strings for local and hosting server - c#

I would like to ask if there is a way to tell ASP.NET Core 2 to choose different connection strings.
It is quite annoying to keep changing the connection string in the appsettings.json file every time I publish my website to the hosting server..
I am using this code to get connection string.
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(Configuration["Data:WebDataBase:ConnectionString"]));
Maybe there is an easy way but I am thinking of using an if statement in my Startup.cs:
if (local) {
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(Configuration["Data:WebDataBase1:ConnectionString"]));
}
else {
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(Configuration["Data:WebDataBase2:ConnectionString"]));
}
But how can I set this local variable whether the server is my local computer or a live hosting server?
"Data": {
"WebDataBase1": {
"ConnectionString": "Data Source=DatasoruceName;Initial Catalog=DBname;Trusted_Connection=True;Integrated Security=True;"
},
"WebDataBase2": {
"ConnectionString": "Data Source=DatasoruceName;Initial Catalog=DatabaseName;Trusted_Connection=True;Integrated Security=True;"
}
}

Environment specific configuration is not supposed to be specified within code. ASP.NET Core has a mechanism for that which allows you to swap out the configuration dependending on what environment you run on.
While developing your application, you usually run in the Development environment. When you are deploying your application for production, the Production environment is used by default. But if you have other environments, you can totally make up new names for those too and have specific configurations for them. That all is explained in the Environments chapter of the documentation
What environments allow you to do is create multiple appsettings.json files. The ASP.NET Core by default comes with two files: appsettings.json and appsettings.Development.json.
The former is supposed to contain environment unspecific configuration; things that apply to all environments. The latter file contains development-specific configuration and for example adjusts the logging level so that you get more information during development. You can also use these files to specify a default connection string within appsettings.json and overwrite that for development within appsettings.Development.json.
Furthermore, the configuration file follows a very simple pattern: appsettings.<Environment>.json. So if you run in the Production environment, a file named appsettings.Production.json will be loaded if it exists. This mechanism allows you to configure all your environments differently without having to resort to detections within your code.
In addition, there is also the concept of user secrets during development. These are for development-specific configurations that do only apply to yourself but not for example to other members of your team. This is basically a per-machine configuration that allows you to overwrite both the appsettings.json and the appsettings.Development.json. This is described in the user secrets chapter.
Best practice is to avoid connection strings altogether within configuration files though, since you want to avoid that people that happen to have access to your configuration files (for example through your source code) can know the passwords to your database. In that case you can use other mechanisms, for example environment variables that are local to the process.
In your case, where you are just using integrated security, and as such rely on the credentials of the current user, this is not that much of a problem. The only thing you are leaking is the database name. – So you can definitely start out with putting the connection strings into the appsettings files.
So for example, this is how you would configure your database context within your Startup’s ConfigureServices:
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("WebDataBase"));
Your appsettings.Development.json would look like this:
{
"ConnectionStrings": {
"WebDataBase": "Data Source=DatasourceName;Initial Catalog=DBname;Trusted_Connection=True;Integrated Security=True;"
}
}
And your appsettings.Production.json would look like this:
{
"ConnectionStrings": {
"WebDataBase": "Data Source=DatasourceName;Initial Catalog=DatabaseName;Trusted_Connection=True;Integrated Security=True;"
}
}

Related

.NET Core 6 : to protect potentially sensitive information in your connection string

How do I move sensitive information below into the 'The Secret Manager Tool'?
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer("Server=Test; column encryption setting=enabled;Database=Test;user id=User1;password='Password1';Trust Server Certificate=true");
I know I can right click on the solution name and select "Manage User Secrets", which then generates the secret Json file, but what I am pasting into this file?
And when I move this application over to the production server, do I copy & paste over the secret.json as well?
Thanks in advance.
You need to take a small step back and consider tools ASP.NET Core/.NET provides to work with configuration.
From DbContext Lifetime, Configuration, and Initialization doc you can see that one of the common pattern is to use dependency injection and setup the the connection string on application startup. This will require adding constructor to the context (and modifying/removing OnConfiguring overload - docs):
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
And:
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer("ConnectionStringHere")); // or AddDbContextFactory
Next step is to read the connection string from the settings:
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer(builder.Configuration.GetConnectionString("ConnStringName"))); // or AddDbContextFactory
Which will require connection string to be read from the configuration, for example from appsettting.json:
{
"ConnectionStrings": {
"ConnStringName": "ACTUAL_CONNECTION_STRING"
},
}
Also you can move connection string to any of the supported configuration providers, for example - Secret Manager (note, it is for development environment only, for other environments is better to use either environment variables or secured key storages).
In the production server you need to create a configuration key with the same name with the production connection string.
Set the ASPNETCORE_ENVIRONMENT variable to "Production"
When environment "ASPNETCORE_ENVIRONMENT" is in "Production" the secrets.json source is ignored. You can check this in Default application configuration sources
According to ASP.NET Core documentation
WebApplication.CreateBuilder initializes a new instance of the WebApplicationBuilder class with preconfigured defaults. The initialized WebApplicationBuilder (builder) provides default configuration for the app in the following order, from highest to lowest priority:
Command-line arguments using the Command-line configuration provider.
Non-prefixed environment variables using the Non-prefixed environment variables configuration provider.
User secrets when the app runs in the Development environment.
appsettings.{Environment}.json using the JSON configuration provider. For example, appsettings.Production.json and appsettings.Development.json.
appsettings.json using the JSON configuration provider.
A fallback to the host configuration described in the next section.
When running production apps in AWS, GCP, or Azure, we keep all secrets in the cloud provider's respective secret manager (e.g. AWS Secrets Manager) and use scripting when the runtime environment is created to inject those secrets into environment variables.
Note, by Secrets Manager, I don't mean the .NET Secret Manager, which merely stores secrets in a file on the development machine.
.NET can read configuration from the environment, including connection strings.
With this approach, only trusted DevOps personnel ever have the ability to view a connection string. It is never in a file, and certainly never in source control.
Best that you can do for the connection string in the production server is to configure windows authentication.
There must be a network user configured. This user should be given permissions in the SQL Server.
When you configure your Web server pool, run this pool under identity created in #1
At this point your connection string will look like this Server=MyServerName;Database=MyDbName;Trusted_Connection=SSPI;Encrypt=false;TrustServerCertificate=true. As you see - no password or user
With this setup, unless attacker knows password to the account under which your pool runs, this is plenty secure.
If you insist in using Sql Authentication, you need to store your credentials in the secure secrets manager (even if homegrown) and then acquire them and build connection string at runtime.

C# .NET Core SQL Server Connectivity

Within my startup, I load a set of database connection strings from the appsettings.json file. The connection strings look as follows
"CoreConnectionString": "Server=localhost; Database=DBCore; Uid=someUserName; Pwd=somePW",
"IdentityConnectionString": "Server=localhost; Database=DBAuth; Uid=someUserName; Pwd=somePW"
What is the best way to encrypt this information so I don't show the actual user name and password?
Here's two suggestions to not expose your DB Password and Conn Strings:
Use a secret file in your computer, apart from your Solution. In Visual Studio 2022 you can do it by clicking your project. Just throw your connections strings there like in AppSettings.json.
Pro: Easy to use
Con: You can't deply it with your project or store it at github
Use Azure Key Valut to store all connection strings. Read this doc from Microsoft if it's your way to go.
Pro: No need for local files. Cloud stored Keys.
Con: Need a bot more configuration in your project and an Azure account.

adding placeholder variables to the appSettings.json file

So when generating a new .NET Core web project there is an appSettings.json and appSettings.Development.json for configuration parts. By default, those are not ignored by the .gitignore file so I think they should stay in the repository.
I'm using a database and want to store my connection string to those files. Obviously the parameters contain sensitive information and shouldn't be in the repository. If the environment is the development I can add the local connection string to the appSettings.Development.json (but then every developer would have to use the same settings until I add the dev file to the .gitignore)
"Database": {
"Server": "localhost",
"Port": 5432,
"UserId": "admin",
"Password": "admin",
"Name": "myDb"
}
How can I set-up the appSettings.json for production or other purposes? Is there a way for something like
"Database": {
"Server": "$DB_SERVER",
"Port": "$DB_PORT",
"UserId": "$DB_USER_ID",
"Password": "$DB_PASSWORD",
"Name": "$DB_NAME"
}
and those placeholders would be replaced with the values from the environment variables?
If you include any sort of sensitive information (like production connection strings) in source control they are usually considered compromised.
You have two options:
First option wopuld be to go for appsettings file override values. It is supported by all the established CI/CD tools. That step usually happen in the release pipeline right before you deploy.In this scenario you store your values encrypted in the CD tool.
Second option is to use Environment variables. In this case for development purposes you can just pass this variables in the launchSettings.json file. And you set the values of your environment variables in the server running your application.
If you want to use Environment variables you do not need place holders in appsettings file. You can read them directly
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT ")
Use secret
They save in a local file the configuration, so they aren't on repository.
When you go in production, you save this information in environment variable.
In visual studio on Project, select Manage user secret and add your connection
{
"ConnectionStrings": {
"MyConnection": "the connection"
}
in startup use IConfiguration
configuration.GetConnectionString("MyConnection")
and at production, in EnvironmentVariable of server, you save a new EnvironmentVariable
ConnectionStrings:MyConnection
So only administrator know the connection.
If you use Azure, you could use Azure key vault.

Where should I store the connection string for the production environment of my ASP.NET Core app?

Where should the production and staging connection strings be stored in an ASP.NET Core application, when deploying into IIS 7 (not Azure) ?
I am looking for the recommended way of doing it / best-practice, especially security-wise.
In ASP.NET 5 it's possible to specify multiple configuration sources. Thanks to this welcoming change to previous model you can store your development connection string in simple json file, and your staging and production connection string in environment variables directly on the respective servers.
If you configure your app like this :
var config = new Configuration()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
and there is connection string in both config.json and environment variable then environment source will win.
So, store your development connection string in config.json(and freely check in in source control) and production one in environment variable. More info here and here.

Maintaining both on-line (Azure) and off-line version of a website

Note: Not sure if the question is asked the right way. This is how I perceive the issue but it's fully possible that the problem is addressable form a totally different angle, which I'm unaware of due to the ignorance.
Question
Is there a built-in database available for an out-of-the-box, MVC solution? If so, how do I find out its connection string?
Current string is for Azure and looks like this (frankly, it scares living excrement out me because I don't understand most of it).
<add name="DefaultConnection" connectionString="
Data Source=(LocalDb)\v11.0;
Initial Catalog=aspnet-Plong-20141107210818;
Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|\aspnet-Plong-20141107210818.mdf"
providerName="System.Data.SqlClient" />
Background info
I'm developing a site and publish it to the Azure. It has some connections to the database and I'm using Code First and Entity Framework. Everything works great (maybe except the fact that it takes a few seconds to upload and initialize the page prior showing, which is annoying if I've only made changes to the markup of Razor).
In fact, all's been set up pretty much automagically, and I didn't have to configure much at all. Now, it's biting my in the sitting device because of the following.
I need to be able to run my site on the local host (using F5, if you will) because I'll be going off-line (or at the very least under a very lousy connection). I can do that right now, except for the page that contacts the database reference, where I'm getting the error below.
I get what the problem is - no local DB set up using code first. I wonder if there's a lazy man's solution to it (using some built in DB and code-first-able). If so, where do I set it up? I prefer to keep the reference to default connection string as intact as possible but if I need to edit it (or, most likely, add a new one and reference it), how do I learn the correct connection string?! (Yes, I know, this is the price I pay for taking an easy way out letting Azure configure everything for me. Head down in shame.)
{"Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations."}
As far as I know that's not a connection string to SQL Azure, but for a local (development) database. It will create a .mdf file in your App_Data folder. You can find connection strings to SQL Azure somewhere in the Azure dashboard. I switch between dev en production using for example:
public MyContext : DbContext
{
public MyContext()
#if DEBUG
: base("development")
#else
: base("production")
#endif
{
}
}
However, you could also use XML transformation of the web.config, web.debug.config and web.release.config. Note that web.debug.config is not really used when you run your application locally, so put your development connection strings in web.config and publish your application in release mode so the XML transformation of web.release.config takes place.
Edit: Get the SQL Azure connection string
Got to the management portal and click on SQL Databases. Click on the database and go to Dashboard. On the right side you see "Show connection strings". It looks something like this:
Server=tcp:xxx.database.windows.net,1433;Database={your_db_name};User ID={your_user_id};Password={your_password_here};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;

Categories