Files
opsxsql/docs/CONFIGURATION.md
logan 3a6dd99633 feat: 审核规则驱动SQL检查 + db_type过滤 + Redis只读拦截 + 配置文档
1. 审核规则改为从audit_rules表动态匹配(去硬编码)
   - CreateTicket提交时查audit_rules WHERE db_type=? AND is_enabled=true
   - 正则匹配SQL,value=reject拦截,warn/review放行
   - UPDATE/DELETE无WHERE: Go RE2不支持(?!...)负向前瞻
     → 用value=where_check特殊标记+strings.Contains WHERE检测
   - 修复UPDATE/DELETE无WHERE正则(Go兼容)

2. ListAuditRules按db_type过滤
   - ghost.go: 添加c.Query('db_type') WHERE过滤
   - MySQL不显示KEYS规则,Redis不显示DROP规则

3. Redis只读命令拦截(工单提交)
   - 新增Redis只读命令白名单: GET/HGET/MGET/HGETALL/KEYS/SCAN等28个
   - 只读命令走工单→直接拦截,引导用户用查询功能

4. 补充audit_rules规则
   - Redis新增7条: DEBUG/SHUTDOWN/SCRIPT/SAVE/BGSAVE/BGREWRITEAOF/SLAVEOF/CLUSTER
   - MySQL新增1条: DROP SCHEMA
   - 总计34条规则(MySQL12/Redis11/PG7/MongoDB4)

5. docs/CONFIGURATION.md 配置系统文档
   - 三套配置体系: system_settings/audit_rules/ldap_configs
   - 每项配置: key/默认值/作用/代码引用位置
   - 未引用配置标注: executor_batch_size/executor_backup/query_max_rows_examined(待实现)
   - LDAP冗余配置: system_settings中7项ldap_*无代码引用(LDAP用独立表)

验证: 5/5审批流通过, 36/36安全测试通过, 27/27审核规则匹配正确
2026-06-03 03:17:22 +08:00

23 KiB
Raw Permalink Blame History

OpsxSQL 平台配置系统文档

本文档详细说明 OpsxSQL 平台的三套配置体系:system_settings 系统设置、audit_rules 审核规则、ldap_configs LDAP 配置。

最后更新:2025-06


目录


一、配置体系总览

配置体系 存储表 配置项数 用途
系统设置 system_settings 42 项(7 个分组) 平台运行参数
审核规则 audit_rules 34 条(4 种 DB 类型) SQL 提交审核拦截
LDAP 配置 ldap_configs 独立 CRUD LDAP 认证集成

system_settings 分组概览

分组 配置项数 有效引用 状态
query 查询控制 5 4 ⚠️ query_max_rows_examined 未引用
security 安全策略 5 5 ✅ 全部有效
data_masking 数据脱敏 2 2 ✅ 全部有效
cleanup 日志清理 4 4 ✅ 全部有效
executor 执行器 4 2 ⚠️ batch_size/backup 未引用
ghost 在线 DDL 13 13 ✅ 全部有效
ldap LDAP 9 0 ❌ 全部冗余(LDAP 使用独立 ldap_configs 表)

配置读写 API

操作 端点 说明
读取所有设置 GET /api/v1/settings 按 group 字段分组返回
批量更新设置 PUT /api/v1/settings 接收 [{key, value}, ...] 数组
读取审核规则 GET /api/v1/audit-rules?db_type=mysql 可按 db_type 过滤

配置均在服务启动时通过 seedDefaultSettings() / seedAuditRules() 幂等初始化。


二、查询控制 (query)

查询控制配置作用于在线查询功能(instance_detail.go),限制用户对数据库的查询行为。

