关于 acl-management
该技能面向 ServiceNow 管理员和安全人员,指导 ACL 的检查、创建、修改与故障排查。内容涵盖表级、字段级和记录级访问控制,以及角色要求和调试方法。
主要功能
- 01查询 ACL 及其角色要求
- 02创建表级、字段级和记录级 ACL
- 03安全修改现有 ACL
- 04排查用户权限问题
- 05分析 ACL 评估与冲突
- 06检查角色组合风险
适用场景
- 01为新表或应用配置访问控制
- 02调查用户遇到的拒绝访问问题
- 03实施字段级或行级权限
- 04审查现有权限与 ACL 配置
MCP 相关
该技能使用 ServiceNow MCP 工具查询 ACL、创建或更新规则与角色,并运行脚本辅助调试。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ happy-technologies-llc/ happy-platform-skills --skill acl-management安装后在 Claude Code 中输入/acl-management确认已加载。
详细介绍
ACL 管理
概述
访问控制列表(ACL)是 ServiceNow 安全性的基础。本技能涵盖:
- 了解 ACL 结构和继承层级
- 为表、字段和记录创建新的 ACL
- 安全地修改现有 ACL 规则
- 排查权限问题
- ACL 调试技术和工具
- 基于角色的访问控制最佳实践
使用场景:
- 为新表或应用设置安全性
- 排查“拒绝访问”问题
- 实施字段级安全性
- 审计和审查现有权限
- 实施行级安全性(查询条件)
前提条件
- 角色:
security_admin或admin - 访问权限: sys_security_acl、sys_security_acl_role 表
- 知识: 了解 ServiceNow 角色和用户组
- 插件: 核心平台(ACL 为内置功能)
ACL 基础知识
ACL 层级
┌─────────────────┐
│ Table ACL (*) │ ← Broadest
│ incident.* │
└────────┬────────┘
│
┌────────▼────────┐
│ Table.Field │ ← Field-specific
│ incident.state │
└────────┬────────┘
│
┌────────▼────────┐
│ Table.None │ ← Row-level
│ (with script) │
└─────────────────┘ ← Most specific
ACL 操作
| 操作 | 用途 | 常见用法 |
|---|---|---|
read | 查看记录/字段 | 列表、表单显示 |
write | 修改记录/字段 | 表单编辑 |
create | 插入新记录 | 创建新记录 |
delete | 删除记录 | 删除记录 |
execute | 运行脚本/操作 | UI 操作、处理器 |
ACL 评估顺序
- 最具体的规则优先: 字段 ACL > 表 ACL
- 首次匹配: 评估在第一个匹配的 ACL 处停止
- 默认拒绝: 没有匹配的 ACL = 拒绝访问
- 管理员绕过: 管理员角色可绕过大多数 ACL
操作步骤
阶段 1:了解现有 ACL
1.1 查询表的 ACL
查找特定表的所有 ACL:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: nameLIKEincident
fields: name,operation,type,condition,script,active
limit: 50
按操作类型查找 ACL:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: name=incident^operation=write
fields: name,operation,admin_overrides,condition,script,active
limit: 20
1.2 了解 ACL 结构
获取 ACL 表架构:
Tool: SN-Get-Table-Schema
Parameters:
table_name: sys_security_acl
ACL 关键字段:
| 字段 | 类型 | 用途 |
|---|---|---|
name | 字符串 | 表.字段或表.* |
operation | 选项 | read、write、create、delete、execute |
type | 选项 | record、client_callable_script_include |
condition | 条件 | 行级安全性的筛选条件 |
script | 脚本 | 高级条件逻辑 |
admin_overrides | 布尔值 | 允许管理员绕过 |
active | 布尔值 | 是否强制执行 ACL |
advanced | 布尔值 | 是否使用脚本条件 |
1.3 检查 ACL 的角色要求
查找 ACL 所需的角色:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl_role
query: acl.name=incident.*^acl.operation=write
fields: acl.name,acl.operation,role.name
limit: 20
阶段 2:创建新的 ACL
2.1 创建表级 ACL
为自定义表创建读取 ACL:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_custom_table.*"
operation: read
type: record
admin_overrides: true
active: true
description: "Read access to custom table"
添加角色要求:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl_role
data:
acl: [acl_sys_id]
role: [role_sys_id]
2.2 创建字段级 ACL
保护敏感字段:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_custom_table.ssn_number"
operation: read
type: record
admin_overrides: true
active: true
description: "Restrict SSN field to authorized users only"
添加多个角色要求:
Tool: SN-Query-Table
Parameters:
table_name: sys_user_role
query: nameINhr_admin,security_admin
fields: sys_id,name
limit: 10
然后为每个角色执行:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl_role
data:
acl: [field_acl_sys_id]
role: [hr_admin_role_sys_id]
2.3 创建行级 ACL(基于条件)
用户只能查看自己的记录:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_custom_table"
operation: read
type: record
condition: "opened_by=javascript:gs.getUserID()"
admin_overrides: true
active: true
description: "Users can only read their own records"
2.4 创建基于脚本的 ACL
需要脚本的复杂逻辑:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_custom_table"
operation: write
type: record
advanced: true
script: |
// Allow write if user is the owner OR is in the assigned group
var userId = gs.getUserID();
var userGroups = gs.getUser().getMyGroups();
if (current.owner == userId) {
answer = true;
} else if (userGroups.indexOf(current.assignment_group.toString()) >= 0) {
answer = true;
} else {
answer = false;
}
admin_overrides: true
active: true
description: "Allow write for owner or group members"
阶段 3:安全地修改 ACL
3.1 进行重大更改前先停用
暂时停用 ACL:
Tool: SN-Update-Record
Parameters:
table_name: sys_security_acl
sys_id: [acl_sys_id]
data:
active: false
进行更改:
Tool: SN-Update-Record
Parameters:
table_name: sys_security_acl
sys_id: [acl_sys_id]
data:
condition: "state!=6^ORassigned_to=javascript:gs.getUserID()"
description: "Updated condition - users can access non-closed or own records"
测试后重新启用:
Tool: SN-Update-Record
Parameters:
table_name: sys_security_acl
sys_id: [acl_sys_id]
data:
active: true
3.2 添加/移除角色要求
添加新的角色要求:
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl_role
data:
acl: [acl_sys_id]
role: [new_role_sys_id]
移除角色要求:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl_role
query: acl=[acl_sys_id]^role=[role_sys_id]
fields: sys_id
# Then delete the record using SN-Update-Record or background script
阶段 4:排查权限问题
4.1 确定阻止访问的 ACL
启用 ACL 调试(基于会话):
Tool: SN-Execute-Background-Script
Parameters:
script: |
// This enables debug output for the session
// Run manually: Navigate to User menu > Impersonate > Check security
gs.info('To debug ACLs:');
gs.info('1. Navigate to System Security > Debugging');
gs.info('2. Or add ?sysparm_security_debug=true to URL');
gs.info('3. Or impersonate user and check security diagnostics');
description: "ACL debugging instructions"
检查用户的角色:
Tool: SN-Query-Table
Parameters:
table_name: sys_user_has_role
query: user=[user_sys_id]^role.name!=snc_internal
fields: role.name,granted_by,inherited
limit: 50
检查用户的组:
Tool: SN-Query-Table
Parameters:
table_name: sys_user_grmember
query: user=[user_sys_id]
fields: group.name,group.sys_id
limit: 50
4.2 跟踪 ACL 评估
查找适用的 ACL:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var table = 'incident';
var operation = 'write';
var fieldName = 'state'; // or '*' for table-level
var acl = new GlideRecord('sys_security_acl');
acl.addQuery('name', 'CONTAINS', table);
acl.addQuery('operation', operation);
acl.addQuery('active', true);
acl.orderBy('name');
acl.query();
gs.info('ACLs for ' + table + '.' + fieldName + ' (' + operation + '):');
while (acl.next()) {
var roles = [];
var roleGr = new GlideRecord('sys_security_acl_role');
roleGr.addQuery('acl', acl.sys_id);
roleGr.query();
while (roleGr.next()) {
roles.push(roleGr.role.name.toString());
}
gs.info(acl.name + ' - Roles: [' + roles.join(', ') + '] - Condition: ' + acl.condition);
}
description: "Trace ACL evaluation for table/operation"
4.3 测试用户访问权限
检查用户是否拥有所需角色:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var userId = '[user_sys_id]';
var requiredRoles = ['itil', 'incident_manager'];
var user = new GlideRecord('sys_user');
user.get(userId);
gs.info('Checking roles for: ' + user.user_name);
for (var i = 0; i < requiredRoles.length; i++) {
var hasRole = new GlideRecord('sys_user_has_role');
hasRole.addQuery('user', userId);
hasRole.addQuery('role.name', requiredRoles[i]);
hasRole.query();
if (hasRole.hasNext()) {
gs.info(' HAS: ' + requiredRoles[i]);
} else {
gs.warn(' MISSING: ' + requiredRoles[i]);
}
}
description: "Check user role membership"
4.4 常见权限问题
问题:用户可以查看表,但无法查看特定记录
# Check for row-level ACL conditions
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: name=[table_name]^operation=read^conditionISNOTEMPTY
fields: name,condition,script
问题:用户可以读取,但无法写入
# Compare read vs write ACLs
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: nameLIKE[table_name]^operationINread,write
fields: name,operation,condition
limit: 20
问题:字段意外变为只读
# Check field-level ACLs
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: name=[table_name].[field_name]^operation=write
fields: name,operation,condition,active
阶段 5:ACL 调试工具
5.1 安全诊断工具
对记录运行安全诊断:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var table = 'incident';
var sysId = '[record_sys_id]';
var userId = '[user_sys_id]';
// Impersonate and check access
var gr = new GlideRecord(table);
gr.get(sysId);
var canRead = gr.canRead();
var canWrite = gr.canWrite();
var canDelete = gr.canDelete();
gs.info('Security Diagnostic for ' + table + '/' + sysId);
gs.info(' Can Read: ' + canRead);
gs.info(' Can Write: ' + canWrite);
gs.info(' Can Delete: ' + canDelete);
// Check field-level access
var elements = ['state', 'priority', 'assigned_to'];
for (var i = 0; i < elements.length; i++) {
var field = elements[i];
gs.info(' Field ' + field + ' - canRead: ' + gr[field].canRead() +
', canWrite: ' + gr[field].canWrite());
}
description: "Run security diagnostic on record"
5.2 ACL 规则分析器
分析所有 ACL 是否存在冲突:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var table = 'incident';
var analysis = {
table_acls: [],
field_acls: [],
potential_conflicts: []
};
var acl = new GlideRecord('sys_security_acl');
acl.addQuery('name', 'STARTSWITH', table);
acl.addQuery('active', true);
acl.orderBy('name');
acl.query();
while (acl.next()) {
var aclInfo = {
name: acl.name.toString(),
operation: acl.operation.toString(),
has_condition: acl.condition.toString() !== '',
has_script: acl.advanced.toString() === 'true'
};
if (acl.name.toString().indexOf('.') === -1 ||
acl.name.toString().endsWith('.*')) {
analysis.table_acls.push(aclInfo);
} else {
analysis.field_acls.push(aclInfo);
}
}
// Check for potential issues
if (analysis.table_acls.length === 0) {
analysis.potential_conflicts.push('No table-level ACLs - may be too open or rely on inheritance');
}
gs.info('ACL Analysis for ' + table + ':\n' + JSON.stringify(analysis, null, 2));
description: "Analyze ACLs for conflicts and issues"
5.3 角色提升检查
查找可能存在危险角色组合的用户:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var dangerousCombos = [
['admin', 'maint'],
['security_admin', 'personalize_dictionary'],
['admin', 'soap']
];
var findings = [];
for (var i = 0; i < dangerousCombos.length; i++) {
var combo = dangerousCombos[i];
var users = new GlideRecord('sys_user');
users.addQuery('active', true);
users.query();
while (users.next()) {
var hasAll = true;
for (var j = 0; j < combo.length; j++) {
var roleCheck = new GlideRecord('sys_user_has_role');
roleCheck.addQuery('user', users.sys_id);
roleCheck.addQuery('role.name', combo[j]);
roleCheck.query();
if (!roleCheck.hasNext()) {
hasAll = false;
break;
}
}
if (hasAll) {
findings.push({
user: users.user_name.toString(),
roles: combo
});
}
}
}
if (findings.length > 0) {
gs.warn('Users with dangerous role combinations:');
gs.info(JSON.stringify(findings, null, 2));
} else {
gs.info('No dangerous role combinations found');
}
description: "Find users with dangerous role combinations"
最佳实践
设计原则
- 最小权限原则: 仅授予所需的最低访问权限
- 基于角色的访问: 使用角色,而非单个用户
- 尽可能继承: 使用表级 ACL 作为基准
- 记录一切: 为所有 ACL 添加说明
- 彻底测试: 使用多个用户角色进行验证
常见模式
模式 1:所有者 + 群组访问
// Condition for owner or group member access
opened_by=javascript:gs.getUserID()^ORassignment_group.memberSOME=javascript:gs.getUserID()
模式 2:分层访问
// Managers can see their team's records
var mgr = new GlideRecord('sys_user');
mgr.addQuery('manager', gs.getUserID());
mgr.query();
var users = [gs.getUserID()];
while (mgr.next()) users.push(mgr.sys_id.toString());
answer = gs.getUser().getID() in users.join(',').split(',');
模式 3:基于时间的访问
// Only allow access during business hours
var now = new GlideDateTime();
var hour = now.getLocalTime().getHourOfDay();
answer = (hour >= 8 && hour < 18);
工具使用摘要
| 操作 | MCP 工具 | REST 端点 |
|---|---|---|
| 查询 ACL | SN-Query-Table | GET /sys_security_acl |
| 创建 ACL | SN-Create-Record | POST /sys_security_acl |
| 更新 ACL | SN-Update-Record | PATCH /sys_security_acl |
| 添加角色 | SN-Create-Record | POST /sys_security_acl_role |
| 调试 ACL | SN-Execute-Background-Script | 通过 sys_trigger |
| 检查架构 | SN-Get-Table-Schema | GET /sys_dictionary |
故障排除
ACL 未被评估
症状: ACL 更改没有效果 原因: ACL 缓存未清除,或 ACL 未启用 解决方案:
Tool: SN-Execute-Background-Script
Parameters:
script: |
// Clear ACL cache
GlideAccessControl.reset();
gs.info('ACL cache cleared');
description: "Clear ACL cache"
管理员无法访问记录
症状: 管理员角色被阻止访问记录 原因: ACL 设置了 admin_overrides=false 解决方案:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: name=[table]^admin_overrides=false
fields: name,operation,admin_overrides
脚本 ACL 始终失败
症状: 基于脚本的 ACL 从不授予访问权限 原因: 脚本出错或 answer 变量不正确 解决方案:
- 确认脚本设置了
answer = true或answer = false - 检查 syslog 中的脚本错误
- 确保设置了
advanced = true
角色未授予访问权限
症状: 用户拥有角色,但仍被拒绝访问 原因: ACL 要求多个角色(AND),或条件不满足 解决方案:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl_role
query: acl=[acl_sys_id]
fields: role.name
默认情况下,必须具备列出的所有角色(AND 逻辑)。
示例
示例 1:保护自定义表
# Step 1: Create table-level read ACL
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_employee_data.*"
operation: read
type: record
admin_overrides: true
active: true
description: "Base read access to employee data"
# Step 2: Add role requirement
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl_role
data:
acl: [step1_sys_id]
role: [hr_user_role_sys_id]
# Step 3: Create write ACL (more restrictive)
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_employee_data.*"
operation: write
type: record
admin_overrides: true
active: true
description: "Write access to employee data - HR admins only"
# Step 4: Add admin role requirement
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl_role
data:
acl: [step3_sys_id]
role: [hr_admin_role_sys_id]
示例 2:字段级 SSN 保护
# Protect SSN field - only security cleared users
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl
data:
name: "u_employee_data.ssn"
operation: read
type: record
admin_overrides: false
active: true
description: "SSN access restricted - security clearance required"
# Add special role
Tool: SN-Create-Record
Parameters:
table_name: sys_security_acl_role
data:
acl: [ssn_acl_sys_id]
role: [security_cleared_role_sys_id]
相关技能
security/audit-compliance- 审计 ACL 更改security/incident-response- 响应访问违规security/data-classification- 确定需要保护的内容admin/user-provisioning- 管理用户角色