feat(admin-console): Stage 1 — pipe + skeleton behind the gateway
Tests · Go / test (push) Successful in 2m0s
Tests · Go / test (push) Successful in 2m0s
Add the server-rendered operator console at /_gm, exposed publicly through the gateway behind the existing admin_accounts Basic Auth. Backend: - new internal/adminconsole package (html/template Renderer, stateless HMAC CSRF signer, embedded stylesheet) - /_gm route group reusing basicauth.Middleware(admin.Service) + a CSRF guard (per-operator token + same-origin check); dashboard landing page - BACKEND_ADMIN_CONSOLE_CSRF_KEY config (per-process random fallback) Gateway: - new "admin" public route class (per-IP rate limit, body + GET/HEAD/POST method limits) classifying /_gm traffic - reverse proxy to the backend /_gm surface, preserving Host and relaying the backend 401 Basic Auth challenge; 502 when the backend is unreachable - GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_* config dev-deploy: - Caddy routes /_gm/* to the gateway - bootstrap admin + stable CSRF key; enable Prometheus /metrics exporters on backend and gateway (forward-compat for a future Prometheus/Grafana stack) Docs: ARCHITECTURE 14.1/16, FUNCTIONAL 10.2.1 (+ru mirror), backend and gateway READMEs, new backend/docs/admin-console.md. Tests: renderer + CSRF unit tests; backend router auth/render/asset/CSRF; gateway classifier, proxy forwarding/Host/401/405/413/429/502.
This commit is contained in:
@@ -276,6 +276,22 @@ const (
|
||||
// configures the public_misc rate-limit burst.
|
||||
publicMiscRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_RATE_LIMIT_BURST"
|
||||
|
||||
// adminMaxBodyBytesEnvVar names the environment variable that configures
|
||||
// the maximum accepted request body size for the admin console class.
|
||||
adminMaxBodyBytesEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_MAX_BODY_BYTES"
|
||||
|
||||
// adminRateLimitRequestsEnvVar names the environment variable that
|
||||
// configures the admin console request budget per window.
|
||||
adminRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_RATE_LIMIT_REQUESTS"
|
||||
|
||||
// adminRateLimitWindowEnvVar names the environment variable that configures
|
||||
// the admin console rate-limit window.
|
||||
adminRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_RATE_LIMIT_WINDOW"
|
||||
|
||||
// adminRateLimitBurstEnvVar names the environment variable that configures
|
||||
// the admin console rate-limit burst.
|
||||
adminRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_RATE_LIMIT_BURST"
|
||||
|
||||
// sendEmailCodeIdentityRateLimitRequestsEnvVar names the environment
|
||||
// variable that configures the send-email-code identity request budget per
|
||||
// window.
|
||||
@@ -372,6 +388,14 @@ const (
|
||||
defaultPublicMiscRateLimitRequests = 30
|
||||
defaultPublicMiscRateLimitBurst = 10
|
||||
|
||||
// Admin console class: sized for a human operator clicking through pages
|
||||
// and submitting forms, while still throttling Basic Auth brute-force at
|
||||
// the edge. The body budget accommodates form posts.
|
||||
defaultAdminMaxBodyBytes = int64(65536)
|
||||
|
||||
defaultAdminRateLimitRequests = 120
|
||||
defaultAdminRateLimitBurst = 40
|
||||
|
||||
defaultSendEmailCodeIdentityRateLimitRequests = 3
|
||||
defaultSendEmailCodeIdentityRateLimitBurst = 1
|
||||
|
||||
@@ -439,6 +463,11 @@ type PublicHTTPAntiAbuseConfig struct {
|
||||
// PublicMisc applies to the stable public_misc route class.
|
||||
PublicMisc PublicRoutePolicyConfig
|
||||
|
||||
// Admin applies to the stable admin route class — the `/_gm` operator
|
||||
// console reverse-proxied to the backend. Only per-IP limiting applies;
|
||||
// the class carries no identity buckets.
|
||||
Admin PublicRoutePolicyConfig
|
||||
|
||||
// SendEmailCodeIdentity applies the additional identity limiter for
|
||||
// send-email-code.
|
||||
SendEmailCodeIdentity PublicAuthIdentityPolicyConfig
|
||||
@@ -708,6 +737,14 @@ func DefaultPublicHTTPConfig() PublicHTTPConfig {
|
||||
Burst: defaultPublicMiscRateLimitBurst,
|
||||
},
|
||||
},
|
||||
Admin: PublicRoutePolicyConfig{
|
||||
MaxBodyBytes: defaultAdminMaxBodyBytes,
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultAdminRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAdminRateLimitBurst,
|
||||
},
|
||||
},
|
||||
SendEmailCodeIdentity: PublicAuthIdentityPolicyConfig{
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultSendEmailCodeIdentityRateLimitRequests,
|
||||
@@ -1092,6 +1129,18 @@ func LoadFromEnv() (Config, error) {
|
||||
}
|
||||
cfg.PublicHTTP.AntiAbuse.PublicMisc = publicMiscPolicy
|
||||
|
||||
adminPolicy, err := loadPublicRoutePolicyConfigFromEnv(
|
||||
cfg.PublicHTTP.AntiAbuse.Admin,
|
||||
adminMaxBodyBytesEnvVar,
|
||||
adminRateLimitRequestsEnvVar,
|
||||
adminRateLimitWindowEnvVar,
|
||||
adminRateLimitBurstEnvVar,
|
||||
)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.PublicHTTP.AntiAbuse.Admin = adminPolicy
|
||||
|
||||
sendIdentityPolicy, err := loadPublicAuthIdentityPolicyConfigFromEnv(
|
||||
cfg.PublicHTTP.AntiAbuse.SendEmailCodeIdentity,
|
||||
sendEmailCodeIdentityRateLimitRequestsEnvVar,
|
||||
@@ -1247,6 +1296,9 @@ func LoadFromEnv() (Config, error) {
|
||||
if err := validatePublicRoutePolicyConfig(cfg.PublicHTTP.AntiAbuse.PublicMisc, publicMiscMaxBodyBytesEnvVar, publicMiscRateLimitRequestsEnvVar, publicMiscRateLimitWindowEnvVar, publicMiscRateLimitBurstEnvVar); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
if err := validatePublicRoutePolicyConfig(cfg.PublicHTTP.AntiAbuse.Admin, adminMaxBodyBytesEnvVar, adminRateLimitRequestsEnvVar, adminRateLimitWindowEnvVar, adminRateLimitBurstEnvVar); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
if err := validatePublicAuthIdentityPolicyConfig(cfg.PublicHTTP.AntiAbuse.SendEmailCodeIdentity, sendEmailCodeIdentityRateLimitRequestsEnvVar, sendEmailCodeIdentityRateLimitWindowEnvVar, sendEmailCodeIdentityRateLimitBurstEnvVar); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user