Key 类型 默认值 说明 引用位置
query_limit_max number 1000 SELECT 查询返回的最大行数,超过自动截断 instance_detail.go:525
query_timeout number 30 单次查询最长执行时间(秒),超时自动终止 instance_detail.go:616-617
query_auto_limit boolean true 用户未写 LIMIT 时自动追加,防止全表扫描 instance_detail.go:526
query_dangerous_pattern boolean true 检测不带 WHERE 的 DELETE/UPDATE 等高危操作 instance_detail.go:540
query_max_rows_examined number 1000000 单次查询允许扫描的最大行数 ⚠️ 待实现 — 仅 seed 定义

作用机制

query_limit_max — 查询请求中的 limit 参数不能超过此值:

maxLimit := getSettingInt("query_limit_max", 1000)
if input.Limit <= 0 {
    input.Limit = maxLimit
}
// ... 后续截断到 maxLimit

query_auto_limit — 当用户未指定 LIMIT 时,自动追加平台默认上限:

autoLimit := getSetting("query_auto_limit", "true") == "true"

query_timeout — 使用 Go context.WithTimeout 实现硬超时:

timeoutSec := getSettingInt("query_timeout", 30)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSec)*time.Second)

query_dangerous_pattern — 在执行前检测 SQL 中是否包含高危操作关键字:

if getSetting("query_dangerous_pattern", "true") == "true" {
    for _, pat := range []string{"DELETE FROM", "UPDATE ", "DROP ", "TRUNCATE", "ALTER ", "RENAME "} {
        // ... 检测并拦截
    }
}

三、审核规则 (audit_rules)

概述

审核规则存储在 audit_rules 表中,在 工单提交时(CreateTicket)自动触发检查。系统预置 34 条规则,覆盖 MySQL、PostgreSQL、Redis、MongoDB 四种数据库类型。

匹配机制

CreateTicket → 加载 audit_rules WHERE db_type=? AND is_enabled=true
            → 对每条 SQL 语句逐一匹配
            → Pattern 正则匹配  ⟶  value=where_check 时使用字符串检测

正则匹配流程(ticket.go:299-303):

for _, rule := range rules {
    matched, _ := regexp.MatchString(*rule.Pattern, checkStmt)
    if matched { /* 规则命中 */ }
}

WHERE 特殊检测(ticket.go:305-314):

由于 Go 的 RE2 正则引擎不支持负向前瞻(negative lookahead),无法用正则"匹配不含 WHERE 的 DELETE"。因此采用两步检测:

  1. 正则匹配 DELETE FROM / UPDATE ... SET 等基础模式
  2. 若规则 value 字段为 "where_check",则用 strings.Contains(upperSQL, "WHERE") 判断是否包含 WHERE 子句
  3. 包含 WHERE → 跳过(安全);不包含 → 拦截

规则字段说明

字段 类型 说明
name string 规则名称
description text 规则描述
rule_type string 规则类型:DDL / DML / DCL / DQL / performance / security
severity string 严重级别:error / warning / info
db_type string 目标数据库类型:mysql / postgresql / redis / mongodb
pattern text 正则表达式(RE2 语法)
is_enabled boolean 是否启用
message string(500) 命中时的提示消息
value string(255) 处理方式:reject(拦截) / review(需审核) / warn(警告) / where_check(WHERE检测)
code string(50) 规则编码(预留)
config_json text 扩展配置 JSON(预留)

MySQL 审核规则(12 条)

规则名称 类型 严重级别 Pattern Value 说明
禁止 DROP TABLE DDL error (?i)^\s*DROP\s+TABLE reject 防止数据永久丢失
禁止 DROP DATABASE DDL error (?i)^\s*DROP\s+DATABASE reject 禁止删库
禁止 TRUNCATE TABLE DDL error (?i)^\s*TRUNCATE\s+TABLE? reject 请用 DELETE 逐批删除
ALTER TABLE 需审核 DDL warning (?i)^\s*ALTER\s+TABLE review 需审批后执行
禁止 DELETE 无 WHERE DML error (?i)^\s*DELETE\s+FROM?\s+\S+\s*$ reject 必须包含 WHERE 条件
禁止 UPDATE 无 WHERE DML error (?i)^\s*UPDATE\s+\S+\s+SET\s+.*\s*$ reject 必须包含 WHERE 条件
SELECT * 建议 DQL info (?i)^\s*SELECT\s+\*\s+FROM warn 建议明确指定查询字段
INSERT 需指定列 DML warning (?i)^\s*INSERT\s+INTO\s+\S+\s+VALUES review 应明确指定列名
禁止 GRANT ALL DCL error (?i)^\s*GRANT\s+ALL reject 禁止授予全部权限
大表变更警告 performance warning (空 pattern) warn 影响行数大时警告
禁止不带 LIMIT 的 DELETE DML warning (?i)^\s*DELETE\s+FROM\s+\S+\s+WHERE warn 建议添加 LIMIT 分批删除

