172 lines
3.9 KiB
Go
172 lines
3.9 KiB
Go
|
|
package service
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"math/rand"
|
|||
|
|
"strings"
|
|||
|
|
"sync"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ==================== P1-04 审计事件采样策略 ====================
|
|||
|
|
|
|||
|
|
// AuditSamplingConfig 审计采样配置
|
|||
|
|
type AuditSamplingConfig struct {
|
|||
|
|
// 成功事件采样率 (0.0 - 1.0)
|
|||
|
|
// 0.01 = 1% 采样
|
|||
|
|
SuccessSampleRate float64
|
|||
|
|
|
|||
|
|
// 是否启用采样
|
|||
|
|
Enabled bool
|
|||
|
|
|
|||
|
|
// 强制全量记录的事件类型(不受采样影响)
|
|||
|
|
ForceRecordEventTypes []string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DefaultAuditSamplingConfig 默认审计采样配置
|
|||
|
|
func DefaultAuditSamplingConfig() *AuditSamplingConfig {
|
|||
|
|
return &AuditSamplingConfig{
|
|||
|
|
Enabled: true,
|
|||
|
|
SuccessSampleRate: 0.01, // 1% 采样
|
|||
|
|
ForceRecordEventTypes: []string{
|
|||
|
|
"token.authn.fail",
|
|||
|
|
"token.authz.fail",
|
|||
|
|
"token.revoked",
|
|||
|
|
"account.created",
|
|||
|
|
"account.deleted",
|
|||
|
|
"settlement.completed",
|
|||
|
|
"payment.processed",
|
|||
|
|
"admin.action",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditSampler 审计事件采样器
|
|||
|
|
type AuditSampler struct {
|
|||
|
|
config *AuditSamplingConfig
|
|||
|
|
sampled *rand.Rand
|
|||
|
|
mu sync.Mutex
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewAuditSampler 创建审计采样器
|
|||
|
|
func NewAuditSampler(config *AuditSamplingConfig) *AuditSampler {
|
|||
|
|
if config == nil {
|
|||
|
|
config = DefaultAuditSamplingConfig()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return &AuditSampler{
|
|||
|
|
config: config,
|
|||
|
|
sampled: rand.New(rand.NewSource(42)), // 确定性采样
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ShouldRecord 判断事件是否应该记录
|
|||
|
|
// 返回 true 表示记录,false 表示采样丢弃
|
|||
|
|
func (s *AuditSampler) ShouldRecord(eventName string, success bool) bool {
|
|||
|
|
if !s.config.Enabled {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 失败事件总是记录
|
|||
|
|
if !success {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 强制记录类型总是记录(支持前缀匹配)
|
|||
|
|
for _, forcedType := range s.config.ForceRecordEventTypes {
|
|||
|
|
if eventName == forcedType || strings.HasPrefix(eventName, forcedType) {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 成功事件按采样率决定
|
|||
|
|
return s.ShouldSample()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ShouldSample 判断成功事件是否应该采样
|
|||
|
|
func (s *AuditSampler) ShouldSample() bool {
|
|||
|
|
s.mu.Lock()
|
|||
|
|
defer s.mu.Unlock()
|
|||
|
|
|
|||
|
|
r := s.sampled.Float64()
|
|||
|
|
return r < s.config.SuccessSampleRate
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RecordRate 返回当前采样率
|
|||
|
|
func (s *AuditSampler) RecordRate() float64 {
|
|||
|
|
return 1.0 - s.config.SuccessSampleRate
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetConfig 返回采样配置
|
|||
|
|
func (s *AuditSampler) GetConfig() *AuditSamplingConfig {
|
|||
|
|
return s.config
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AuditEventClassifier 审计事件分类器
|
|||
|
|
type AuditEventClassifier struct{}
|
|||
|
|
|
|||
|
|
// NewAuditEventClassifier 创建事件分类器
|
|||
|
|
func NewAuditEventClassifier() *AuditEventClassifier {
|
|||
|
|
return &AuditEventClassifier{}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsHighPriorityEvent 判断是否为高优先级事件(失败事件)
|
|||
|
|
func (c *AuditEventClassifier) IsHighPriorityEvent(eventName string, success bool) bool {
|
|||
|
|
if !success {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
highPriorityPrefixes := []string{
|
|||
|
|
"token.authn.fail",
|
|||
|
|
"token.authz.fail",
|
|||
|
|
"token.revoked",
|
|||
|
|
"account.",
|
|||
|
|
"settlement.",
|
|||
|
|
"payment.",
|
|||
|
|
"admin.",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lowPriorityPrefixes := []string{
|
|||
|
|
"token.authn.success",
|
|||
|
|
"token.access",
|
|||
|
|
"api.request",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否低优先级
|
|||
|
|
for _, prefix := range lowPriorityPrefixes {
|
|||
|
|
if strings.HasPrefix(eventName, prefix) {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否高优先级
|
|||
|
|
for _, prefix := range highPriorityPrefixes {
|
|||
|
|
if strings.HasPrefix(eventName, prefix) {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetSamplingRecommendation 获取采样建议
|
|||
|
|
func (c *AuditEventClassifier) GetSamplingRecommendation(eventName string) string {
|
|||
|
|
if strings.HasPrefix(eventName, "token.authn.success") {
|
|||
|
|
return "1% sampling recommended"
|
|||
|
|
}
|
|||
|
|
if strings.HasPrefix(eventName, "token.authn.fail") {
|
|||
|
|
return "100% record required"
|
|||
|
|
}
|
|||
|
|
if strings.HasPrefix(eventName, "account.") {
|
|||
|
|
return "100% record required"
|
|||
|
|
}
|
|||
|
|
if strings.HasPrefix(eventName, "settlement.") {
|
|||
|
|
return "100% record required"
|
|||
|
|
}
|
|||
|
|
if strings.HasPrefix(eventName, "payment.") {
|
|||
|
|
return "100% record required"
|
|||
|
|
}
|
|||
|
|
if strings.HasPrefix(eventName, "api.request") {
|
|||
|
|
return "1% sampling recommended"
|
|||
|
|
}
|
|||
|
|
return "10% sampling recommended"
|
|||
|
|
}
|