fix(auth): 公开登录门按来源限速并设全站发信上限,冷却表定期清理
This commit is contained in:
26 files changed
+1141
-64
No files matched your search
@@ -300,8 +300,20 @@ func cmdAPI(args []string, stdout, stderr io.Writer) int {
|
||||
// for legitimate multi-tab / multi-server watching, while capping how many
|
||||
// upstream follow connections a single caller can tie up if their streams stall.
|
||||
MaxStreamsPerPrincipal: 16,
|
||||
// Public sign-in doors, per client address: a person signing in makes a
|
||||
// handful of calls, so 20 at once refilled at 20 a minute never bites a
|
||||
// real user and still turns a spray into a trickle. The client address
|
||||
// is the edge's header when the install names one (config.AuthConfig).
|
||||
AuthDoorLimit: api.RateLimit{Burst: 20, PerMinute: 20},
|
||||
ClientIPHeader: cfg.Auth.EffectiveClientIPHeader(),
|
||||
MailLimit: mailLimit(cfg.SMTP.MaxPerHour),
|
||||
}
|
||||
fmt.Fprintln(stderr, "felis api: external face fails closed (Access JWKS key function not configured)")
|
||||
if a.ClientIPHeader != "" {
|
||||
fmt.Fprintf(stderr, "felis api: sign-in rate limit keys on the %s header\n", a.ClientIPHeader)
|
||||
} else {
|
||||
fmt.Fprintln(stderr, "felis api: sign-in rate limit keys on the TCP peer ([auth] client_ip_header unset)")
|
||||
}
|
||||
|
||||
// Felis-nano: the multi-source hasJoined multiplexer. Mojang leads as the code-owned
|
||||
// identity anchor (正版优先); config can only append namespace-rewritten third-party
|
||||
@@ -546,3 +558,13 @@ func reconcileBuilds(ctx context.Context, b *build.Builder, stderr io.Writer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mailLimit turns smtp.max_per_hour into the API's install-wide mail bucket:
|
||||
// the hourly cap as the refill rate, with a quarter of it (at least 5) allowed
|
||||
// at once so a burst of real sign-ins is not queued behind the average.
|
||||
func mailLimit(perHour int) api.RateLimit {
|
||||
if perHour <= 0 {
|
||||
perHour = config.DefaultMailPerHour
|
||||
}
|
||||
return api.RateLimit{Burst: max(perHour/4, 5), PerMinute: float64(perHour) / 60}
|
||||
}
|
||||
@@ -32,7 +32,9 @@ func applyCloudflareEdge(ctx context.Context, result *cfsetup.Result, panelHost,
|
||||
if adminHost == "" {
|
||||
return fmt.Errorf("admin hostname is required")
|
||||
}
|
||||
if err := writeConnectionConfig(panelHost, adminHost, result.AccessAud); err != nil {
|
||||
// cloudflared is the only way in once the NodePort is fenced, so the
|
||||
// visitor address it writes can key the sign-in rate limit.
|
||||
if err := writeConnectionConfig(panelHost, adminHost, result.AccessAud, "CF-Connecting-IP"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := applyFelisConfigSecret(ctx); err != nil {
|
||||
@@ -78,7 +80,8 @@ func applyReverseProxy(ctx context.Context, panelHost, adminHost string) error {
|
||||
if adminHost == "" {
|
||||
return fmt.Errorf("admin hostname is required")
|
||||
}
|
||||
if err := writeConnectionConfig(panelHost, adminHost, ""); err != nil {
|
||||
// Caddy, nginx and Traefik all append the peer they saw to X-Forwarded-For.
|
||||
if err := writeConnectionConfig(panelHost, adminHost, "", "X-Forwarded-For"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := applyFelisConfigSecret(ctx); err != nil {
|
||||
@@ -93,16 +96,17 @@ func applyReverseProxy(ctx context.Context, panelHost, adminHost string) error {
|
||||
// writeConnectionConfig stamps the chosen hostnames (and optional Access audience)
|
||||
// into both the host and pod config files. An empty aud clears any prior
|
||||
// Cloudflare audience, which is correct when switching to a non-Access front.
|
||||
func writeConnectionConfig(panelHost, adminHost, aud string) error {
|
||||
// clientIPHeader is the header that front writes the visitor address into.
|
||||
func writeConnectionConfig(panelHost, adminHost, aud, clientIPHeader string) error {
|
||||
for _, path := range []string{hostSetupConfigPath, podSetupConfigPath} {
|
||||
if err := updateAuthConfig(path, panelHost, adminHost, aud); err != nil {
|
||||
if err := updateAuthConfig(path, panelHost, adminHost, aud, clientIPHeader); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateAuthConfig(path, panelHost, adminHost, aud string) error {
|
||||
func updateAuthConfig(path, panelHost, adminHost, aud, clientIPHeader string) error {
|
||||
cfg, err := config.Load(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -112,6 +116,7 @@ func updateAuthConfig(path, panelHost, adminHost, aud string) error {
|
||||
}
|
||||
cfg.Auth.AdminHostname = adminHost
|
||||
cfg.Auth.AccessJWTAud = aud
|
||||
cfg.Auth.ClientIPHeader = clientIPHeader
|
||||
return writeConfig(path, cfg)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user