注意:seed 中 MySQL 预置 12 条,实际按 len(allRules["mysql"]) 计算。上表列出 11 条有明确 pattern 的规则,另含 1 条 "大表变更警告"(无 pattern,作为提示性规则存在)。

PostgreSQL 审核规则(7 条)

规则名称 类型 严重级别 Value 说明
禁止 DROP TABLE DDL error reject 同 MySQL
禁止 DROP DATABASE DDL error reject 同 MySQL
禁止 DELETE 无 WHERE DML error reject 同 MySQL
禁止 UPDATE 无 WHERE DML error reject 同 MySQL
ALTER TABLE 需审核 DDL warning review 同 MySQL
SELECT * 建议 DQL info warn 同 MySQL
禁止 GRANT ALL DCL error reject 同 MySQL

Redis 审核规则(4 条)

规则名称 类型 严重级别 Pattern Value 说明
禁止 FLUSHALL DDL error (?i)^FLUSHALL reject 禁止清空所有数据
禁止 FLUSHDB DDL error (?i)^FLUSHDB reject 清空数据库需审批
禁止 CONFIG security error (?i)^CONFIG\s reject 配置修改需走审批
KEYS 命令警告 performance error (?i)^KEYS\s reject 生产环境禁止 KEYS,请使用 SCAN

MongoDB 审核规则(4 条)

规则名称 类型 严重级别 Pattern Value 说明
禁止 dropDatabase DDL error dropDatabase reject 禁止删除数据库
禁止 drop 集合 DDL error (?i)\.drop\(\) reject 禁止删除集合
remove 需带条件 DML error (?i)remove\(\s*\) reject remove 必须带查询条件
updateMany 需审核 DML warning (?i)updateMany review 批量更新需审批

四、数据脱敏 (data_masking)

数据脱敏功能作用于在线查询返回结果,自动将敏感字段的内容替换为 ***。

Key 类型 默认值 说明 引用位置
data_masking_enabled boolean true 全局脱敏开关 instance_detail.go:1522-1525
data_masking_sensitive_fields string (见下方) 全局敏感字段列表(逗号分隔) instance_detail.go:1531-1534

默认敏感字段列表:

mobile, concat_mobile, email_alias, email, password, ga_key,
private_key, secret, secret_key, key_snow, telephone, username,
real_name, token, two_factor_secret, content, phone

作用机制

applyDataMasking() 函数(instance_detail.go:1520)执行以下逻辑:

  1. 读取 data_masking_enabled,若非 true 则跳过
  2. 读取 data_masking_sensitive_fields,按逗号拆分为字段名列表
  3. 合并实例级别 instance.mask_fields 的字段
  4. 遍历查询结果的每一行每一列,若列名(不区分大小写)匹配敏感字段,则将值替换为 ***

字段匹配方式:列名包含(contains)敏感字段名即匹配,不区分大小写。

优先级:全局敏感字段 ∪ 实例级 mask_fields,两者合并生效。


五、执行器 (executor)

执行器配置控制工单中 SQL 语句的实际执行行为。

