Thursday, January 1, 2015

DSC - Protecting the credentials in the MOF files

When you dot source the DSC configuration file that contains a resource having a PSCredential object as parameter with the PSDscAllowPlainTextPassword option set in the configuration data, the resulting MOF file will have the password saved as plain text in a human readable format. This results in compromising the credentials from the MOF files. If you want to secure your credentials in the MOF file, then you need to use the LCM to check the credentials of the user, encrypt the credentials using the certificate details mentioned in the configuration data and then later decrypt it using the settings of the LCM.
To secure your MOF files, you’ll need to first create a certificate with a private key to decrypt the data in the MOF files and then use that information to create the MOF files.
You can create the certificate, root certificate and revocation list using the makecert command from the VS 2013 command prompt as given below

makecert -pe -n "CN=*your subject here" -a sha256 -sky exchange -eku 1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13 -ic ..\Root\Myroot.cer -iv ..\Root\Myroot.pvk -sy 24 -sv Myroot.pvk  Myroot.cer

pvk2pfx -pvk Myroot.pvk -spc Myroot.cer -pfx Myroot..pfx -po "your password"

makecert -pe -n "CN=ROOT Authority" -sy 24 -sv MyCert.pvk  MyCert.cer

pvk2pfx -pvk MyCert.pvk -spc MyCert.cer -pfx MyCert.pfx -po "Your password"

makecert -crl -sv MyCert.pvk MyCert.crl

Once you have the required certificates, you can use this data in the configuration file to encrypt the credentials and store in the MOF files.

$ErrorActionPreference = "Stop"

Import-Module DSCAdministration
Configuration SecuredAccountConfiguration
{
    Node $AllNodes.Where{$_.Role -eq "DEV"}.NodeName
    {      
        $credential = Get-Credentials
        ProtectedResource Resource1
       {
            Username = $credential.Username
            Credential = $credential
            Ensure = "Present"
        }
        LocalConfigurationManager
        {
             CertificateId = $Node.Thumbprint
        }
    }
}

Function Create-Configuration{
    param(
        [Parameter(Mandatory = $true)]
        [string] $Thumbprint,
        [bool] $ApplyConfiguration = $false
    )   
    $certificate = (Get-CertDetailsToEncryptMofFile $Thumbprint)
    $config = @{
        AllNodes = @(
            @{
                NodeName = $env:COMPUTERNAME
                Role = "DEV"                                     
                CertificateFile = $certificate.Certificate
                Thumbprint = $certificate.Thumbprint
            } 
        )
    }

    SecuredAccountConfiguration -configurationdata $config -OutputPath .\SecuredAccountConfiguration
    if($ApplyConfiguration){
        Set-DSCLocalConfigurationManager .\SecuredAccountConfiguration
        Start-DscConfiguration .\SecuredAccountConfiguration -Verbose -Wait
    }
}

Create-Configuration -Thumbprint "546AD85913453805AF1115E135DF9EB126218765"

The Get-CertDetailsToEncryptMofFile function is defined in the PS module as

Function Get-CertDetailsToEncryptMofFile
{
    param(
                        [Parameter(Mandatory = $true)]
                        [string] $Thumbprint,
                       
                        [string] $Path
            )
            $result = @{Certificate = $null; Thumbprint = $null}
            Get-ChildItem -Path "cert:\LocalMachine\My" |% {
                        if($_.PrivateKey.KeyExchangeAlgorithm –and $_.Verify()){
                                    if($_.Thumbprint -eq $Thumbprint){
                                                if([string]::IsNullOrEmpty($Path)){
                                                            $Path = Join-Path $env:SystemDrive -ChildPath "MyPublicKeys”
                                                }
                                                if(-not (Test-Path $Path -ErrorAction SilentlyContinue)){
                                                            Write-Verbose "Creating new directory at location $Path to export the public key to encrypt the credentials in the mof file"
                                                            New-Item -Path $Path -ItemType directory -ErrorAction SilentlyContinue | Out-Null
                                                }
                                                [Byte[]]$CertContent = $_.Export('Cert')
                                                $Path = Join-Path $Path MyCert.cer
                                                Set-Content -Path $Path -Value $CertContent -Encoding Byte
                                                Write-Verbose "Exported the certificate to $Path"
                                                $result.Certificate = $Path
                                                $result.Thumbprint = $_.Thumbprint
                                    }
                        }
            }          
    return $result
}


The Set-DSCLocalConfigurationManager command will make sure that the LCM on the target machine knows the certificate to decrypt the credentials in the MOF file.

No comments: