配置本地配置管理器
在前面我们搭建一个pull服务器时,包含了一个修改目标节点的本地配置管理器(LCM)的简短例子。在任何机器上,你都可以运行Get-DscLocalConfigurationManager来检查这个机电的LCM设置。它们包含这些:
- AllowModuleOverwrite.当它设为 $True时, 表示允许新的模块(从pull server下载的) 覆盖旧的模块。.
- CertificateID. 节点证书的指纹. 这个证书必须被储存在节点本机上,并且它将用于解密那些包含在配置文件内的加密数据. 比如,DSC让你在MOF文件中包含PSCredential这个对象, 但需要它们是加密的. 该书的下一段落我们就会涉及这一方面。
- ConfigurationID. 节点从它的pull server山拉回配置文件时用到的GUID.
- ConfigurationMode. LCM工作的方式。ApplyOnly DSC仅应用一次配置除非监测到pull server上有新的配置。(原文是ApplyOnce only applies a configuration one time。但与实际情况不符). ApplyAndMonitor 应用该配置,并且在之后间断性重复检查它。变化会被记录在日志内。 ApplyAndAutoCorrect 自动地重复应用配置。
- ConfigurationModeFrequencyMins. LCM 重复检查配置的间隔分钟数。它必须是RefreshFrequencyMinutes倍数。 如果你写的参数不是其倍数,那你的值就会最终取与其最近的倍数。该属性的最小值为30分钟。
- Credential. 用于获取远程Resource的证书。正常情况下,LCM是已SYSTEM这个用户来运行的,它访问非本地的资源时只有很有限的权限。比如,如果你打算让你的LCM从一个SMB的pull server上拉取配置,你就一定需要给提供一个合法地 证书,才可以实现这个。
- DownloadManagerCustomData. 被传递到所选的下载管理器的属性。例如,WebDownloadManager需要一个URI,且要设置成为支持HTTP.
- DownloadManagerName. 必须是WebDownloadManager 或DscFileDownloadManager.
- RebootNodeIfNeeded. 如果它为$True。目标节点会在需要的时候自动重启。默认值为$False,这就意味着配置操作需要重启就无法实现了,除非有人手动重启了这个节点。微软选择默认为$False ,因为这更安全–当设为$True时,一旦DSC认为有必要重启,那重启就会立马发生。在产品环境里的一台服务器上,你就会发现这可能是个问题。
- RefreshFrequencyMins. 在pull模式里,指定多久从pull server上检查一次新的配置。 该属性的最小值为15分钟.
- ReFresgMode: 只能是Push 或Pull。你必须指定一个DownloadManagerName属性。 注意LCM只会处理单个配置。如果你推送了一个新的配置,LCM将会使用这个配置来替换以前的那个。在pull模式里,它只会拉回一个配置。你可以使用组合的配置(前文介绍过)来把多个配置联合成一个。
当你生成了相应的MOF文件时,你需要运行Set-DscLoaclConfiguration指令而不是Start-DscConfigutration来应用它。而且配置脚本应该只包含LocalConfigurationManager这个配置项,不应该包含任何其他的配置项。
更多LCM配置的信息,请看http://blogs.msdn.com/b/PowerShell/archive/2013/12/09/understanding-meta-configuration-in-Windows-PowerShell-desired-state-configuration.aspx。在写这本书时,http://technet.microsoft.com/en-us/library/dn249922.aspx 上的一些内容是不准确的。
在配置中加入证书(Credentials)
很多次,你都需要在你的配置中加入证书。在配置脚本中,你可以简单的传递进去一个PSCredential的对象作为参数,并且使用Get-Credential来创建这个PSCredential这个对象。当这个配置脚本运行的时候,这个PSCredential对象也会被连载进入这个MOF文件,然后被传送(通过push或者pull模式)到目标节点上去。当然,你是肯定不想你的证书以明文的形式传递过去吧?
正确的方式
为了能够让认证正常工作,证书必须在所有的目标节点(特别是在本地机器库里)上都有。在节点的LCM配置中必须指定这个证书的指纹(具体见前文)。同样的证书也必须要安装在你将要生成MOF文件来执行配置的电脑。当你创建这个配置的时候,你应该把证书的指纹作为配置数据的一部分传入。我们接下来讨论如何实现这个。
具体实现可以看PowerShell团队的博客: http://blogs.msdn.com/b/PowerShell/archive/2014/01/31/want-to-secure-credentials-in-Windows-PowerShell-desired-state-configuration.aspx 这里你可以看到更多细节。
这儿有一个快速学习的例子,其中加入了PSCredential:
configuration CredentialEncryptionExample
{
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[PsCredential] $credential
)
Node $AllNodes.NodeName
{
File exampleFile
{
SourcePath = "\\Server\share\path\file.ext"
DestinationPath = "C:\destinationPath"
Credential = $credential
}
}
}
这个配置脚本在运行的时候,会提示你需要PSCredential的用户名和密码。你可以注意到FIle这个Resource被用作从一个UNC路径拷贝一个文件。假设这个UNC路径需要一个非匿名的连接,我们就将需要提供一个证书---并且我们还要传递这个PSCredential。
这个配置里所用到的方法就是从$AllNode变量中取。下面就是我们的实现:
$ConfigData = @{
AllNodes = @(
@{
# The name of the node we are describing
NodeName = "SERVER2"
# The path to the .cer file containing the
# public key of the Encryption Certificate
# used to encrypt credentials for this node
CertificateFile = "C:\publicKeys\targetNode.cer"
# The thumbprint of the Encryption Certificate
# used to decrypt the credentials on target node
Thumbprint = "AC23EA3A9E291A75757A556D0B71CBBF8C4F6FD8"
};
);
}
所以我们在$ConfigData创建了一个哈希表。这个哈希表只有一个关键字,名字为AllNodes,并且它的值是一个只有一项的数组。这一项本身也是一个有三个关键字(NodeNumber,CertificateFile,以及Thumbprint)的哈希表。这个证书没有安装在这台电脑上,但是它可以用一个导出的.cer文件代替。但是,这个证书必须要安装在任何我们即将应用这些配置的节点上。我们还要设置这些目标节点的LCM的CertificateId属性值为它的指纹。
因此,我们创建了这个配置。并且把这个配置数据块也要传进去它里面,并且这一块包含了这个证书的细节。现在我们需要在运行这个配置时传入这个配置数据:
CredentialEncryptionExample –ConfigurationData $ConfigData
注意我们从来没有定义–ConfigurationData这个作为这个配置的参数,它是一个所有配置都自动支持的内置参数。PowerShell会在这个MOF文件中自动加密这个证书,因为PowerShell被设计用于识别PSCredential这个对象并且对它们加密。目标节点会识别这些加密的数据,并且使用这些证书的拷贝然后解密。 需要注意的是,我们创建MOF文件的节点使用这个证书的公共密钥,而目标节点使用私钥用于解密。
更简单,更少权限的方式
当然,证书有时候不是那么方便,有时候你也不需要这种安全。比如,假设你正在搭建一个实验环境,并且你的所有密码都是Pa$
$w0rd。谁还在乎加密?
在这种情况下,你可以强制PowerShell在MOF文件中用明文的、未加密的密码。这儿就是一个在实验环境中搭建3台机器的例子:
Configuration LabSetup {
Param(
[Parameter(Mandatory=$True)]
[PSCredential]$DomainCredential,
[Parameter(Mandatory=$True)]
[PSCredential]$ SafeModeCredential,
[Parameter(Mandatory=$True)]
[string]$EthernetInterfaceAlias
)
# Ensure KB2883200 is installed on all computers
# Expecting Windows 8.1 and Windows Server 2012 R2
# Run this script on each computer to produce
# MOF files and start configuration
# You should do DC1 first, then the other two
# You will be prompted for two credentials
# For the first, provide DOMAIN\Administrator and Pa$$w0rd
# For the second, provide Administrator and Pa$$w0rd
# This assumes that the Student Materials files are at
# E:\AllFiles
# Computers must have the following downloaded and installed
# into C:\Program Files\WindowsPowerShell\Modules:
# - http://gallery.technet.microsoft.com/xActiveDirectory-f2d573f3
# - http://gallery.technet.microsoft.com/scriptcenter/xComputerManagement-Module-3ad911cc
# - http://gallery.technet.microsoft.com/scriptcenter/xNetworking-Module-818b3583
Import-DscResource -ModuleName ActiveDirectory,xNetworking,xComputerManagement
Node 'DC1' {
WindowsFeature ADDSInstall {
Ensure = 'Present'
Name = 'AD-Domain-Services'
}
xIPAddress IP {
IPAddress = '10.0.0.10'
InterfaceAlias = $EthernetInterfaceAlias
DefaultGateway = '10.0.0.1'
SubnetMask = 24
AddressFamily = 'IPv4'
}
xDNSServerAddress DNS {
Address = '127.0.0.1'
InterfaceAlias = $EthernetInterfaceAlias
AddressFamily = 'IPv4'
}
xComputer Computer {
Name = 'DC1'
}
xADDomain Adatum {
DomainName = domain.pri'
DomainAdministratorCredential = $domaincredential
SafemodeAdministratorPassword = $SafeModeCredential
DependsOn = '[WindowsFeature]ADDSInstall',
'[xIPAddress]IP',
'[xDNSServerAddress]DNS',
'[xComputer]Computer'
}
}
Node 'CL1' {
xIPAddress IP {
IPAddress = '10.0.0.30'
InterfaceAlias = $EthernetInterfaceAlias
DefaultGateway = '10.0.0.1'
SubnetMask = 24
AddressFamily = 'IPv4'
}
xDNSServerAddress DNS {
Address = '10.0.0.10'
InterfaceAlias = $EthernetInterfaceAlias
AddressFamily = 'IPv4'
}
xComputer Computer {
Name = 'CL1'
DomainName = 'DOMAIN'
Credential = $DomainCredential
DependsOn = '[xIPAddress]IP','[xDNSServerAddress]DNS'
}
Environment Env {
Name = 'PSModulePath'
Ensure = 'Present'
Path = $true
Value = 'E:\AllFiles\Modules'
}
}
Node 'SRV1' {
xIPAddress IP {
IPAddress = '10.0.0.20'
InterfaceAlias = $EthernetInterfaceAlias
DefaultGateway = '10.0.0.1'
SubnetMask = 24
AddressFamily = 'IPv4'
}
xDNSServerAddress DNS {
Address = '10.0.0.10'
InterfaceAlias = $EthernetInterfaceAlias
AddressFamily = 'IPv4'
}
xComputer Computer {
Name = 'SRV1'
DomainName = 'DOMAIN'
Credential = $DomainCredential
DependsOn = '[xIPAddress]IP','[xDNSServerAddress]DNS'
}
}
}
$ConfigurationData = @{
AllNodes = @(
@{
NodeName='LON-DC1'
PSDscAllowPlainTextPassword=$true
}
@{
NodeName='LON-SRV1'
PSDscAllowPlainTextPassword=$true
}
@{
NodeName='LON-CL1'
PSDscAllowPlainTextPassword=$true
}
)
}
LabSetup -OutputPath C:\LabSetup -ConfigurationData $ConfigurationData `
-EthernetInterfaceAlias 'Ethernet0'
Start-DscConfiguration -Path C:\LabSetup -ComputerName $env:COMPUTERNAME
这确实是一个非常酷的例子---有几个事情需要注意:
- 我们加入了超过一个的NODE段落。所以,我们使用单个配置脚本来搭建整个环境。当我们执行这个的时候,会生成三个MOF文件。
- 发现PSDscAllowPlainTextPassword 在配置数据内?那就是为什么MOF可以合法的包含未加密的密码的原因。注意我们是如何在Param() 块加入两个证书的,以及之后使用这些证书完成这个配置。 我们参数化了以太网接口的别称,因为有时候它并不是“Ethernet0” 。参数化它有利于在未来的步骤中更加容易改变。
- 在一台试验机器上执行该脚本会生成全部三个MOF文件,但是只有本地机器的MOF是真的执行了的。我们假设这台“空的”电脑已经是正确的机器名了,要关注的就是我们最开始基于的镜像。很明显不是所有的机器都会那样启动,但是我们的机器会。