public static IHostBuilder CreateHostBuilder(IConsole console, string[] urls, string[] metricUrls, bool metrics, string diagnosticPort, bool noAuth) { return(Host.CreateDefaultBuilder() .UseContentRoot(AppContext.BaseDirectory) // Use the application root instead of the current directory .ConfigureAppConfiguration((IConfigurationBuilder builder) => { //Note these are in precedence order. ConfigureEndpointInfoSource(builder, diagnosticPort); ConfigureMetricsEndpoint(builder, metrics, metricUrls); builder.AddCommandLine(new[] { "--urls", ConfigurationHelper.JoinValue(urls) }); builder.AddJsonFile(UserSettingsPath, optional: true, reloadOnChange: true); builder.AddJsonFile(SharedSettingsPath, optional: true, reloadOnChange: true); //HACK Workaround for https://github.com/dotnet/runtime/issues/36091 //KeyPerFile provider uses a file system watcher to trigger changes. //The watcher does not follow symlinks inside the watched directory, such as mounted files //in Kubernetes. //We get around this by watching the target folder of the symlink instead. //See https://github.com/kubernetes/kubernetes/master/pkg/volume/util/atomic_writer.go string path = SharedConfigDirectoryPath; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInfo.IsInKubernetes) { string symlinkTarget = Path.Combine(SharedConfigDirectoryPath, "..data"); if (Directory.Exists(symlinkTarget)) { path = symlinkTarget; } } builder.AddKeyPerFile(path, optional: true, reloadOnChange: true); builder.AddEnvironmentVariables(ConfigPrefix); }) .ConfigureServices((HostBuilderContext context, IServiceCollection services) => { //TODO Many of these service additions should be done through extension methods AuthOptions authenticationOptions = new AuthOptions(noAuth ? KeyAuthenticationMode.NoAuth : KeyAuthenticationMode.StoredKey); services.AddSingleton <IAuthOptions>(authenticationOptions); List <string> authSchemas = null; if (authenticationOptions.EnableKeyAuth) { //Add support for Authentication and Authorization. AuthenticationBuilder authBuilder = services.AddAuthentication(options => { options.DefaultAuthenticateScheme = AuthConstants.ApiKeySchema; options.DefaultChallengeScheme = AuthConstants.ApiKeySchema; }) .AddScheme <ApiKeyAuthenticationHandlerOptions, ApiKeyAuthenticationHandler>(AuthConstants.ApiKeySchema, _ => { }); authSchemas = new List <string> { AuthConstants.ApiKeySchema }; if (authenticationOptions.EnableNegotiate) { //On Windows add Negotiate package. This will use NTLM to perform Windows Authentication. authBuilder.AddNegotiate(); authSchemas.Add(AuthConstants.NegotiateSchema); } } //Apply Authorization Policy for NTLM. Without Authorization, any user with a valid login/password will be authorized. We only //want to authorize the same user that is running dotnet-monitor, at least for now. //Note this policy applies to both Authorization schemas. services.AddAuthorization(authOptions => { if (authenticationOptions.EnableKeyAuth) { authOptions.AddPolicy(AuthConstants.PolicyName, (builder) => { builder.AddRequirements(new AuthorizedUserRequirement()); builder.RequireAuthenticatedUser(); builder.AddAuthenticationSchemes(authSchemas.ToArray()); }); } else { authOptions.AddPolicy(AuthConstants.PolicyName, (builder) => { builder.RequireAssertion((_) => true); }); } }); if (authenticationOptions.EnableKeyAuth) { services.AddSingleton <IAuthorizationHandler, UserAuthorizationHandler>(); } services.Configure <DiagnosticPortOptions>(context.Configuration.GetSection(ConfigurationKeys.DiagnosticPort)); services.AddSingleton <IEndpointInfoSource, FilteredEndpointInfoSource>(); services.AddHostedService <FilteredEndpointInfoSourceHostedService>(); services.AddSingleton <IDiagnosticServices, DiagnosticServices>(); services.ConfigureEgress(context.Configuration); services.ConfigureMetrics(context.Configuration); services.AddSingleton <ExperimentalToolLogger>(); }) .ConfigureLogging(builder => { // Always allow the experimental tool message to be logged ExperimentalToolLogger.AddLogFilter(builder); }) .ConfigureWebHostDefaults(webBuilder => { AddressListenResults listenResults = new AddressListenResults(); webBuilder.ConfigureServices(services => { services.AddSingleton(listenResults); }) .ConfigureKestrel((context, options) => { //Note our priorities for hosting urls don't match the default behavior. //Default Kestrel behavior priority //1) ConfigureKestrel settings //2) Command line arguments (--urls) //3) Environment variables (ASPNETCORE_URLS, then DOTNETCORE_URLS) //Our precedence //1) Environment variables (ASPNETCORE_URLS, DotnetMonitor_Metrics__Endpoints) //2) Command line arguments (these have defaults) --urls, --metricUrls //3) ConfigureKestrel is used for fine control of the server, but honors the first two configurations. string hostingUrl = context.Configuration.GetValue <string>(WebHostDefaults.ServerUrlsKey); urls = ConfigurationHelper.SplitValue(hostingUrl); var metricsOptions = new MetricsOptions(); context.Configuration.Bind(ConfigurationKeys.Metrics, metricsOptions); //Workaround for lack of default certificate. See https://github.com/dotnet/aspnetcore/issues/28120 options.Configure(context.Configuration.GetSection("Kestrel")).Load(); //By default, we bind to https for sensitive data (such as dumps and traces) and bind http for //non-sensitive data such as metrics. We may be missing a certificate for https binding. We want to continue with the //http binding in that scenario. metricUrls = metricsOptions.Enabled.GetValueOrDefault(MetricsOptionsDefaults.Enabled) ? ProcessMetricUrls(metricUrls, metricsOptions) : Array.Empty <string>(); listenResults.Listen(options, urls, metricUrls); }) .UseStartup <Startup>(); })); }
public static IHostBuilder CreateHostBuilder(string[] urls, string[] metricUrls, bool metrics, string diagnosticPort, AuthConfiguration authenticationOptions) { return(Host.CreateDefaultBuilder() .UseContentRoot(AppContext.BaseDirectory) // Use the application root instead of the current directory .ConfigureHostConfiguration((IConfigurationBuilder builder) => { //Note these are in precedence order. ConfigureEndpointInfoSource(builder, diagnosticPort); ConfigureMetricsEndpoint(builder, metrics, metricUrls); ConfigureGlobalMetrics(builder); builder.ConfigureStorageDefaults(); builder.AddCommandLine(new[] { "--urls", ConfigurationHelper.JoinValue(urls) }); }) .ConfigureAppConfiguration((IConfigurationBuilder builder) => { builder.AddJsonFile(UserSettingsPath, optional: true, reloadOnChange: true); builder.AddJsonFile(SharedSettingsPath, optional: true, reloadOnChange: true); //HACK Workaround for https://github.com/dotnet/runtime/issues/36091 //KeyPerFile provider uses a file system watcher to trigger changes. //The watcher does not follow symlinks inside the watched directory, such as mounted files //in Kubernetes. //We get around this by watching the target folder of the symlink instead. //See https://github.com/kubernetes/kubernetes/master/pkg/volume/util/atomic_writer.go string path = SharedConfigDirectoryPath; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInfo.IsInKubernetes) { string symlinkTarget = Path.Combine(SharedConfigDirectoryPath, "..data"); if (Directory.Exists(symlinkTarget)) { path = symlinkTarget; } } builder.AddKeyPerFile(path, optional: true, reloadOnChange: true); builder.AddEnvironmentVariables(ConfigPrefix); if (authenticationOptions.KeyAuthenticationMode == KeyAuthenticationMode.TemporaryKey) { ConfigureTempApiHashKey(builder, authenticationOptions); } }) //Note this is necessary for config only because Kestrel configuration //is not added until WebHostDefaults are added. .ConfigureWebHostDefaults(webBuilder => { AddressListenResults listenResults = new AddressListenResults(); webBuilder.ConfigureServices(services => { services.AddSingleton(listenResults); }) .ConfigureKestrel((context, options) => { //Note our priorities for hosting urls don't match the default behavior. //Default Kestrel behavior priority //1) ConfigureKestrel settings //2) Command line arguments (--urls) //3) Environment variables (ASPNETCORE_URLS, then DOTNETCORE_URLS) //Our precedence //1) Environment variables (ASPNETCORE_URLS, DotnetMonitor_Metrics__Endpoints) //2) Command line arguments (these have defaults) --urls, --metricUrls //3) ConfigureKestrel is used for fine control of the server, but honors the first two configurations. string hostingUrl = context.Configuration.GetValue <string>(WebHostDefaults.ServerUrlsKey); urls = ConfigurationHelper.SplitValue(hostingUrl); var metricsOptions = new MetricsOptions(); context.Configuration.Bind(ConfigurationKeys.Metrics, metricsOptions); string metricHostingUrls = metricsOptions.Endpoints; metricUrls = ConfigurationHelper.SplitValue(metricHostingUrls); //Workaround for lack of default certificate. See https://github.com/dotnet/aspnetcore/issues/28120 options.Configure(context.Configuration.GetSection("Kestrel")).Load(); //By default, we bind to https for sensitive data (such as dumps and traces) and bind http for //non-sensitive data such as metrics. We may be missing a certificate for https binding. We want to continue with the //http binding in that scenario. listenResults.Listen( options, urls, metricsOptions.Enabled.GetValueOrDefault(MetricsOptionsDefaults.Enabled) ? metricUrls : Array.Empty <string>()); }) .UseStartup <Startup>(); })); }