万里侯头像
关注

RBAC权限治理的一年复盘:从root账号泛滥到基于属性的细粒度访问控制的渐进式安全改造

RBAC权限治理的一年复盘:从root账号泛滥到基于属性的细粒度访问控制的渐进式安全改造

一、起点:一份令人触目惊心的权限审计报告

2024年5月,在一次常规的安全合规审计中,我拿到了一份内部权限使用情况的统计报告。数据的糟糕程度超出了预期——公司200人规模的技术团队中,拥有生产环境root权限的账号竟然多达47个。更令人不安的是,其中11个账号在过去6个月内没有任何登录记录(离职未收回),8个账号属于早已不从事运维工作的开发人员(历史遗留),还有3个共享账号被多人同时使用。

这种权限管理的混乱状态在行业中并非个例。企业在初创阶段追求效率,往往采用"最小管理成本"的权限策略——给关键人员root权限,遇到权限问题时直接sudo su解决。这种模式的危害是隐蔽的、累积的,直到某次安全事故才会集中爆发。我们看到过太多因为权限管理疏漏导致的删库跑路、配置误操作、数据泄露的行业案例,而我们要做的就是在悲剧发生前把这道门关好。

关键发现汇总

风险类别数量严重程度主要问题
生产环境root账号47个严重无法追溯操作人,无审计日志
离职未回收账号11个高危账号仍然可以SSH登录生产服务器
共享账号8组高危多人共用同一账号,操作无法归属
权限过大(读业务也配写权限)63个中等最小权限原则未被遵守
无审计无日志全量严重无法追查历史操作

二、渐进式安全改造的四个阶段

面对如此复杂的权限治理问题,采用"一刀切"式的强制改造方案(例如直接回收所有root权限)无异于自杀——业务系统会因权限不足而大面积中断。必须设计一套有节奏的渐进式方案,在各个阶段之间设置安全缓冲和回滚机制。

阶段一:权限盘点与可视化(第1-2月)

在这个阶段,我们没有动任何权限配置,核心工作是摸清家底。具体执行了以下操作:

  1. 全量权限扫描脚本:编写了Python脚本,通过SSH批量登录200+台服务器,收集/etc/passwd/etc/sudoers/etc/group及各应用的权限配置(Kubernetes RBAC、MySQL GRANT、Redis ACL),生成统一的权限清单
  2. 权限关系图谱:使用Neo4j图数据库存储"用户-角色-资源-操作"四元组关系,支持按用户("张三能做什么")、按资源("谁能访问生产数据库")、按角色("所有DBA拥有的权限")三个维度进行查询
  3. 风险分级:根据权限范围、涉及数据类型、历史操作频率三个维度,对每个权限条目打分,生成红(需立即处理)、黄(需关注)、绿(正常)三级预警
#!/usr/bin/env python3
"""Kubernetes RBAC权限扫描与风险分析脚本"""
import json
import subprocess
from typing import List, Dict, Any
from datetime import datetime, timedelta

def scan_cluster_roles(kubeconfig_path: str) -> List[Dict[str, Any]]:
    """扫描集群中所有的ClusterRole和Role绑定关系"""
    try:
        result = subprocess.run(
            ["kubectl", "get", "clusterrolebindings,rolebindings", 
             "-A", "-o", "json", f"--kubeconfig={kubeconfig_path}"],
            capture_output=True, text=True, timeout=30
        )
        if result.returncode != 0:
            print(f"kubectl命令执行失败: {result.stderr}")
            return []
        
        bindings = json.loads(result.stdout)
        risky_items = []
        
        for item in bindings.get("items", []):
            role_ref = item.get("roleRef", {})
            
            # 检查是否绑定了cluster-admin
            if role_ref.get("name") == "cluster-admin":
                # 检查使用频率
                last_used = item.get("metadata", {}).get("annotations", {}).get(
                    "rbac.authorization.k8s.io/last-used", ""
                )
                
                subject_list = item.get("subjects", [])
                for subject in subject_list:
                    risk_item = {
                        "binding_name": item.get("metadata", {}).get("name"),
                        "namespace": item.get("metadata", {}).get("namespace"),
                        "subject": f"{subject.get('kind')}:{subject.get('name')}",
                        "role": "cluster-admin",
                        "risk_level": "高危",
                        "last_used": last_used if last_used else "未知"
                    }
                    
                    # 如果超过90天未使用,标记为僵尸账号
                    if last_used:
                        last_date = datetime.strptime(last_used[:10], "%Y-%m-%d")
                        if (datetime.now() - last_date) > timedelta(days=90):
                            risk_item["risk_level"] = "严重"
                            risk_item["issue"] = "权限已超过90天未使用,疑似僵尸订阅"
                    
                    risky_items.append(risk_item)
        
        return risky_items
    
    except subprocess.TimeoutExpired:
        print("kubectl命令执行超时(30秒)")
        return []
    except json.JSONDecodeError as e:
        print(f"JSON解析失败: {e}")
        return []
    except Exception as e:
        print(f"扫描异常: {e}")
        return []

