仅需管理(Just Enough Administration):PowerShell 安全配置指南
1. 引言
仅需管理(Just Enough Administration,JEA)是 PowerShell 安全生态系统的最后一道安全支柱。它是一个配置框架,使 IT 人员能够在安全环境中部署和使用 PowerShell 远程功能。JEA 利用 PowerShell 会话配置来定义 PowerShell 远程运行空间,旨在确保 PowerShell 远程端点的安全性。
使用 JEA 前,需要对期望状态配置(Desired State Configuration,DSC)有基本的了解。Windows PowerShell 和运行在 Windows 上的 PowerShell (Core) 都支持 JEA。
2. JEA 背景
JEA 基于“即时”安全模型,该模型提供对特权任务的时间敏感和细粒度访问。通过遵循最小权限原则(PoLP),可以限制权限,从而减少横向攻击的范围和影响。
PowerShell 通过注册远程会话配置,对其功能进行细粒度控制,包括:
- 语言模式
- 执行策略
- 预加载或定义的别名、程序集、函数或模块
- Cmdlet 允许列表
- Cmdlet 拒绝列表
- 运行时账户
- 日志记录
- 用户驱动器
- 版本控制
- 参数和值的细粒度控制
2.1 PowerShell 远程基础
PowerShell 远程是一种允许通过网络远程执行 PowerShell 命令的机制。它使用 WinRM(Windows 远程管理)或 SSH 协议作为传输层,将会话状态封装在消息体中。
| PowerShell 版本 | 支持的协议 |
|---|---|
| Windows PowerShell 2.0 - 5.1 | WinRM |
| PowerShell (Core) 6.0 及以上 | WinRM 或 SSH |
需要注意的是,JEA 仅在 WinRM/WSMan 协议下可用,不支持 SSH。PowerShell 远程会话使用 CLIXML 数据类型在端点之间序列化和反序列化对象数据。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(客户端):::process -->|WinRM/SSH| B(服务器):::process
A -->|CLIXML 数据| B
2.2 PowerShell 会话配置概述
当 PowerShell 连接到远程会话时,远程 PowerShell 实例会预加载由 Web 服务管理(WS-Management 或 WSMan)服务存储的配置,该配置描述了会话支持的 JEA 功能。
PowerShell 使用 PowerShell 会话配置文件(扩展名为 .pssc)来注册其远程 WSMan 插件配置,配置数据以 [Hashtable] 形式存储。相关的 PowerShell 会话配置 cmdlet 位于 Microsoft.PowerShell.Core 模块中,包括:
1. New-PSSessionConfigurationFile:创建 PowerShell 会话配置
2. Register-PSSessionConfiguration:注册 PowerShell 会话配置文件
3. Get-PSSessionConfiguration:返回已注册的 PowerShell 会话配置
4. Unregister-PSSessionConfiguration:注销先前注册的 PowerShell 会话配置
5. Get-PSSessionCapability:审核用户在 PowerShell 远程会话配置中的 JEA 功能
6. Test-PSSessionConfigurationFile:测试 PowerShell 会话配置文件是否存在错误
7. Set-PSSessionConfiguration:更新或更改已注册的 PowerShell 会话配置
8. Enable-PSSessionConfiguration:启用已注册的会话配置
9. Disable-PSSessionConfiguration:禁用已注册的会话配置
2.3 PowerShell 远程认证和传输加密
PowerShell 远程支持多种认证方法:
-
默认
:使用协商认证类型
-
Kerberos
:基于票据的相互认证协议,要求设备证明其身份。Kerberos 密钥分发中心(KDC)运行在域控制器上,负责颁发票据。
-
基本(RFC7235)
:在每个 WinRM SOAP 请求的 HTTP 授权标头中使用“基本”认证类型,依赖 WinRM 的传输加密(HTTPS)进行安全传输。
-
协商(Windows 集成认证)
:使用 Kerberos 或 NTLM 两种认证协议,作为本地 Active Directory 域内的单点登录机制。
-
CredSSP(凭证安全支持提供程序)
:用于扩展 Windows 认证机制,加密用户凭证并传输到 SSP,由 SSP 协商使用的认证机制。
-
证书认证
:使用 X.509 证书进行认证,通过 TLS 过程建立安全会话。
| 认证类型 | WinRM HTTP 消息级加密类型 |
|---|---|
| 默认(使用 Kerberos) | AES - 256 |
| 默认(使用 NTLM) | RC4 |
| Kerberos | AES - 256 |
| 基本 | 无 |
| 协商 - NTLM | RC4 |
| 协商 - Kerberos | AES - 256 |
| CredSSP | TLS |
3. PowerShell 角色功能
PowerShell 角色功能(PSRC)文件是定义通过 PowerShell 会话配置暴露的模块功能的配置文件。配置数据以 PowerShell [Hashtable] 形式存储,会话初始化时,角色功能权限会合并为一个单一的角色功能,类似于访问控制项(ACE)和访问控制列表(ACL)。
Windows PowerShell 会从模块目录下的 RoleCapabilities 子目录预加载 *.psrc 文件。而在 PowerShell (Core) 中,可以使用 RoleDefinitions 属性直接在 PowerShell 会话配置文件中定义 PSRC 文件。
以下是一个 Windows PowerShell 模块的目录结构示例:
ModuleName
│ Module.psm1 # 模块文件
│ Module.psd1 # 模块清单文件
│
├───Public
├───Private
├───Help
└───RoleCapabilities
ServiceMaintenance.psrc
ProcessMaintenance.psrc
3.1 在控制台中实现 Windows PowerShell 角色功能
使用 Windows PowerShell 实现角色功能的步骤如下:
1. 使用 New-PSRoleCapabilityFile 创建 PSRC 文件
$roleParameters = @{
Path = ".\ServiceMaintenance.psrc"
Author = "User01"
CompanyName = "Fabrikam Corporation"
Description = "This role enables users to get/restart any service"
VisibleCmdlets = "Restart-Service", "Get-Service"
}
New-PSRoleCapabilityFile @roleParameters
$roleParameters = @{
Path = ".\ProcessMaintenance.psrc"
Author = "User01"
CompanyName = "Fabrikam Corporation"
Description = "This role enables users to stop/start processes"
VisibleCmdlets = "Get-Process", "Stop-Process"
}
New-PSRoleCapabilityFile @roleParameters
- 将文件复制到 PowerShell 模块中
$joinPathParams = @{
Path = $env:ProgramFiles
ChildPath = "WindowsPowerShell\Modules\TestJEAModule"
}
$modulePath = Join-Path @joinPathParams
New-Item -ItemType Directory -Path $modulePath
New-Item -ItemType File -Path (Join-Path $modulePath "TestJEAModule.psm1")
$moduleManifestParams = @{
Path = Join-Path $modulePath "TestJEAModule.psd1"
RootModule = "TestJEAModule.psm1"
}
New-ModuleManifest @moduleManifestParams
3.2 在控制台中实现 PowerShell (Core) 角色功能
使用 PowerShell (Core) 实现角色功能的步骤如下:
1. 使用 New-PSRoleCapabilityFile 创建 PSRC 文件(参考上述示例)
2. 使用 RoleDefinitions 参数在 PowerShell 会话配置中定义 PSRC 文件
PowerShell (Core) 定义了三种配置类型:
- RoleCapabilities:预加载的 PowerShell 模块中的 PSRC 文件名
- RoleCapabilityFiles:其他 PSRC 文件
- 自定义:使用参数定义与组关联的自定义 PSRC 配置
$configSettings = @{
Path = '.\SampleFile.pssc'
SchemaVersion = '1.0.0.0'
Author = 'User01'
Copyright = '(c) Fabrikam Corporation. All rights reserved.'
CompanyName = 'Fabrikam Corporation'
RoleDefinitions = @{
'CONTOSO\PSSC_HELPDESK_RAS01' = @{
RoleCapabilityFiles = '.\ServiceMaintenance.psrc',
'.\ProcessMaintenance.psrc'
}
}
}
New-PSSessionConfigurationFile @configSettings
3.3 在 DSC 中实现 PowerShell 角色功能
JeaDsc 模块使用 JeaRoleCapabilities 资源来定义 PSRC,并支持与 New-PSRoleCapabilityFile 相同的格式。
[DscLocalConfigurationManager()]
Configuration JeaRoleCapabilities
{
Import-DscResource -ModuleName JeaDSC
Node localhost {
JeaRoleCapabilities ServiceMaintenanceCapability {
Path = "C:\Temp\ServiceMaintenance.psrc"
VisibleCmdlets = "Restart-Service", "Get-Service"
Description = "This role enables users to get/restart any service."
}
JeaRoleCapabilities ProcessMaintenanceCapability {
Path = "C:\Temp\ProcessMaintenance.psrc"
VisibleCmdlets = "Get-Process", "Stop-Process"
Description = "This role enables users to stop/start processes."
}
}
}
需要注意的是,JeaRoleCapabilities 必须在会话配置创建/注册之前执行,否则 DSC 配置将失败。还可以使用 Find-RoleCapability 搜索已注册存储库中的 PowerShell 角色功能。
4. 开始使用 PowerShell 会话配置
创建 PowerShell 会话配置涉及以下步骤:
1. 启用 PowerShell 远程功能
2. 创建一个或多个 PowerShell 角色功能文件
3. 注册 PowerShell 会话配置
以下是一个 DSC 服务器配置示例:
# ServerConfigurationData.psd1
@{
AllNodes = @(
@{
NodeName = "DC01"
Role = "DomainController"
PSRemotingEnabled = $true
PSRemotingConfigurationType = @(
"HelpdeskResetPassword",
"DNSManagement"
)
},
@{
NodeName = "FS01"
Role = "FileSrver"
PSRemotingEnabled = $false
},
@{
NodeName = "HRBW"
Role = "HybridRunbookWorker"
PSRemotingEnabled = $true
PSRemotingConfigurationType = "NoRestrictions"
}
)
}
4.1 步骤 1:启用 PowerShell 远程功能
PowerShell 远程功能最好使用管理框架进行部署和管理,以下是一些可行的方法:
1. Ansible/Chef/Desired State Configuration (DSC):使用 DSC 是一个不错的选择,本文示例使用 DSC。
2. 组策略:可以通过组策略启用或禁用 PowerShell 远程功能。
3. SCCM/Intune:可将其纳入机器部署脚本,用于向机器部署 PowerShell 远程功能。
4. Azure Arm/Terraform/Cloud Formation/Puppet:许多工具支持使用基础设施即代码(IaC)部署 PowerShell。
也可以使用
Enable-PSRemoting -Force
在控制台中启用 PowerShell 远程功能,但本文示例使用 DSC。以下是一个启用 PowerShell 远程功能的 DSC 配置:
# Installing the Module
Find-Module -Name WSManDsc -Repository PSGallery | Install-Module
# WSManConfig.ps1
#Requires -module WSManDsc
<#
.DESCRIPTION
Enable compatibility HTTP and HTTPS listeners, set
maximum connections to 100.
#>
Configuration PowerShellRemoting
{
Import-DscResource -ModuleName 'PSDesiredStateConfiguration'
Import-DscResource -ModuleName 'WSManDsc'
Node $AllNodes.Where{$_.PSRemotingEnabled}.NodeName {
WSManServiceConfig ServiceConfig {
IsSingleInstance = 'Yes'
MaxConnections = 100
AllowUnencrypted = $false
AuthCredSSP = $false
}
Service EnableWinRM {
Name = 'WinRM'
StartupType = 'Automatic'
State = 'Running'
}
Script EnablePowerShellRemoting {
DependsOn = '[Service]EnableWinRM'
SetScript = {
Enable-PSRemoting
}
GetScript = {
@{
Result = (
[Bool](New-PSSession . -ErrorAction SilentlyContinue)
-and [Bool](Test-WSMan -ComputerName .)
)
}
}
TestScript = {
$state = [scriptblock]::Create($GetScript).Invoke()
$state.Result
}
}
}
}
4.2 步骤 2:创建/注册 PowerShell 会话配置
传统上,需要在 PowerShell 控制台中使用
New-PSSessionConfigurationFile
和
Register-PSSessionConfiguration
创建 PowerShell 会话配置文件。过程如下:
1. 使用
New-PSSessionConfigurationFile
创建 PowerShell 会话配置文件
2. 使用
Test-PSSessionConfigurationFile
测试文件
3. 使用
Register-PSSessionConfiguration
注册配置
作为替代方案,本文介绍 JeaDsc 资源,它只需使用
JeaSessionConfiguration
即可创建和注册 PowerShell 会话配置。
JeaDsc 是一个 Microsoft DSC 资源,可在多台机器上部署会话配置。使用 JeaDsc 的前提条件如下:
1. PowerShell 5.1 或更高版本
2. 一个或多个作为 PowerShell 模块一部分的 PowerShell 角色功能(PSRC)文件
3. 从 PowerShell 库安装 JeaDsc 模块
4. 访问 DSC 拉取服务器,如 Azure Automation
准备好 JeaDsc 配置后,可以使用
JeaRoleCapabilities
和
JeaSessionConfiguration
资源将其应用到端点。
JeaSessionConfiguration
资源类似于
New-PSSessionConfigurationFile
,但某些属性(如
RoleDefinitions
)需要将 [Hashtable] 包装为 [String]。
以下是一个 JeaDsc PowerShell 会话配置示例,允许所有帮助台人员重启服务和停止进程:
Configuration JEAMaintenance
{
Import-DscResource -Module JeaDsc
Node $AllNodes.Where{$_.PSRemotingEnabled}.NodeName {
JeaRoleCapabilities ServiceMaintenanceCapability {
Path = "C:\Program Files\WindowsPowerShell\Modules\" +
"Demo\RoleCapabilities\ServiceMaintenance.psrc"
VisibleCmdlets = "Restart-Service", "Get-Service"
Description = "This role enables users to get/restart any service"
}
JeaRoleCapabilities ProcessMaintenanceCapability {
Path = "C:\Program Files\WindowsPowerShell\Modules\" +
"Demo\RoleCapabilities\ProcessMaintenance.psrc"
VisibleCmdlets = "Get-Process", "Stop-Process"
Description = "This role enables users to stop/start processes"
}
JeaSessionConfiguration HelpDeskManagmenetEndpoint
{
Name = 'JEAMaintenance'
RunAsVirtualAccount = $true
Ensure = 'Present'
DependsOn =
'[JeaRoleCapabilities]ServiceMaintenanceCapability',
'[JeaRoleCapabilities]ProcessMaintenanceCapability'
RoleDefinitions = "@{
'Contoso\ServiceMaintenanceCapability' = @{ RoleCapabilities =
'ServiceMaintenanceCapability'}
'Contoso\ProcessMaintenanceCapability' = @{ RoleCapabilities =
'ProcessMaintenanceCapability'}
}"
TranscriptDirectory = 'C:\Temp\Transcripts'
}
}
}
对 PowerShell 会话配置的更改会导致 WinRM 服务重启,断开所有打开的 PowerShell 会话。JeaDsc 具有以下属性:
| 属性 | 描述 | 语法示例 |
| ---- | ---- | ---- |
| [String] RoleDefinitions | 定义端点的角色定义映射,需要将 [Hashtable] 包装为 [String] |
RoleDefinitions = "@{DOMAIN\User|Group = @{ RoleCapabilities = "Setting" }}"
|
| [Bool] RunAsVirtualAccount | 将会话配置作为机器的(虚拟)管理员账户运行 |
RunAsVirtualAccount = $true
|
| [String[]] RunAsVirtualAccountGroups | 与虚拟管理员账户关联的可选组 |
RunAsVirtualAccountGroups = 'Group1', 'Group2'
|
| [String] GroupManagedServiceAccount | 将会话配置为在组托管服务账户内运行 |
GroupManagedServiceAccount = 'DOMAIN\gMSAGroup1'
|
| [String] TranscriptDirectory | JeaDsc 保存转录文件的目录 |
TranscriptDirectory = 'C:\FolderPath\'
|
| [String[]] ScriptsToProcess | 启动时运行的脚本 |
ScriptsToProcess = 'C:\FolderPath\Script1.ps1', 'C:\FolderPath\Script2.ps1'
|
| [String] SessionType | 指定 PowerShell 应创建的会话类型,值可以是 ‘Empty’、’Default’、’RestrictedRemoteServer’ |
SessionType = 'RestrictedRemoteServer'
|
| [Bool] MountUserDrive | 配置使用此配置的会话以暴露 User: PSDrive |
MountUserDrive = $true
|
| [Long] UserDriveMaximumSize | 用户驱动器的可选最大大小(字节),默认值为 50MB |
UserDriveMaximumSize = 524288000
|
| [String[]] RequiredGroups | 条件访问规则,需要将 [Hashtable] 包装为 [String] |
RequiredGroups = "@{ And = "RequiredGroup1", @{ Or = "OptionalGroup1", "OptionalGroup2" }}"
|
| [Object[]] ModulesToImport | 要导入的模块列表,需要 [String] 和 [Hashtable] 对象的数组 |
ModulesToImport = "'CustomModule', @{ ModuleName = 'CustomModuleName'; ModuleVersion = '1.0.0.0'; GUID = 'GUID' }"
|
| [String[]] VisibleAliases | 在 PowerShell 会话中暴露的命令别名 |
VisibleAliases = 'gci', 'gm'
|
| [String[]] VisibleCmdlets | 在 PowerShell 会话中暴露的 Cmdlet |
VisibleCmdlets = 'Get-ChildItem', 'Get-Member'
|
| [String[]] VisibleFunctions | 在 PowerShell 会话中暴露的函数 |
VisibleFunctions = 'Do-Something', 'Do-SomethingElse'
|
| [String[]] VisibleExternalCommands | 限制会话的外部二进制文件、脚本和命令,默认情况下无命令可见 |
VisibleExternalCommands = 'C:\dosomething.ps1', 'C:\thirdparty.dll'
|
| [String[]] VisibleProviders | 限制会话中可用的 PowerShell 提供程序 |
VisibleProviders = 'FileSystem', 'Function', 'Variable'
|
| [String[]] AliasDefinitions | 要添加到会话中的命令别名,需要将 [Hashtable] 包装为 [String] |
AliasDefinitions = "@{ AliasName = 'Cmdlet'; AnotherAlias = 'Cmdlet'}"
|
| [String[]] FunctionDefinitions | 在会话中定义的自定义函数,需要将 [Hashtable] 包装为 [String] |
FunctionDefinitions = "@{ Name = 'Do-Something'; ScriptBlock = { param($MyInput) $MyInput } }"
|
| [String] VariableDefinitions | 在会话中声明的变量,需要将 [Hashtable] 包装为 [String] | |
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(启用 PowerShell 远程功能):::process --> B(创建 PowerShell 角色功能文件):::process
B --> C(注册 PowerShell 会话配置):::process
C --> D(使用 JeaDsc 应用配置):::process
通过以上步骤和配置,可以有效地使用 JEA 来增强 PowerShell 远程功能的安全性和管理性。在实际应用中,根据具体需求调整配置参数,以满足不同的安全和管理要求。
超级会员免费看
14

被折叠的 条评论
为什么被折叠?



