36、仅需管理(Just Enough Administration):PowerShell 安全配置指南

仅需管理(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
  1. 将文件复制到 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 远程功能的安全性和管理性。在实际应用中,根据具体需求调整配置参数,以满足不同的安全和管理要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值