AD域建设管理(二)|python3+ldap3管理AD域实践(批量创建OU、用户、修改密码、更新OU和用户)
AD域建设管理(二)| python3+ldap3管理AD域实践(批量创建OU、用户、改密码、更新OU与用户)
-
- 1.使用前提
-
- 1.1.关于程序运行环境
- 1.2.关于AD域的准备和配置
- 2.问题和解决方案
-
- 2.1.安全考虑——防止对象被意外删除
- 2.2.安全考虑——修改用户密码
-
- 2.2.1.最初的探究
- 2.2.2.如何修改密码?
- 2.2.3.pwdLastSet 密码过期相关
- 2.2.4.AD域用户密码策略
- 3.源码及使用说明
-
- 3.1使用案例(待补全)
-
- 3.1.1初始化/更新AD域
- 3.1.2新增用户
最后更新: 2020/8/5
更新说明: 本文只写使用文档和截图说明;源码地址: randolphcyg/ husky_ad ,当发现问题的时候,及时更新提代码;
- AD域建设管理(一)| 安装windows server2019、AD域、AD域证书服务
- AD域建设管理(二)| python3+ldap3管理AD域实践(批量创建OU、用户、改密码、更新OU与用户)
- AD域建设管理(三)| AD域实践(用remoteapp修改初始化密码)
- AD域建设管理(四)| AD域实践(win server2019 RemoteApp前端修改与美化
1.使用前提
1.1.关于程序运行环境
这里是主要的python炸药包及介绍,后面会优化安装方式
项目 | 描述 |
---|---|
python3 | 主要后端开发语言 |
ldap3 | 是一个十分优秀且稳健的对active directory域进行管理的炸药包 |
pandas | 代替python的原生文件读取包,提高处理效率 |
winrm | 用来远程连接windows server执行powershell命令 |
1.2.关于AD域的准备和配置
【注意】本文均启用ssl安全连接AD域,需要先安装AD证书服务;
如果还没来得及安装AD证书服务,需要将程序中use_ssl
参数改成use_ssl=False,但此时建立的ldap连接不可以做修改密码操作(未做判断
);
很多博客讲的是LDAP3的CAUD基本操作,而我作为一个实践过上线了的AD域的实践者,会偏向于总结从无到有的整个经历的过程;
2.问题和解决方案
2.1.安全考虑——防止对象被意外删除
- 位置:
ADSI编辑器
>OU右键属性
>对象
>防止对象被意外删除
- 作用:勾选之后,不可直接将该对象删除,默认不启用
为了保证生产服AD域的组织架构的安全性,需要严格控制OU的是否可以直接被删除的属性;
最初做的时候,是想批量生成多级OU,然后在AD服务器打开powershell执行一下几条命令设置防止对象被意外删除
属性;
后面为了简化操作,使用python的winrm炸药包远程连接AD域服务器并执行powershell命令;
- 启用(勾选):
# 启用ActiveDirectory模块
Import-Module ActiveDirectory
# 查询没有启用对象被意外删除的OU
Get-ADOrganizationalUnit -filter * -Properties ProtectedFromAccidentalDeletion | where {$_.ProtectedFromAccidentalDeletion -eq $false} | ft
# 查询没有启用 对象被意外删除的OU 属性,并设置为启用
Get-ADOrganizationalUnit -filter * -Properties ProtectedFromAccidentalDeletion | where {$_.ProtectedFromAccidentalDeletion -eq $false} |Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $true
这样如果直接对OU删除的话会提示:
同样,用程序也就不能任意的删除OU了;
- 不启用(不勾选):
Import-Module ActiveDirectory
Get-ADOrganizationalUnit -filter * -Properties ProtectedFromAccidentalDeletion | where {$_.ProtectedFromAccidentalDeletion -eq $true} | ft
Get-ADOrganizationalUnit -filter * -Properties ProtectedFromAccidentalDeletion | where {$_.ProtectedFromAccidentalDeletion -eq $true} |Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $false
程序中设计:
传进来的flag用来选择执行那个命令列表flag_map[flag],flag给0 则执行enable_del列表中的命令,不勾选这个属性;
每次修改完OU之后都会给flag传1,勾选此属性;
# powershell命令 用于启用/关闭OU 防止对象被意外删除 属性
# 防止对象被意外删除×
enable_del = ["Import-Module ActiveDirectory",
"Get-ADOrganizationalUnit -filter * -Properties ProtectedFromAccidentalDeletion | where {"
"$_.ProtectedFromAccidentalDeletion -eq $true} |Set-ADOrganizationalUnit "
"-ProtectedFromAccidentalDeletion $false"]
# 防止对象被意外删除√
disable_del = ["Import-Module ActiveDirectory",
"Get-ADOrganizationalUnit -filter * -Properties ProtectedFromAccidentalDeletion | where {"
"$_.ProtectedFromAccidentalDeletion -eq $false} |Set-ADOrganizationalUnit "
"-ProtectedFromAccidentalDeletion $true"]
flag_map = {
0: enable_del, 1: disable_del}
测试案例:
执行ad.ad_update(RAN_EXCEL)
更新AD域,假设AD域还没有组织,没有用户,会自动判断上级OU不存在,会先创建上级几层OU,设置防止对象被意外删除,然后创建用户,保存账号和密码。
- 其他拓展 目前没找到也就没用到
ProtectedFromAccidentalDeletion设置为true的即启用防止对象被意外删除
ProtectedFromAccidentalDeletion设置为false则不启用防止对象被意外删除
2.2.安全考虑——修改用户密码
2.2.1.最初的探究
- 探究发现,在批量创建用户并设置启用用户后,每一个用户的密码默认是空。
这里我修改了5与2密码,都是空
2.2.2.如何修改密码?
最开始,决定用程序初始化/修改用户密码时遇到了问题,对一个测试用户右键查看属性,里面有字段userPassword
,手工赋值后该密码并没有起到作用,通过查询国外文档,找到了原因所在:
- 根据下面文章,我们知道AD域将用户密码存储在
unicodePwd
属性中,而不是userPassword中
,因此,在创建用户的时候,不需要给userPassword
字段赋值; -
unicodePwd
属性不可查询,需要建立ssl安全通道才能进行修改,否则只能在服务器用**Set-ADAccountPassword -Identity 【DN】**修改; -
方案1
这里若域还没有配置安装证书服务,636安全端口不能连接,只能在AD域服务器跑powershell脚本对用户批量设置密码【已实现】 -
方案2
若配置了安装证书服务,则使用self.conn.extend.microsoft.modify_password(dn, new_pwd, old_pwd)
完成对密码的修改/初始化;
Active Directory中的LDAP密码更改
2010年8月26日/ 尼尔·威尔逊我从未真正热衷于Active Directory。Microsoft倾向于将标准更像是建议而不是规则,而Active Directory则提供了一些很好的例子。最近有人问我一个问题,关于如何通过LDAP更改Active Directory中的密码。在大多数目录服务器中,您要么使用LDAP密码修改扩展操作(如RFC 3062中所述),要么执行简单的修改操作以将明文密码替换
userPassword
属性(服务器将自动执行任何操作)。必要的编码来掩盖该值)。但是,Active Directory有许多非常不寻常的要求,因此可能值得一提。它们包括:
- Active Directory似乎不支持密码修改扩展操作,因此您必须使用常规LDAP修改操作来更改密码。
- Active Directory将密码存储在
unicodePwd
属性中,而不是userPassword中
。- Active Directory仅接受通过安全连接的密码更改。我只用过SSL。也许您也可以使用StartTLS或具有机密性的SASL,但是我不确定。
- 新密码必须用引号引起来,并且必须使用UTF-16 little-endian编码。
- Active Directory可能会对密码施加一些强度要求,尽管这些要求的确切含义可能因一个实例而异。
知道了这些要求之后,您应该能够使用允许您在Active Directory中执行密码更改的任何LDAP API编写代码。
2.2.3.pwdLastSet 密码过期相关
参考文章:LDAP pwdlastset unable to change without error showingpwdLastSet
属性查询出来的是时间,但是却不能修改为datetime/timestamp类型,会报错为00000057:SysErr:DSID-031A122C,problem 22(Invalid argument),data0
我在程序中测试的时候,现在AD域修改一个用户的密码,然后查到此属性的值时间戳,而且这个时间戳开始时间是不恰当的,用程序给用户直接修改这个值就会报错,是因为——
仅系统可以将pwdLastSet属性修改为0或-1以外的任何值。如果分配0,则密码立即失效。然后,当用户更改密码时,系统会将当前日期/时间分配给pwdLastSet属性。
值-1对应于64位属性2 ^ 63-1中允许的最大整数。此值取反0。它使密码未过期。当用户下次登录时,系统会将pwdLastSet属性设置为与当前日期/时间相对应的值。
-
说明
:pwdLastSet
给-1
——使得密码不过期;pwdLastSet
给0
——密码立即失效; -
最终方案
:modify_res = self.conn.modify(dn, {'pwdLastSet': (2, [-1])}) # pwdLastSet只能给-1 或 0
2.2.4.AD域用户密码策略
- 位置:
服务器管理器
>工具
>组策略管理
>域的默认策略
>右键编辑
>组策略管理编辑器
>找到密码策略; - 小点:
如果
默认域策略灰禁
不能编辑,去搜一下,忘记了; - 注意根据需要修改密码策略,如果之后都不想让密码过期,只需将密码最长使用期限数值改成0;
3.源码及使用说明
最新版及使用文档优先在源码READ.MD文档中更新
源码地址: RandolphCYG / husky_ad
本文将重点放在生产上遇到的问题和解决策略以及我在本地的实践;
3.1使用案例(待补全)
稍微提一下功能及步骤:
- 从表格读取数据,充分扫描表格数据是否有问题,通过后返回同步AD域用户的元数据
- 开始更新AD域,如果该用户已经在域中切信息未变则忽略/变化则修改、该用户不在域中则新增并将用户密码保存在
pwd.txt
中、然后设置第一次登录必须修改密码 - 前两步骤都是
ad.ad_update(RAN_EXCEL)
一行封装的操作,接下来可选的是——1.扫一下AD域有没有空OU处理下ad.scan_ou()
/ 2.扫一下AD域在表格中不存在的用户判断为离职人员将其禁用并移动到DISABLED_BASE_DN = 'OU=resigned,DC=randolph,DC=com' # 离职账户所在OU
该功能调用方式为ad.disable_users(RAN_EXCEL)
- 其他:ad_update操作在需要从表格更新AD域的时候都可使用、会补充晚上密码过期策略的方案、发送精美邮件及控制发送范围的功能
- 纯新增员工操作需要调用
ad.create_user_by_excel(NEW_RAN_EXCEL)
,NEW_RAN_EXCEL是新员工表格的地址,可以在表格中填写用户(多个),然后执行此功能即可,账号密码会自动在pwd.txt
中新增
拓展任务
:更新AD域后,OU架构可能会因为公司架构而变化,那么手工设置的管控不同OU的admin管理员账户则需要重新检查
3.1.1初始化/更新AD域
必要条件
:用于初始化/更新AD域的表格一定是全量的(包含所有的公司员工);不然之后会将AD域中有的,表格中没有的用户判断为离职员工进行处理;如何使用
:
1.修改基础信息并在main中用ad = AD()
测试AD域连通性,检查info.log中是否出现INFO localAD.py 71 distinguishedName:CN=Administrator,CN=Users,DC=randolph,DC=com res: True
即连接成功的标志
2.解开ad.ad_update(RAN_EXCEL)
一行的注释,执行即可
可以先用一个用户的更新流程做个判断
for循环打个break测试下,后面考虑将各步骤的测试写成一次性的检测机制;
若在info.log
看到有用户创建成功并在pwd.txt
中生成了账号密码,则可将break语句删掉,直接跑代码了;问题
:我发现日志记录的太多了,会让程序运行中花费更多时间在日志记录上,虽然有利于后面的排查与参考,但是会影响执行速度;实验的环境为2000位用户、十几个OU、三四层级OU的更新,附带对AD域服务器远程执行powershell和日志文件和密码文件的读写,耗费时间足足两分钟;【暂时想到优化的方法,将powershell命令修改成每次更新前后执行两次,而不是每位用户的各级OU的修改都会执行两次!】
从日志中可以看到——
AD域连接成功:
最后一位用户创建成功
账号密码文件:
ran_list.xlsx
原始表格是这样的:
用于新增用户的表格文件new_ran_list.xlsx
格式也是一样的:
3.1.2新增用户
需要新增用户的话,这么操作:
效果:
账户密码已经创建成功:
提一下密码规则generate_pwd(count)
函数:count为密码位数,密码为复杂密码——随机密码,必有数字、大小写、特殊字符且数目伪均等;