feat(ssf): 实现安全事件一键连接与凭据托管
新增数据库驱动的 SecurityEventConnectionManager,复用 RFC 7662 机器 Client,自动完成 Discovery、Push Bearer 生成、Stream 创建、Verification、首次启用、零停机轮换和安全退役。 增加文件与 Kubernetes SecretStore、最小权限 RBAC、动态 Receiver/撤销水位/内省降级,以及系统设置管理页面。已通过全量 Go 测试、go vet、关键包竞态测试、27 个 Web 测试、类型检查、生产构建、Compose 和 Kubernetes dry-run。
This commit is contained in:
@@ -179,9 +179,10 @@ func TestOIDCSecurityEventEvaluationUsesWatermarkAndFallbackIntrospection(t *tes
|
||||
verifier, err := NewOIDCVerifier(OIDCConfig{
|
||||
Issuer: issuer, Audience: "gateway-api", TenantID: "tenant-1", RolePrefix: "gateway.",
|
||||
RequiredScopes: []string{"gateway.access"}, HTTPClient: server.Client(),
|
||||
IntrospectionEnabled: true,
|
||||
IntrospectionClientID: "gateway-introspection", IntrospectionClientSecret: "introspection-secret",
|
||||
SecurityEventEvaluator: func(_ context.Context, identity OIDCSecurityEventIdentity) (OIDCSecurityEventEvaluation, error) {
|
||||
if identity.Subject != "platform-subject" || identity.IssuedAt.IsZero() {
|
||||
if identity.Subject != "platform-subject" {
|
||||
t.Fatal("security event evaluator received incomplete identity")
|
||||
}
|
||||
return evaluation, nil
|
||||
@@ -194,6 +195,10 @@ func TestOIDCSecurityEventEvaluationUsesWatermarkAndFallbackIntrospection(t *tes
|
||||
if _, err := verifier.Verify(context.Background(), raw); err != nil || introspectionCalls != 1 {
|
||||
t.Fatalf("fallback token error=%v calls=%d", err, introspectionCalls)
|
||||
}
|
||||
evaluation = OIDCSecurityEventEvaluation{Enabled: true}
|
||||
if _, err := verifier.Verify(context.Background(), raw); err != nil || introspectionCalls != 1 {
|
||||
t.Fatalf("healthy push token error=%v calls=%d", err, introspectionCalls)
|
||||
}
|
||||
evaluation = OIDCSecurityEventEvaluation{Revoked: true}
|
||||
if _, err := verifier.Verify(context.Background(), raw); err == nil || introspectionCalls != 1 {
|
||||
t.Fatalf("revoked token error=%v calls=%d", err, introspectionCalls)
|
||||
@@ -205,6 +210,16 @@ func TestOIDCSecurityEventEvaluationUsesWatermarkAndFallbackIntrospection(t *tes
|
||||
if !errors.As(err, &requestError) || requestError.Status != http.StatusServiceUnavailable {
|
||||
t.Fatalf("introspection outage error=%T %v", err, err)
|
||||
}
|
||||
withoutIssuedAt := signedOIDCToken(t, issuer, "ec-key", jwt.SigningMethodES256, key, func(claims jwt.MapClaims) { delete(claims, "iat") })
|
||||
evaluation = OIDCSecurityEventEvaluation{}
|
||||
introspectionAvailable = true
|
||||
if _, err := verifier.Verify(context.Background(), withoutIssuedAt); err != nil {
|
||||
t.Fatalf("unconfigured security events unexpectedly required iat: %v", err)
|
||||
}
|
||||
evaluation = OIDCSecurityEventEvaluation{Enabled: true}
|
||||
if _, err := verifier.Verify(context.Background(), withoutIssuedAt); err == nil {
|
||||
t.Fatal("configured security events accepted a token without iat")
|
||||
}
|
||||
}
|
||||
|
||||
func signedOIDCToken(t *testing.T, issuer, kid string, method jwt.SigningMethod, key any, mutate func(jwt.MapClaims)) string {
|
||||
|
||||
Reference in New Issue
Block a user