Key 类型 默认值 说明 引用位置 状态
executor_timeout number 300 SQL 执行的最大等待时间(秒) ticket.go:725,766 ✅ 有效
executor_dry_run boolean true 执行前先 EXPLAIN 验证 SQL 语法 ticket.go:770 ✅ 有效
executor_batch_size number 100 DML 批量执行时每批的行数 (无) ⚠️ 待实现
executor_backup boolean true DML 执行前自动备份受影响数据 (无) ⚠️ 待实现

作用机制

executor_timeout — 为每个 SQL 语句创建带超时的 context:

// OSC (gh-ost) 路径
execTimeout := getSettingInt("executor_timeout", 300)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(execTimeout)*time.Second)

// 原生执行路径
execTimeout := getSettingInt("executor_timeout", 300)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(execTimeout)*time.Second)

executor_dry_run — 对 DDL 语句执行 EXPLAIN 预检查:

if getSetting("executor_dry_run", "true") == "true" {
    ddlPrefixes := []string{"CREATE", "ALTER", "DROP", "TRUNCATE", "RENAME"}
    // 对每条 DDL 语句执行 EXPLAIN,语法错误则拦截
}

六、Ghost / OSC 在线 DDL (ghost)

Ghost 配置控制 gh-ost 在线 DDL 变更工具的默认参数。共 13 项配置,全部在 ghost.go 的 applyGhostSettings() 函数和 OSC 触发逻辑中引用。

基本设置

Key 类型 默认值 说明 引用位置
ghost_enabled boolean false 启用 gh-ost 在线 DDL 变更工具 ticket.go (OSC 触发判断)
ghost_path string gh-ost gh-ost 二进制文件路径 ghost.go (任务创建)
ghost_default_mode string dry_run 默认执行模式:dry_run(预演) / execute(直接执行) ghost.go (任务创建)
ghost_osc_priority string native_first OSC 优先级策略:native_first / ghost_first / ghost_only ticket.go (OSC 触发判断)
ghost_env_mode string development 环境模式:development / staging / production ghost.go (任务创建)
ghost_cloud_type string self_hosted 部署类型:self_hosted / rds / cloud ghost.go (任务创建)

自动触发

Key 类型 默认值 说明 引用位置
ghost_auto_trigger_rows number 10 表行数超过此阈值(万行)自动推荐使用 OSC ticket.go (大表检测)
ghost_auto_trigger_ddl string ADD COLUMN,MODIFY COLUMN,ADD INDEX 自动触发 OSC 的 DDL 操作类型列表(逗号分隔) ticket.go (DDL 类型匹配)

性能调优

Key 类型 默认值 说明 引用位置
ghost_default_chunk_size number 1000 每次拷贝的行数 ghost.go:387 (applyGhostSettings)
ghost_max_load string Threads_running=25 超过此负载暂停拷贝 ghost.go:391
ghost_critical_load string Threads_running=50 超过此负载立即停止 ghost.go:395
ghost_allow_on_master boolean true 是否允许直接在主库运行 gh-ost ghost.go:403
ghost_max_lag_millis number 1500 从库复制延迟超过此值(ms)暂停拷贝 ghost.go:399

作用机制

自动触发 OSC 流程(ticket.go):

  1. 检查 ghost_enabled 是否启用
  2. 检查 SQL 是否为 ALTER TABLE 类型
  3. 检查 DDL 操作类型是否在 ghost_auto_trigger_ddl 列表中
  4. 检查目标表行数是否超过 ghost_auto_trigger_rows(万)
  5. 根据 ghost_osc_priority 决定使用原生 ALTER 还是 gh-ost

参数注入流程(ghost.go:applyGhostSettings):

func applyGhostSettings(task *ghost.GhOstTask) {
    task.ChunkSize       = getSettingInt("ghost_default_chunk_size", 1000)
    task.MaxLoad         = getSetting("ghost_max_load", "")
    task.CriticalLoad    = getSetting("ghost_critical_load", "")
    task.MaxLagMillis    = getSettingInt("ghost_max_lag_millis", 1500)
    task.AllowOnMaster   = getSetting("ghost_allow_on_master", "true") == "true"
}

