我试图找出哪个最佳存储ASP.NET核心应用程序的应用程序生产机密.有两个类似的问题 我应该在哪里存储我的asp.net-5应用程序的生产环境的连接字符串? 以及 如何将ASP.NET Core UserSecrets部署到生产中 ,它们都建议使用环境变量.
我的问题是我想运行具有不同数据库和不同数据库凭据的Web应用程序的多个实例.所以应该有一些包含秘密的每个实例配置.
如何以安全的方式实现这一目标?
请注意,应用程序应该能够自我托管并在IIS下托管!(稍后我们还计划在Linux上运行它,如果这对问题有任何重要性)
更新
这个问题不是试图在生产中使用ASP.NET用户机密!UserSecrets被排除用于生产.
正如他们所说,用户机密仅用于开发(以避免意外地将凭证提交到SCM中)而不是用于生产.您应该使用每个数据库,即一个连接字符串ConnectionStrings:CmsDatabaseProduction,ConnectionStrings:CmsDatabaseDevelopment等等.
或者使用docker容器(当您不使用Azure App Service时),然后您可以基于每个容器设置它.
或者,您也可以使用基于环境的appsetting文件.appsettings.production.json,但它们不得包含在源代码管理(Git,CSV,TFS)中!
在启动时只需:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
Run Code Online (Sandbox Code Playgroud)
这样,您可以从中加载特定的东西,appsettings.production.json并且仍然可以通过环境变量覆盖它.
没有Azure Vault或任何第三方提供者,有一种简单的方法可以安全地在生产中存储应用程序秘密:
dotnet helloworld -config; 在中Program.Main,检测到此开关以使用户输入机密并将其存储在加密的单独的.json文件中: public class Program
{
private const string APP_NAME = "5E71EE95-49BD-40A9-81CD-B1DFD873EEA8";
private const string SECRET_CONFIG_FILE_NAME = "appsettings.secret.json";
public static void Main(string[] args)
{
if (args != null && args.Length == 1 && args[0].ToLowerInvariant() == "-config")
{
ConfigAppSettingsSecret();
return;
}
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((builder, options) =>
{
options.AddJsonFile(ConfigFileFullPath, optional: true, reloadOnChange: false);
})
.UseStartup<Startup>();
private static void ConfigAppSettingsSecret()
{
var serviceCollection = new ServiceCollection();
AddDataProtection(serviceCollection);
var services = serviceCollection.BuildServiceProvider();
var dataProtectionProvider = services.GetService<IDataProtectionProvider>();
var protector = CreateProtector(dataProtectionProvider);
string dbPassword = protector.Protect("DbPassword", ReadPasswordFromConsole());
... // other secrets
string json = ...; // Serialize encrypted secrets to JSON
var path = ConfigFileFullPath;
File.WriteAllText(path, json);
Console.WriteLine($"Writing app settings secret to '${path}' completed successfully.");
}
private static string CurrentDirectory
{
get { return Directory.GetParent(typeof(Program).Assembly.Location).FullName; }
}
private static string ConfigFileFullPath
{
get { return Path.Combine(CurrentDirectory, SECRET_CONFIG_FILE_NAME); }
}
internal static void AddDataProtection(IServiceCollection serviceCollection)
{
serviceCollection.AddDataProtection()
.SetApplicationName(APP_NAME)
.DisableAutomaticKeyGeneration();
}
internal static IDataProtector CreateProtector(IDataProtectionProvider dataProtectionProvider)
{
return dataProtectionProvider.CreateProtector(APP_NAME);
}
}
Run Code Online (Sandbox Code Playgroud)
public void ConfigureServices(IServiceCollection services)
{
Program.AddDataProtection(services);
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
if (env.IsProduction())
{
var dataProtectionProvider = app.ApplicationServices.GetService<IDataProtectionProvider>();
var protector = Program.CreateProtector(dataProtectionProvider);
var builder = new SqlConnectionStringBuilder();
builder.Password = protector.Unprotect(configuration["DbPassword"]);
...
}
}
Run Code Online (Sandbox Code Playgroud)
而已!
| 归档时间: |
|
| 查看次数: |
12891 次 |
| 最近记录: |