脚本如何批量清理数据库冗余权限

wen 实用脚本 29

自动化运维的降本增效实战指南

目录导读

  1. 冗余权限的“隐形成本”:为什么必须清理?
  2. 脚本批量清理的核心逻辑:三步搞定权限审计
  3. 实战脚本案例:MySQL/Oracle/PostgreSQL示例
  4. 常见问答:权限清理中的十大坑与解决方案
  5. 自动化+审计+回滚:构建企业级权限治理体系

冗余权限的“隐形成本”:为什么必须清理?

数据库冗余权限指用户或角色拥有不再需要的访问权限(如离职员工、过期临时账户、未使用的表级别权限),据安全机构调查,超过60%的数据泄露与未清理的冗余权限相关,其危害包括:

脚本如何批量清理数据库冗余权限

  • 安全风险:攻击者可利用未删除的旧凭证横向移动,例如2023年某金融企业因遗留DBA权限导致核心库被勒索。
  • 性能开销:MySQL的SHOW GRANTS、Oracle的权限递归检查会消耗CPU,冗余权限每增加10%,查询延迟平均上升3%-5%。
  • 合规审计重灾区:GDPR、等保2.0等法规要求权限必须“最小化且定期审计”。

真实案例:某电商平台有2000+个MySQL用户,其中30%是测试账户,通过批量清理后,数据库CPU使用率下降12%,且通过了一次渗透测试。


脚本批量清理的核心逻辑:三步搞定权限审计

第一步:自动发现冗余权限

通过脚本扫描数据库元数据,识别以下“高危场景”:

  • 用户状态异常last_login超过90天的未使用用户(PostgreSQL的pg_stat_activity)。
  • 权限交叉重复:同一角色被授予了多个相互覆盖的权限(如SELECT + ALL PRIVILEGES)。
  • 过期临时账户:名称含temp_test_等关键词,且account_lockedNO的账户。

第二步:生成清理脚本(非直接执行)

  • 输出SQL文件:生成REVOKE语句并记录到日志,支持--dry-run模式验证。
  • 备份原权限:使用mysqldump --all-databases --events > backup.sql或Oracle的expdp导出元数据。

第三步:分批执行+回滚机制

  • 限速执行:每批处理50个用户,避免锁表或超时。
  • 快照回滚:执行前保存information_schema.USER_PRIVILEGES快照,执行后若发现问题,自动运行逆向GRANT脚本。

实战脚本案例:MySQL/Oracle/PostgreSQL示例

案例1:MySQL批量清理90天未登录用户