def evaluate_risk_score(binding: Dict[str, Any]) -> int:
    """计算权限风险评分,0-100分,越高越危险"""
    score = 0
    role = binding.get("role", "")
    
    # 高权限角色加分
    if "cluster-admin" in role:
        score += 40
    elif "admin" in role.lower():
        score += 25
    elif "edit" in role.lower():
        score += 15
    
    # 僵尸订阅加分
    if binding.get("risk_level") == "严重":
        score += 30
    
    # 共享账号加分
    if "shared" in binding.get("subject", "").lower():
        score += 20
    
    return min(score, 100)

阶段二:权限收敛与审批流程(第3-5月)

摸清家底后,进入手术阶段。这个阶段的操作需要极其谨慎,每个权限的变更都需要经过审批、灰度、验证、回滚四个步骤。

僵尸账号清理:对11个离职未回收账号和8组共享账号,采取了"先通知后回收"的策略。提前一周邮件通知账号关联的团队负责人,确认无异议后执行回收。遇到的一个坑:某个标记为"离职"的开发人员的账号实际上被CI/CD系统用于自动部署,直接回收导致一次持续15分钟的部署中断。教训是:回收前必须做使用痕迹分析,这里的审计日志体现出了价值。

权限审批流程集成:在内部工单系统中增加了权限申请审批流。申请者提交所需权限后,系统自动进行权限最小化分析——需要的权限范围(namespace级别、资源类型、操作类型)与已有角色匹配,推荐最小权限的角色组合。审批通过后通过Argo Workflow自动执行权限配置脚本,30分钟后自动发送权限验证报告。

临时权限自动回收:这是一个重要创新。有些运维操作需要短期提权(如数据库结构变更需要ALTER权限),但长期持有这些权限就是安全隐患。我们基于JIT(Just-In-Time)原则设计了临时权限机制:所有提权申请默认设置24小时过期时间(可申请延长),到时间自动回收。在MySQL层面,使用ProxySQL的查询规则实现了动态权限管理;在Kubernetes层面,通过CronJob每5分钟扫描临时RoleBinding并清理过期的。

阶段三:ABAC细粒度改造(第6-9月)

传统RBAC的粒度到"角色"层面就止步了,但在生产环境实践中,同一角色的不同用户可能需要不同的权限边界。例如:同样是DBA角色,华东团队的DBA只能操作华东Region的数据库实例。这种基于属性的细粒度控制正是ABAC(Attribute-Based Access Control)的用武之地。

选择了Open Policy Agent(OPA)作为策略引擎,原因:CNCF毕业项目、Rego语言表达能力强、Kubernetes原生集成、支持Sidecar模式低延迟策略决策。改造的核心工作包括:

  1. 属性模型设计:定义四维属性空间——用户属性(部门、职级、团队)、资源属性(环境、Region、应用名、数据分类)、操作属性(读/写/删除/管理)、环境属性(时间窗口、来源IP、操作路径)

  2. 策略编写与测试:使用Rego语言编写了120+条策略规则,每条策略都有对应的单元测试。策略变更走Git PR→Code Review→OPA Test→灰度发布的标准流程

  3. 策略性能优化:OPA的策略评估时间需要控制在微秒级。关键优化手段:规则索引预编译、部分评估(Partial Evaluation)缓存、使用some语句替代所有遍历

