自动化运维与权限审计实战指南
目录导读
- 安全账户管理的核心痛点
- 脚本获取账户信息的原理与工具选择
- 实战:PowerShell脚本批量提取AD账户与权限
- 实战:Bash脚本抓取Linux本地账户与sudo权限
- 脚本输出数据的安全处理与审计报告生成
- 常见问题问答(Q&A)
- 总结与最佳实践建议
安全账户管理的核心痛点
在企业的IT运维中,安全账户管理指的是对用户账户、服务账户、特权账户的生命周期进行控制,包括创建、授权、禁用、删除以及权限审计,传统方式依赖管理员手动登录每台服务器或域控制器,效率低且容易遗漏。

三大痛点:
- 账户数量爆炸:一台Windows域控可能管理数千个账户,手动检查不现实。
- 权限滥用风险:离职员工账户、僵尸服务账户、本地管理员组中的未知成员,都是安全盲区。
- 合规要求:等保2.0、ISO 27001、SOX等标准要求定期审计账户权限,脚本化是必然选择。
核心问题:怎么用脚本获取账户列表、鉴别长期未登录账户、提取特权组成员?下文将拆解具体实现。
脚本获取账户信息的原理与工具选择
1 基本原理
- Windows环境:通过Active Directory域服务(AD)或本地SAM数据库,脚本使用LDAP查询、PowerShell的ActiveDirectory模块、WMI或Net用户命令。
- Linux环境:从
/etc/passwd、/etc/shadow、/etc/group文件读取,或使用getent命令,审计/etc/sudoers获得特权级别。 - 云环境(AWS IAM、Azure AD、华为云IAM):通过各平台API(如AWS CLI、Azure CLI)提取用户列表和权限绑定。
2 脚本工具选型
| 环境 | 推荐脚本语言 | 核心命令/模块 |
|---|---|---|
| Windows AD | PowerShell | Get-ADUser,Get-ADGroupMember |
| Windows本地 | PowerShell/WMI | Get-LocalUser,Get-LocalGroupMember |
| Linux | Bash/Ansible | getent passwd,grep /etc/sudoers |
| 混合环境 | Python+Paramiko | paramiko.SSHClient,subprocess |
选择依据:纯Windows环境首推PowerShell,Linux运维用Bash或Python,混合环境用Ansible playbook或Python脚本统一调度。
实战:PowerShell脚本批量提取AD账户与权限
1 脚本功能设计
我们需要:提取所有域用户(包括禁用账户)→ 提取其所属组 → 标记最近登录时间 >90天的待清理账户 → 输出CSV报表。
2 核心代码(可直接拷贝执行)
# 需要预先加载ActiveDirectory模块
Import-Module ActiveDirectory
# 获取所有域用户基本信息,筛选关键字段
$users = Get-ADUser -Filter * -Properties Name,SamAccountName,Enabled,LastLogonDate,PasswordLastSet,MemberOf,PasswordNeverExpires
# 循环处理:提取每人的组列表(分为特权组与普通组)
$report = @()
foreach ($user in $users) {
$groups = $user.MemberOf
$isPrivileged = $false
$privilegeGroups = @()
# 定义常见特权组关键字
$adminGroups = "Domain Admins","Enterprise Admins","Schema Admins","Administrators"
foreach ($groupDN in $groups) {
$groupName = ($groupDN -split ",",2)[0] -replace "CN=",""
if ($adminGroups -contains $groupName) {
$isPrivileged = $true
$privilegeGroups += $groupName
}
}
# 标记长期未登录(超过90天)
$daysSinceLastLogon = if ($user.LastLogonDate) { (Get-Date) - $user.LastLogonDate | Select -ExpandProperty Days } else { 9999 }
$status = if ($daysSinceLastLogon -gt 90) { "Warning-LongUnused" } else { "Normal" }
$report += [PSCustomObject]@{
SamAccountName = $user.SamAccountName
Enabled = $user.Enabled
LastLogonDays = $daysSinceLastLogon
IsPrivileged = $isPrivileged
PrivilegeGroup = ($privilegeGroups -join "; ")
PassNeverExpires = $user.PasswordNeverExpires
Status = $status
}
}
# 导出到CSV
$report | Export-Csv -Path "C:\Audit\AD_Account_Audit_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation
Write-Host "报告已生成:C:\Audit\AD_Account_Audit_$(Get-Date -Format yyyyMMdd).csv" -ForegroundColor Green
3 输出示例
| SamAccountName | Enabled | LastLogonDays | IsPrivileged | PrivilegeGroup | Status |
|---|---|---|---|---|---|
| zhangsan | True | 2 | False | Normal | |
| li_admin | True | 1 | True | Domain Admins | Normal |
| old_account | False | 125 | False | Warning-LongUnused |
关键输出:管理员可直接从报告中找出“Enabled=False”的僵尸账户,以及“IsPrivileged=True”的高危权限账户。
实战:Bash脚本抓取Linux本地账户与sudo权限
1 脚本设计思路
Linux下的安全审计难点在sudo权限的隐秘性,很多普通用户拥有/etc/sudoers中隐藏的提权规则(如%wheel ALL=(ALL) NOPASSWD: ALL),脚本需要解析sudoers文件并关联用户。
2 核心代码
#!/bin/bash
# 文件名:linux_account_audit.sh
# 功能:提取所有本地用户、UID、主组、最后登录时间、是否可使用sudo并输出为CSV
echo "SamAccountName,UID,PrimaryGroup,LastLoginDays,SudoAccess,ShellPath" > /tmp/linux_accounts_$(date +%Y%m%d).csv
# 遍历所有用户(排除系统UID小于1000的和nobody)
for user in $(getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {print $1}'); do
uid=$(id -u "$user")
primary_group=$(id -gn "$user")
shell=$(getent passwd "$user" | cut -d: -f7)
# 获取最后登录时间(lastlog命令)
last_login=$(lastlog -u "$user" 2>/dev/null | tail -1 | awk '{print $4, $5, $6}')
if [[ -z "$last_login" || "$last_login" == "**Never logged in**" ]]; then
days_since_login=9999
else
last_epoch=$(date -d "$last_login" +%s)
current_epoch=$(date +%s)
days_since_login=$(( (current_epoch - last_epoch) / 86400 ))
fi
# 检查是否拥有sudo权限
sudo_access="False"
# 检查用户是否直接出现在sudoers中
if sudo -l -U "$user" 2>/dev/null | grep -q "may run the following commands"; then
sudo_access="True"
# 检查用户是否在sudoers的组中(如%wheel、%sudo)
elif grep -E "^%[^ ]+.*ALL.*" /etc/sudoers | grep -q "$(id -ng "$user")"; then
sudo_access="True"
fi
echo "$user,$uid,$primary_group,$days_since_login,$sudo_access,$shell" >> /tmp/linux_accounts_$(date +%Y%m%d).csv
done
echo "Linux账户审计报告已生成:/tmp/linux_accounts_$(date +%Y%m%d).csv"
3 脚本优化点
- 使用
lastlog替代w或who:lastlog能显示Never logged in(从未登录)的账户,这是清理孤儿账户的关键指标。 - sudo权限检测:
sudo -l -U直接查询用户的实际sudo权限,比单纯解析/etc/sudoers更准确(因为/etc/sudoers.d/目录下还有碎片规则)。 - 跳过系统用户:只审计UID>=1000的普通用户和UID>=65534的nobody用户,避免产生大量噪音。
脚本输出数据的安全处理与审计报告生成
1 数据安全防护
脚本获取的账户信息属于敏感数据,必须遵循最低权限原则:
- 存储:导出的CSV文件设置
600权限(Linux)或限制NTFS ACL(Windows)。 - 传输:若需将报告发送给安全团队,使用加密通道(SFTP、加密邮件附件)。
- 清理:脚本运行后立即删除临时中间文件,并在报告文件名中加入时间戳以便追溯。
2 自动报告生成(Python示例)
import pandas as pd
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 读取上月生成的CSV
df = pd.read_csv("/tmp/linux_accounts_20231001.csv")
# 提取高风险账户:sudo权限 + 超过90天未登录
high_risk = df[(df['SudoAccess'] == 'True') & (df['LastLoginDays'] > 90)]
# 生成HTML格式报告
html_report = high_risk.to_html()
message = MIMEMultipart()
message["Subject"] = "Linux账户安全审计报告 - 高风险账户需立即处理"
message.attach(MIMEText(html_report, "html"))
# 发送给安全管理员
with smtplib.SMTP("mail.company.com") as server:
server.send_message(message)
合规价值:通过脚本自动化,从获取数据到发送报告全流程无需人工干预,满足等保2.0中的“定期自动审计”要求。
常见问题问答(Q&A)
Q1:脚本执行时需要管理员权限吗?
- A:是的,PowerShell脚本获取AD信息需要域管理员或委派权限;Linux脚本读取
/etc/shadow和sudo -l需要root权限,建议使用具有最小必要权限的服务账户运行,并在脚本开头添加#Requires -RunAsAdministrator(Windows)或检测$EUID是否为0(Linux)。
Q2:如果域控制器有多个站点,脚本如何覆盖所有域用户?
- A:
Get-ADUser -Filter *默认从当前登录的域控制器查询,会自动复制全域数据,若需要指定某站点,可加-Server "dc01.site1.company.com"参数。
Q3:Linux服务器数量众多,如何批量执行并汇总结果?
- A:推荐使用Ansible的
ad_hoc命令:ansible all -m script -a "/path/to/linux_account_audit.sh"
或使用
ansible.builtin.fetch模块将每台服务器的CSV拉到控制节点,再用Python合并。
Q4:脚本是否会泄露账户密码?
- A:不会,脚本仅提取账户元数据(名称、组、登录时间等),不接触哈希或明文密码,Linux的
/etc/shadow虽然被读取,但只用于判断账户是否禁用及最后一次修改时间,不输出哈希内容,安全审计的黄金法则是:永远不在报告中包含密码字段。
Q5:非英文系统(中文)下脚本是否兼容?
- A:若AD或Linux系统使用中文字段名,PowerShell脚本中应使用
Name、SamAccountName等内部字段名(与语言无关),CSV输出时通过ConvertTo-Csv可处理中文,Linux脚本的lastlog输出中日期格式可能依赖locale,建议在脚本头加export LANG=en_US.UTF-8确保一致格式。
总结与最佳实践建议
本文详细阐述了怎么用脚本获取安全账户管理的核心方法,覆盖Windows AD、Linux本地账户以及混合场景,通过自动化脚本,运维人员可以:
- 每周自动扫描所有账户,输出“特权用户清单”和“长期未登录清单”。
- 与CMDB系统联动,发现未注册的服务账户(如:sqlsvc、backupuser)。
- 建立“时间线”:对比不同时段的报告,发现新增/删除账户。
最佳实践总结:
- 分层审计:先扫所有账户,再聚焦特权账户,最后人工复核。
- 持续自动化:将脚本放入计划任务(Windows Task Scheduler)或cron,设置每周一凌晨执行。
- 事件联动:当脚本检测到新账户被加入Domain Admins组时,立即触发告警(如发送到企业微信、钉钉)。
- 版本控制:脚本本身也需纳入Git管理,确保审计行为可追溯。
重点提醒:安全账户管理不是一次性的项目,而是持续的过程,脚本只是工具,配合严格的流程(如:申请-审批-回收)才能真正提升安全水位,从今天起,用脚本替代手工,让安全审计成为每周的自动化例行任务。