#!/bin/bash
# 清理冗余数据库用户权限脚本(适合MySQL 8.0+)
DB_USER="admin"
DB_PASS="your_pass"
DRY_RUN="true"  # 设置为false时真正执行
# 1. 查找未登录用户并生成REVOKE语句
mysql -u$DB_USER -p$DB_PASS -e "
SELECT CONCAT('REVOKE ALL PRIVILEGES, GRANT OPTION FROM ''',user,'''@''',host,''';') as revoke_stmt
FROM mysql.user
WHERE (LAST_LOGIN < NOW() - INTERVAL 90 DAY OR LAST_LOGIN IS NULL)
  AND user NOT IN ('root','mysql.sys','mysql.session')
  AND account_locked = 'N';
" > /tmp/revoke_commands.sql
# 2. 生成备份脚本
mysqldump --all-databases --routines --events --single-transaction > /backup/permissions_$(date +%Y%m%d).sql
# 3. 分批执行(每批10条)
if [ "$DRY_RUN" = "false" ]; then
  sqlplus -s / as sysdba <<EOF
   SPOOL /tmp/revoke_exec.log
   DECLARE
     sql_stmt VARCHAR2(4000);
   BEGIN
     FOR r IN (SELECT revoke_stmt FROM temp_revoke_list WHERE rownum <= 10)
     LOOP
       EXECUTE IMMEDIATE r.revoke_stmt;
     END LOOP;
   END;
   /
   SPOOL OFF
EOF
fi

案例2:Oracle清理无权限但存在的角色

-- 生成清理脚本(仅输出SQL,不执行)
SELECT 'DROP ROLE ' || role || ';' AS drop_role_sql
FROM dba_roles
WHERE role NOT IN (SELECT granted_role FROM dba_role_privs)
  AND role NOT LIKE 'ROLE_%DEFAULT%';
-- 备份当前角色权限
CREATE TABLE backup_role_privs AS SELECT * FROM dba_role_privs;

案例3:PostgreSQL清理重复权限

-- 找出拥有超过表级权限的用户
SELECT u.usename, COUNT(DISTINCT n.nspname || '.' || c.relname) as table_count
FROM pg_user u
JOIN pg_class c ON c.relowner = u.usesysid
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
  AND u.usename NOT IN ('postgres', 'pg_stat_scan')
  AND u.valuntil < NOW()  -- 过期账户
GROUP BY u.usename
HAVING COUNT(DISTINCT c.oid) > 50;  -- 超过50张表的权限视为冗余

常见问答:权限清理中的十大坑与解决方案

Q1:执行REVOKE后导致应用崩溃怎么办?

A:务必使用--dry-run模式先分析影响,生产环境建议:

  1. 先对非核心库执行。
  2. 监控slow_query_log中权限拒绝错误。
  3. 保留回滚脚本,生成GRANT反向SQL存入rollback_sep.sql

Q2:如何区分“测试账户”和“人工误删”?

A:采用“权限标签”策略,在用户备注字段(MySQL的user_attributes)或Oracle的COMMENT中标记purpose=testexpire=2025-01-01,脚本只清理标记为test且过期的账户。

Q3:PostgreSQL的pg_hba.conf中的权限如何清理?

Apg_hba.conf级别权限无法通过SQL直接清理,需要脚本解析配置行,示例:

sed -i '/^host.*test_user/d' /var/lib/pgsql/data/pg_hba.conf  # 删除含test_user的行
pg_ctl reload  # 应用变更

同时生成备份:cp pg_hba.conf pg_hba.conf.$(date +%Y%m%d)

Q4:如何自动化审计频率?

A:集成到CI/CD流程中(如Jenkins+Ansible):

  • 每周一凌晨3点执行扫描脚本,输出HTML报告。
  • 报告包含“待清理列表”、“风险评估”和“自动回滚按钮”。
  • 仅对“高风险”权限(如SUPERDBA)自动发工单审批。

自动化+审计+回滚:构建企业级权限治理体系

推荐架构图(文字描述)

定时任务(Crontab/Scheduler)
  → 扫描脚本(Python+SQL元数据)
    → 输出CSV报告(含风险等级)
      → API通知(企业微信/Slack)
        → 审批后执行Ansible Playbook
          → 执行清理 → 记录日志 → 快照备份

完整脚本封装(Python示例)

import MySQLdb
import datetime
def find_redundant_permissions(db_host, db_user, db_pass):
    conn = MySQLdb.connect(host=db_host, user=db_user, passwd=db_pass, db='mysql')
    cursor = conn.cursor()
    cursor.execute("""
        SELECT user, host, 
               CASE WHEN (SELECT COUNT(*) FROM information_schema.TABLE_PRIVILEGES WHERE GRANTEE = CONCAT("'", user, "'@'", host, "'")) > 100 THEN '冗余'
               ELSE '正常' END as status
        FROM mysql.user
        WHERE account_locked = 'N' AND user NOT IN ('root','mysql.sys')
    """)
    with open(f'permission_audit_{datetime.date.today()}.csv', 'w') as f:
        f.write('User,Host,Status\n')
        for row in cursor.fetchall():
            f.write(f"{row[0]},{row[1]},{row[2]}\n")
    conn.close()
    print("报告生成完毕")

批量清理数据库冗余权限不仅是安全刚需,更是降本增效的利器,通过脚本实现自动化发现、分批执行、快照回滚三要素,可以避免人工误操作,将清理时间从数天缩短到数分钟,记住最佳实践:先审计,后执行;先回滚,后删除,立即部署一次扫描,你可能会发现自己的数据库里藏着50个“幽灵”管理员账户。

抱歉,评论功能暂时关闭!