七、安全策略 (security)

安全策略配置控制用户登录和认证行为,全部在 auth.go(handler)和 middleware/auth.go 中引用。

Key 类型 默认值 说明 引用位置
login_max_attempts number 5 连续登录失败达到此次数后锁定账号 auth.go:34,365
login_lockout_minutes number 30 账号锁定后的持续时长(分钟) auth.go:35,366
password_min_length number 8 用户密码的最短字符数 auth.go (密码校验)
password_require_complex boolean true 要求密码包含大小写字母、数字和特殊字符 auth.go (密码校验)
session_timeout_hours number 24 JWT Token 有效期(小时) middleware/auth.go:20

作用机制

登录锁定流程(auth.go):

  1. 登录时检查 login_max_attempts 和 login_lockout_minutes
  2. 密码错误时调用 handleFailedLogin(),递增 FailedLoginAttempts
  3. 达到 login_max_attempts 时,设置 LockedUntil = now + lockout_minutes
  4. 账号锁定期间拒绝登录,返回剩余锁定时间

会话超时(middleware/auth.go):

func getSessionTimeoutHours() int {
    // 从 system_settings 读取 session_timeout_hours
    // 用于 JWT Token 的过期时间计算
}

八、日志清理 (cleanup)

清理配置控制各类日志和工单数据的自动保留期限。全部在 ghost.go(清理定时任务)和 main.go(seed)中引用。

Key 类型 默认值 说明 引用位置
ticket_retention_days number 180 超过此天数的已完成/已关闭工单将被清理 ghost.go (清理任务)
audit_log_retention_days number 365 超过此天数的审计日志将被清理 ghost.go (清理任务)
query_history_retention_days number 90 超过此天数的查询历史将被清理 ghost.go (清理任务)
slow_log_retention_days number 180 超过此天数的慢查询日志将被清理 ghost.go (清理任务)

九、LDAP 配置 (ldap)

system_settings 中的 LDAP 配置(⚠️ 冗余)

以下 9 项配置存在于 system_settings 表的 ldap 分组中,但 全部未被业务代码引用。LDAP 功能使用独立的 ldap_configs 表进行管理。

Key 类型 默认值 说明 状态
ldap_host string 8.217.205.92 LDAP 服务器地址 ❌ 冗余
ldap_port string 389 LDAP 端口 ❌ 冗余
ldap_use_ssl boolean false 启用 LDAPS (SSL/TLS) ❌ 冗余
ldap_bind_dn string cn=admin,dc=opsx,dc=vip 管理员 DN ❌ 冗余
ldap_base_dn string dc=opsx,dc=vip Base DN ❌ 冗余
ldap_user_filter string (objectClass=inetOrgPerson) 用户过滤器 ❌ 冗余
ldap_uid_attr string uid UID 属性 ❌ 冗余
ldap_mail_attr string mail 邮箱属性 ❌ 冗余
ldap_cn_attr string cn 显示名属性 ❌ 冗余

ldap_configs 独立表(实际使用)

LDAP 功能通过独立的 ldap_configs 表管理,提供完整的 CRUD 功能:

功能 API 端点 说明
配置 CRUD /api/v1/ldap-configs 增删改查 LDAP 服务器配置
测试连接 /api/v1/ldap-configs/:id/test 验证 LDAP 服务器连通性
OU 管理 /api/v1/ldap-configs/:id/ous 管理 LDAP 组织单元
用户导入 /api/v1/ldap-configs/:id/import 从 LDAP 导入用户到平台

建议:后续版本可清理 system_settings 中 ldap 分组的冗余配置项,避免维护混淆。


十、未引用 / 待实现配置

以下配置项在 seed.go 中定义,但在业务代码中 无实际引用,标注为"待实现":

