收口三个匿名可读端点: - 根路径 /metrics:默认完全不注册(访问 404);配置 METRICS_ALLOW_CIDR 后按内网白名单开放 - /health:改为鉴权(原本匿名泄漏版本、commit、运行时长、内存、goroutine 与配置错误文本) - /dashboard:改为鉴权(原本匿名,且它同时聚合 /health 与 /metrics,是单点泄漏最严重的端点) - /api/setup/status:改为鉴权(原本 normal 模式下仍匿名返回 installed/mode) 新增 /healthz 匿名存活探针,只回 200 与字面量 ok、不含任何字段,解决 "给 /health 加鉴权后 K8s 探针与 Docker HEALTHCHECK 会一律 401 导致 Pod 反复重启" 的问题; 新增 /api/admin/health 鉴权版详细健康数据,与 /api/admin/metrics 风格一致。 /dashboard 对浏览器 HTML 请求做内容协商:返回页面外壳由前端显示登录视图(SPA 登录态存在 sessionStorage、不随请求发送,服务端无从判断,强行 401 会把现有体验变成直接报错); 非 HTML 请求(脚本、抓取)无凭证一律 401。页面外壳本身不含数据,数据全部来自鉴权后的 API。 IP 白名单中间件复用 GetClientIP(已处理 XFF 与 TRUSTED_PROXY_HOPS),非白名单返回 404 而非 403,避免向扫描者确认端点存在。main.go 启动日志同步改为指向 /healthz 与 /api/admin/health。 验证(真实服务器端到端,非仅单元测试): - 安装前 /healthz=200、/health=401 - 安装后未带凭证:/healthz=200 /health=401 /metrics=404 /dashboard=401 /api/setup/status=401 - /dashboard 带 Accept: text/html 得 200 页面外壳,Accept: application/json 得 401 - /healthz 响应体确认为字面量 ok(不含任何字段) - 回退模式(未配 admin_key):业务 key 访问管理接口全部 200,向后兼容成立 - 配置独立 admin_key 后:业务 key 访问 /health /api/admin/* /api/voices /api/settings 全部 401, admin_key 全部 200,而 /v1/audio/speech 不受影响;GET /api/settings 只回打码值 另新增 middleware/metricsip_test.go 覆盖 CIDR 命中、越界、非法 IP、空列表拒绝, 以及伪造 X-Forwarded-For 不能绕过白名单。 go build ./... / go vet ./... / go test ./... -count=1 全绿。
This commit is contained in:
@@ -274,6 +274,21 @@ func contentTypeFor(format string) string {
|
||||
}
|
||||
|
||||
// HealthHandler 暴露运行期状态;无鉴权。
|
||||
// HealthzHandler GET /healthz —— 匿名存活探针,**只回 200 与字面量 "ok"**。
|
||||
//
|
||||
// 为什么单独做这个:v0.3.0 把详细健康数据(/health)收口到管理鉴权之后,
|
||||
// 但 K8s liveness/readiness、Docker HEALTHCHECK、负载均衡健康检查默认都不带 Authorization。
|
||||
// 若把它们继续指向 /health,加鉴权后会一律 401,导致探针失败、Pod 反复重启。
|
||||
//
|
||||
// 因此本端点刻意**不返回任何字段**(无版本、无内存、无配置状态、无模式信息),
|
||||
// 只用于回答"进程还在不在"。运维要细节请走鉴权后的 /health。
|
||||
func HealthzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
func HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user