背景
由于公司安全需求,希望用户连接开发用VM时候可以多一道MFA,同时也希望可以记录用户连接开发VM的log,以便出现问题时追查。因为开发VM基本都是Windows系统,走的RDP协议,并且公司也拥有Entra(原名AAD),RD Gateway作为Windows Server自带的配套服务自然成为了免费的不二之选(我们可以实现Duo MFA甚至买Citrix,但是得加钱),搭配NPS更可以做到利用Entra做MFA,实现Microsoft Authenticator弹窗认证。
RD Gateway的安装
RD Gateway的安装非常简单,在服务器管理器内添加功能就行,这里不赘述。比较特殊的是由于预估会有300多个并发session,所以想做负载均衡,但是在网上搜索都说需要做一个RD Connection broker。经过大量搜索后,我个人推测broker更倾向于针对Session host,而非Gateway,并且broker的搭建非常麻烦(我找到的教程甚至要我搭建一个SQL Server……),鉴于时间非常紧,只有两天时间,所以果断放弃broker,转而寻找其他方法实现负载均衡。
这里补充一下Session host和Gateway的区别,Session host本质上是一个打开了Remote Desktop Service的Windows环境,这个功能开启后会允许两个以上的用户连入这个Windows,broker可以确保用户在断开连接后再连回去的时候还可以连接回原本的Session,Gateway是为用户提供从外网安全连接到RD的环境。因为我们的开发VM是一个用户一台专用VM,所以用不上broker的功能,自然不必搭建。虽然我们是内网环境连接VM,但是RDG搭配NPS可以做到MFA,所以选择此方案。
RD Gateway的配置
RD Gateway的配置也相当简单,这里我贴上微软官方的配置文档,这个文档不仅包括了一部分RDG的配置,也包含了NPS连接Entra的配置:https://learn.microsoft.com/zh-cn/entra/identity/authentication/howto-mfa-nps-extension-rdg
给RDG安装好证书,需要给RDG添加一个Resource Authorization Policy才能让用户连接,这里直接按需添加规则和用户组就行
其次是在RDG的属性里面为Transport指定好本机IP
随后将RDG修改为使用远程NPS并且配置好NPS的认证规则,这个参考微软官方文档就可以了。值得一提的是,除了远程NPS服务器外,RDG服务器在安装RDG服务时也会附带安装NPS,配置时一定要分清RDG上的NPS和远程NPS的区别,总体思路为让RDG把自己的NPS请求全部转发到远程NPS上。
微软的灾难级BUG
按理来说,到这里了,RDG应该会直接好用了,但是经过测试,mstsc配置好RDG后,虽然可以正常弹出RDG验证账户密码的部分,但是输入完以后登录会直接报错0x3000008,更诡异的是,RDG和NPS服务器上竟然都没有出现任何日志,注意,是任何日志。能连接也能ping到RDG,但是连接居然没有任何日志?这也太吓人了。后续我尝试了重装了第一台RDG服务器,重新配置了RDG,并且先不对接远程NPS,报错依旧,另一台RDG也是相同报错和表现,第一天搜索和尝试未果,只能抱着郁闷的心情下班回家。
第二天一早,继续死磕这个报错,最后终于在午休前找到了一篇国外的文章,贴在这里:https://call4cloud.nl/remote-desktop-client-0xc000035b-configuring/#4_0xc000035b_and_0x3000008_Errors
文章内提到,作者记得曾经有一个补丁把mstsc搞坏了,并且猜测微软虽然更新了mstsc,但是又给它搞坏了(Windows11上会发现连接RD时上方的状态条明显和曾经不一样了),于是继续阅读,作者调查了客户端event里的log,怀疑和UDP有关,于是登录RDG关闭了它,立刻恢复正常了。
有样学样,照葫芦画瓢,登录RDG,关闭Transport Settings里下方的UDP transport(最开始我是勾选了它的)。
好了。
至此,对于微软已经无力再骂,只能庆幸找到了正确的文章,碰到了遇到过相同问题的人。文章内作者发现是他们的网络环境疑似没有开启UDP转发,但是经过确认我们的环境是开启了的。无力吐槽,只能说谢谢你,微软。
负载均衡
负载均衡这一步要比想象的简单非常多,最开始我是想用Nginx来实现负载均衡,但是转念一想,我只需要负载均衡,并不需要别的功能,不妨试试别的代理,于是选择了专注于负载均衡HAProxy,事实证明,我选对了,HAProxy的性能实际上是比Nginx要高很多的。
HAproxy负载均衡配置非常简单,配置好frontend监听任何来源的443端口请求,backend以域名+端口格式配置好两台RDG服务器(因为RDG会检查连接时使用的域名和证书是否匹配,如果使用IP或者非域名全称的话RDG会拒接连接),把default里面的mode从http改为tcp,使用leastconn(自动将用户分配到活动Session最少的后端上,根据官方文档,此方式最适合用在长连接上,正好符合RDP的特性)的balance方式。启动服务,一切正常,可以连接上RDG,并且在连接了一个用户后,再找第二个人测试连接,会发现他被分配到了第二台RDG服务器上。至此,两台RDG+MFA并且负载均衡的要求已经完全实现。
后记
其实到这里只是三个需求实现了两个,我们还有一个需求是禁用RDP的剪贴板重定向,实现禁止双向的复制粘贴,防止用户将代码从开发VM内复制出来。但是奇异搞笑的是,如果不使用远程NPS的话,RDG自己确实是可以做到通过规则禁止特定的设备重定向,来禁用掉剪贴板功能,但是如果启用了远程NPS,这个功能会消失的无影无踪。
谢谢你,微软,傻逼来的。