Key 分组 默认值 预期功能 状态
executor_batch_size executor 100 DML 批量执行时每批的行数 ⚠️ 待实现
executor_backup executor true DML 执行前自动备份受影响数据 ⚠️ 待实现
query_max_rows_examined query 1000000 单次查询允许扫描的最大行数 ⚠️ 待实现
ldap_host ldap 8.217.205.92 LDAP 服务器地址 ❌ 冗余(使用 ldap_configs 表)
ldap_port ldap 389 LDAP 端口 ❌ 冗余
ldap_use_ssl ldap false 启用 LDAPS ❌ 冗余
ldap_bind_dn ldap cn=admin,dc=opsx,dc=vip 管理员 DN ❌ 冗余
ldap_base_dn ldap dc=opsx,dc=vip Base DN ❌ 冗余
ldap_user_filter ldap (objectClass=inetOrgPerson) 用户过滤器 ❌ 冗余
ldap_uid_attr ldap uid UID 属性 ❌ 冗余
ldap_mail_attr ldap mail 邮箱属性 ❌ 冗余
ldap_cn_attr ldap cn 显示名属性 ❌ 冗余

汇总:

  • ⚠️ 待实现:3 项(executor_batch_size、executor_backup、query_max_rows_examined)
  • ❌ 冗余:9 项(ldap 分组全部,LDAP 使用独立 ldap_configs 表)

附录:数据模型

system_settings 表结构

type SystemSetting struct {
    ID           int        `gorm:"primaryKey" json:"id"`
    Key          string     `gorm:"size:100;not null"  json:"key"`          // 唯一配置键
    Value        string     `gorm:"type:text;not null" json:"value"`        // 当前值
    ValueType    string     `gorm:"size:20;not null"  json:"value_type"`   // number / boolean / string
    Group        string     `gorm:"size:50;not null"  json:"group"`        // 分组名
    Label        string     `gorm:"size:100;not null" json:"label"`        // 前端显示名
    Desc         *string    `gorm:"type:text"         json:"description"` // 配置说明
    DefaultValue *string    `gorm:"type:text"         json:"default_value"` // 默认值
    SortOrder    int        `gorm:"not null"          json:"sort_order"` // 组内排序
    UpdatedAt    *time.Time `json:"updated_at"`
}

audit_rules 表结构

type AuditRule struct {
    ID         int       `gorm:"primaryKey"      json:"id"`
    Name       string    `gorm:"size:100;not null" json:"name"`          // 规则名称
    Desc       *string   `gorm:"type:text"        json:"description"`   // 规则描述
    RuleType   string    `gorm:"size:50;not null" json:"rule_type"`     // DDL/DML/DCL/DQL/performance/security
    Severity   *string   `gorm:"size:20"          json:"severity"`      // error/warning/info
    DBType     *string   `gorm:"size:20"          json:"db_type"`       // mysql/postgresql/redis/mongodb
    Pattern    *string   `gorm:"type:text"        json:"pattern"`       // RE2 正则表达式
    IsEnabled  *bool     `                         json:"is_enabled"`   // 是否启用
    Message    string    `gorm:"size:500;not null" json:"message"`      // 命中提示消息
    Value      *string   `gorm:"size:255"         json:"value"`         // reject/review/warn/where_check
    Code       *string   `gorm:"size:50"          json:"code"`          // 规则编码(预留)
    ConfigJSON *string   `gorm:"type:text;column:config_json" json:"config_json"` // 扩展配置(预留)
    CreatedAt  time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
    UpdatedAt  time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}

配置读取辅助函数

// ghost.go — 读取字符串配置
func getSetting(key, fallback string) string {
    var s model.SystemSetting
    if model.DB.Where("`key` = ?", key).Take(&s).Error == nil && s.Value != "" {
        return s.Value
    }
    return fallback
}

// ghost.go — 读取整数配置
func getSettingInt(key string, fallback int) int {
    // 读取字符串并 strconv.Atoi,失败返回 fallback
}

文档维护说明:新增配置项时,需同步更新 seed.go 的 seedDefaultSettings() / seedAuditRules() 函数及本文档。