Skip to content

Commit 512a318

Browse files
committed
Add IP restriction health check feature
1 parent 43dcb8f commit 512a318

4 files changed

Lines changed: 62 additions & 2 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Microsoft.AspNetCore.Http;
2+
using Microsoft.Extensions.Configuration;
3+
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
5+
using OrchardCore.Environment.Shell.Configuration;
6+
7+
namespace OrchardCoreContrib.HealthChecks;
8+
9+
public class HealthCheckIPRestrictionMiddleware(
10+
RequestDelegate next,
11+
IShellConfiguration shellConfiguration,
12+
IOptions<HealthChecksOptions> healthChecksOptions,
13+
ILogger<HealthCheckIPRestrictionMiddleware> logger)
14+
{
15+
private readonly HealthChecksOptions _healthChecksOptions = healthChecksOptions.Value;
16+
private readonly HashSet<string> _allowedIPs = shellConfiguration.GetSection($"{Constants.ConfigurationKey}:AllowedIPs")
17+
.Get<string[]>()?.ToHashSet() ?? [];
18+
19+
public async Task InvokeAsync(HttpContext context)
20+
{
21+
if (context.Request.Path.Equals(_healthChecksOptions.Url))
22+
{
23+
var remoteIP = context.Connection.RemoteIpAddress?.ToString();
24+
if (!_allowedIPs.Contains(remoteIP))
25+
{
26+
logger.LogWarning("Unauthorized IP {IP} tried to access {HealthCheckEndpoint}.", remoteIP, _healthChecksOptions.Url);
27+
context.Response.StatusCode = StatusCodes.Status403Forbidden;
28+
29+
await context.Response.WriteAsync("Forbidden");
30+
31+
return;
32+
}
33+
}
34+
35+
await next(context);
36+
}
37+
}

src/OrchardCoreContrib.HealthChecks/Manifest.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
Author = ManifestConstants.Author,
77
Website = ManifestConstants.Website,
88
Version = "1.4.0",
9-
Description = "Provides health checks for the website.",
109
Category = "Infrastructure"
1110
)]
11+
12+
[assembly: Feature(
13+
Id = "OrchardCoreContrib.HealthChecks",
14+
Name = "Health Checks",
15+
Description = "Provides health checks for the website."
16+
)]
17+
18+
[assembly: Feature(
19+
Id = "OrchardCoreContrib.HealthChecks.IPRestriction",
20+
Name = "Health Checks IP Restriction",
21+
Description = "Restricts access to health check endpoints by IP address.",
22+
Dependencies = [ "OrchardCoreContrib.HealthChecks" ]
23+
)]

src/OrchardCoreContrib.HealthChecks/Startup.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Text.Json;
1313

1414
namespace OrchardCoreContrib.HealthChecks;
15+
1516
public class Startup(IShellConfiguration shellConfiguration) : StartupBase
1617
{
1718
private static readonly JsonSerializerOptions _jsonSerializerOptions = new() { WriteIndented = true };
@@ -66,3 +67,12 @@ private static async Task WriteResponse(HttpContext context, HealthReport report
6667
await context.Response.WriteAsync(JsonSerializer.Serialize(response, response.GetType(), options: _jsonSerializerOptions));
6768
}
6869
}
70+
71+
[Feature("OrchardCoreContrib.HealthChecks.IPRestriction")]
72+
public class IPRestrictionStartup : StartupBase
73+
{
74+
public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
75+
{
76+
app.UseMiddleware<HealthCheckIPRestrictionMiddleware>();
77+
}
78+
}

src/OrchardCoreContrib.Modules.Web/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
//},
4545
//"OrchardCoreContrib_HealthChecks": {
4646
// "Url": "/health",
47-
// "ShowDetails": true
47+
// "ShowDetails": true,
48+
// "AllowedIPs": [ "127.0.0.1", "::1", "192.168.1.100" ]
4849
//},
4950
//"OrchardCoreContrib_Garnet": {
5051
// "Host": "127.0.0.1",

0 commit comments

Comments
 (0)