本文目录导读:

针对自动化脚本清理未使用角色,需根据不同的系统环境(如数据库、云平台、应用系统)采用不同的策略,以下是几种常见场景的自动化清理方案:
数据库(以 PostgreSQL / MySQL 为例)
场景:数据库中存在大量已创建但未被任何用户、API或应用引用的角色/用户。
自动化脚本思路:
# Python 示例:连接数据库并清理未被授权的角色
import psycopg2
import os
def clean_unused_roles(conn):
cursor = conn.cursor()
# 1. 查找没有被授予任何权限的角色(排除系统角色)
cursor.execute("""
SELECT rolname FROM pg_roles
WHERE rolname NOT IN ('postgres', 'pg_signal_backend', 'pg_read_all_data', 'pg_write_all_data')
AND NOT EXISTS (
SELECT 1 FROM pg_auth_members WHERE member = pg_roles.oid
)
AND NOT EXISTS (
SELECT 1 FROM pg_shdepend WHERE refobjid = pg_roles.oid AND deptype = 'a'
)
""")
unused_roles = cursor.fetchall()
# 2. 删除这些角色
for (role_name,) in unused_roles:
cursor.execute(f"DROP ROLE IF EXISTS {role_name}")
print(f"Dropped unused role: {role_name}")
conn.commit()
# 使用方式(需在安全窗口运行)
# clean_unused_roles(connect_db())
适用条件:需要数据库管理员权限,且确认这些角色确实未被任何连接或对象依赖。
AWS IAM 角色清理(云平台)
场景:AWS 账户中积累了未附加到任何服务、实例或用户的角色。
自动化方案(使用 AWS CLI + bash):
#!/bin/bash
# 获取所有IAM角色
aws iam list-roles --query "Roles[?RoleName!='AWSServiceRoleForSupport'].RoleName" --output text | while read role; do
# 检查角色是否附加了任何实例配置文件
instance_profiles=$(aws iam list-instance-profiles-for-role --role-name "$role" --query "InstanceProfiles" --output text 2>/dev/null)
# 检查角色是否被任何服务信任策略引用
trust_policy=$(aws iam get-role --role-name "$role" --query "Role.AssumeRolePolicyDocument" --output json 2>/dev/null)
if [ -z "$instance_profiles" ] && echo "$trust_policy" | grep -q "Service:.*lambda\|Service:.*ec2\|Service:.*ecs"; then
# 等待24小时后再次确认(避免误删)
echo "Role $role might be unused. Skipping automatic deletion."
else
# 删除完全无关联的角色
aws iam delete-role --role-name "$role" 2>/dev/null
echo "Deleted IAM role: $role"
fi
done
关键点:
- 必须同时检查信任关系和附加的实体。
- 建议增加人工确认步骤(如将疑似未使用角色输出到审计日志,超过30天无变化才自动删除)。
应用系统(如 Django 或自建权限系统)
场景:系统中定义了多种角色,但部分角色在数据库的用户表中从未被分配。
自动化清理脚本(Python + SQLAlchemy):
from sqlalchemy import create_engine, text
from datetime import datetime, timedelta
def clean_app_roles(engine, dry_run=True):
with engine.connect() as conn:
# 1. 查找未被任何用户分配的角色
query = text("""
SELECT r.id, r.name
FROM roles r
LEFT JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id IS NULL
AND r.created_at < :threshold
""")
threshold = datetime.utcnow() - timedelta(days=30) # 超过30天未分配的角色
unused_roles = conn.execute(query, {"threshold": threshold}).fetchall()
if dry_run:
print("未使用角色(模拟运行,不会删除):")
for role in unused_roles:
print(f" ID: {role.id}, Name: {role.name}")
else:
for role in unused_roles:
conn.execute(text("DELETE FROM role_permissions WHERE role_id = :rid"), {"rid": role.id})
conn.execute(text("DELETE FROM roles WHERE id = :rid"), {"rid": role.id})
print(f"Deleted role: {role.name}")
conn.commit()
建议:
- 始终提供
dry_run=True参数,先在测试环境验证。 - 记录删除的角色到日志表,以备回滚。
通用安全自动化脚本设计原则
无论是哪种场景,清理未使用角色的脚本都应该包含以下机制:
| 机制 | 说明 |
|---|---|
| 依赖检查 | 确认该角色没有被任何ACL、策略或数据库对象引用 |
| 多重确认 | 分两步执行:第一天标记(设置过期标签),第二天删除(防止误删) |
| 日志记录 | 每次操作写入审计日志,包含角色名、操作时间、执行者 |
| 回滚能力 | 保留被删除角色的权限快照,必要时重建 |
| 黑名单 | 明确禁止删除内置角色(如 postgres、root、admin) |
| 通知机制 | 删除前通知相关系统负责人(通过邮件或SLACK) |
推荐执行策略
最佳实践是采用“两步走”方案:
-
扫描并标记(安全阶段)
- 脚本每天运行,找出“疑似未使用”的角色。
- 将这些角色加入 待清理队列,并发送通知给管理员。
-
延迟删除(确认阶段)
- 等待 7~30 天(根据角色重要程度)。
- 再次验证这些角色仍然未使用。
- 正式执行删除,并记录日志。
示例脚本框架(调度用 crontab 每天运行):
# 每天凌晨的扫描任务
def daily_scan():
unused = find_unused_roles()
for role in unused:
if role.last_seen is None or role.last_seen < (now - 7days):
mark_for_deletion(role)
notify_admin(role)
elif role.is_marked_for_deletion():
if role.marked_time < (now - 7days):
delete_role(role)
- 数据库、云平台、应用系统需要不同的检查逻辑。
- 核心是依赖分析(角色是否被引用)+ 时间缓冲(避免误删)。
- 始终配置 dry_run 模式和日志记录。
- 对于关键系统,更安全的做法是只标记+提示,由人工确认后再触发删除。