# OPA Rego策略示例:限制数据库管理员只能操作指定Region的实例
package database.access

import future.keywords.if
import future.keywords.in

# 默认拒绝
default allow = false

# 允许的条件:用户角色匹配 + Region匹配 + 操作类型合规
allow if {
    # 提取用户信息
    user_role := input.user.attributes.role
    user_region := input.user.attributes.region
    
    # 提取请求信息
    target_resource := input.resource
    target_region := target_resource.labels.region
    target_operation := input.operation
    
    # 角色检查:必须是DBA或SRE
    user_role in {"dba", "sre"}
    
    # Region匹配:用户只能操作自己所属Region的数据库
    user_region == target_region
    
    # 操作级别限制:ALTER/CREATE/DROP需要额外审批标记
    target_operation_type := target_operation.type
    
    # 高危操作需要审批通过标记
    target_operation_type in {"SELECT", "INSERT", "UPDATE", "DELETE"} 
    or input.approval.id != ""
}

阶段四:常态化运营与审计(第10-12月)

治理的终点不是项目上线,而是制度化运营。建立以下机制:

  • 全链路审计日志:所有权限变更、提权操作、审批记录全部记录在ELK中,保留至少1年
  • 异常行为检测:基于历史行为基线检测异常权限使用,如凌晨2点突然使用root权限、单用户短时间内大量资源访问
  • 季度权限复核:每季度由安全团队牵头进行权限全量复核,确认所有权限的必要性和时效性
  • 合规报告:自动生成SOC2、ISO27001等合规框架要求的权限管理报告

三、改造中的数据与效果

一年治理的全景数据:

指标治理前治理后改进
生产root账号数475(全部绑定MFA+审计)-89.4%
僵尸/无效账号200-100%
共享账号8组0组-100%
权限审批覆盖率0%100%+100%
操作可追溯率<10%100%+90pp
最小权限合规率23%91%+68pp
临时权限占比0%67%(按需提权)
安全事件(权限相关)3次/半年0次/半年-100%

四、过程中的冲突与解决

权限治理本质上是一场权力再分配,不可避免地会遇到阻力。最常见的三类冲突:

开发团队的抵触:"以前我都能直接登服务器看日志,现在还要申请,太麻烦了。"——解决方案是提供自助式的日志查询平台,无需登录服务器即可查看日志,从根本上消除了直接登录的动机。

运维效率下降的担忧:"紧急故障的时候还要走审批流程?"——为此专门设计了一条紧急通道:紧急故障期间,值班负责人审批后直接放行(事后补详细操作报告),审批响应时限为5分钟内。实际上线后,平均紧急审批响应时间为2.3分钟。

老员工的"特权惯性":一些资深运维工程师已经习惯拥有全面权限,对新的ABAC策略有抵触。处理方式是逐个沟通、解释安全必要性,同时赋予他们"审批委员"的角色,将他们纳入治理体系而非对立面。

五、总结

一年权限治理的经验浓缩为三点:

  1. 权限治理是技术问题,更是组织行为学问题。技术方案再完善,如果得不到团队的配合和认同,就无法真正落地。在方案设计阶段就需要考虑用户体验和操作效率,让安全策略成为"助推"而非"障碍"。

  2. 最小权限原则的践行需要基础设施支撑。不是不想做最小权限,而是缺乏工具来定义"什么是够用的权限"。ABAC+OPA的组合提供了足够灵活的权限建模能力,让最小权限从理念变成可执行策略。

  3. 治理永无止境,需要常态化运营。权限治理没有"做完"的一天。随着业务发展、人员流动、架构演进,权限体系需要持续迭代。建立自动化的审计和检测机制,比依赖人工的定期Review更可靠。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qwe0iop0/article/details/163175765

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--