security: add tenant allowlist and WAF canary proof

This commit is contained in:
Andrew Stoltz
2026-06-18 16:21:08 -05:00
parent bd050c3d9b
commit 9cef99739a
5 changed files with 90 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
{
"apiVersion": "v1",
"data": {
"default.conf": "server {\n listen 80;\n server_name _;\n root /usr/share/nginx/html;\n index index.html;\n location / { try_files $uri $uri/ =404; }\n location /healthz { access_log off; return 200 \"ok\"; add_header Content-Type text/plain; }\n}\n"
"default.conf": "server {\n listen 80;\n server_name _;\n root /usr/share/nginx/html;\n index index.html;\n location / { try_files $uri $uri/ =404; }\n location = /lamp-canary/index.php { add_header Content-Type text/plain; return 200 \"lamp-index-ok\\n\"; }\n location = /lamp-canary/wp-login.php { add_header Content-Type text/plain; return 200 \"wp-login-ok\\n\"; }\n location = /lamp-canary/mediawiki/index.php { add_header Content-Type text/plain; return 200 \"mediawiki-ok\\n\"; }\n location = /admin-allowlist-proof { add_header Content-Type text/plain; return 200 \"admin-allowlist-ok\\n\"; }\n location /healthz { access_log off; return 200 \"ok\"; add_header Content-Type text/plain; }\n}\n"
},
"kind": "ConfigMap",
"metadata": {

View File

@@ -26,6 +26,9 @@
},
"template": {
"metadata": {
"annotations": {
"flowercore.io/config-revision": "whc4-lamp-allowlist-20260618"
},
"labels": {
"app": "andrew-web"
}

View File

@@ -30,6 +30,31 @@
"port": 8080
}
]
},
{
"kind": "Rule",
"match": "(Host(`bluejay.dev`) || Host(`www.bluejay.dev`)) && PathPrefix(`/admin-allowlist-proof`)",
"middlewares": [
{
"name": "andrew-admin-ip-allowlist",
"namespace": "fc-tenant-andrew"
},
{
"name": "andrew-tenant-rate-limit",
"namespace": "fc-tenant-andrew"
},
{
"name": "andrew-tenant-secure-headers",
"namespace": "fc-tenant-andrew"
}
],
"priority": 300,
"services": [
{
"name": "andrew-web-waf",
"port": 8080
}
]
}
],
"tls": {

View File

@@ -0,0 +1,15 @@
{
"apiVersion": "traefik.io/v1alpha1",
"kind": "Middleware",
"metadata": {
"name": "andrew-admin-ip-allowlist",
"namespace": "fc-tenant-andrew"
},
"spec": {
"ipAllowList": {
"sourceRange": [
"10.0.56.14/32"
]
}
}
}

View File

@@ -1128,9 +1128,48 @@ public sealed class FleetManifestLintTests
.Should()
.Equal("andrew-tenant-rate-limit", "andrew-tenant-secure-headers");
var adminRoute = ingressRoute.RootElement
.GetProperty("spec")
.GetProperty("routes")
.EnumerateArray()
.Single(route => route.GetProperty("match").GetString()!.Contains("PathPrefix(`/admin-allowlist-proof`)", StringComparison.Ordinal));
adminRoute.GetProperty("priority").GetInt32().Should().Be(300);
adminRoute.GetProperty("services").EnumerateArray().Should().ContainSingle().Subject
.GetProperty("name").GetString().Should().Be("andrew-web-waf");
adminRoute.GetProperty("middlewares")
.EnumerateArray()
.Select(item => item.GetProperty("name").GetString())
.Should()
.Equal("andrew-admin-ip-allowlist", "andrew-tenant-rate-limit", "andrew-tenant-secure-headers");
using var rateLimit = JsonDocument.Parse(File.ReadAllText(Path.Combine(appRoot, "middleware-andrew-tenant-rate-limit.json")));
rateLimit.RootElement.GetProperty("spec").GetProperty("rateLimit").GetProperty("average").GetInt32().Should().Be(120);
using var allowlist = JsonDocument.Parse(File.ReadAllText(Path.Combine(appRoot, "middleware-andrew-admin-ip-allowlist.json")));
allowlist.RootElement.GetProperty("kind").GetString().Should().Be("Middleware");
allowlist.RootElement.GetProperty("spec").GetProperty("ipAllowList").GetProperty("sourceRange")
.EnumerateArray()
.Select(item => item.GetString())
.Should()
.Equal("10.0.56.14/32");
using var nginxConfig = JsonDocument.Parse(File.ReadAllText(Path.Combine(appRoot, "configmap-andrew-web-nginx-conf.json")));
var nginx = nginxConfig.RootElement.GetProperty("data").GetProperty("default.conf").GetString();
nginx.Should().Contain("location = /lamp-canary/index.php");
nginx.Should().Contain("location = /lamp-canary/wp-login.php");
nginx.Should().Contain("location = /lamp-canary/mediawiki/index.php");
nginx.Should().Contain("location = /admin-allowlist-proof");
using var webDeployment = JsonDocument.Parse(File.ReadAllText(Path.Combine(appRoot, "deployment-andrew-web.json")));
webDeployment.RootElement.GetProperty("spec")
.GetProperty("template")
.GetProperty("metadata")
.GetProperty("annotations")
.GetProperty("flowercore.io/config-revision")
.GetString()
.Should()
.Be("whc4-lamp-allowlist-20260618");
using var headers = JsonDocument.Parse(File.ReadAllText(Path.Combine(appRoot, "middleware-andrew-tenant-secure-headers.json")));
var headerSpec = headers.RootElement.GetProperty("spec").GetProperty("headers");
headerSpec.GetProperty("contentTypeNosniff").GetBoolean().Should().BeTrue();