Chicken / Egg Problem with Pull Server Creation

Welcome Forums DSC (Desired State Configuration) Chicken / Egg Problem with Pull Server Creation

Viewing 2 reply threads
  • Author
    Posts
    • #144617
      Participant
      Topics: 3
      Replies: 1
      Points: 7
      Rank: Member

      First real crack at DSC…  I’ve created an Active Directory server, and a CA using push configurations since those seem to be the requirements for a HTTPS Pull Server.  I am running into an issue attempting to request a certificate in the same configuration that creates the pull server.

      The CertReq resource works perfectly to request the certificate, but populating the Thumbprint from that certificate to the xDSCWebService resource is very challenging.  I’m trying to acquire the thumbprint programatically with the following :

      CertificateThumbPrint = (Get-ChildItem 'Cert:\LocalMachine\My\' | Where-Object { $_.Subject -eq 'CN=Pull01'}).Thumbprint.ToString()

      It appears to try and calculate that prior to running the preceding resources even though it “depends” on them, which causes the error:

      PSDesiredStateConfiguration\Node : You cannot call a method on a null-valued expression.

      Presumably because the certificate does not exist yet.

      I know I can request the certificate via command line and feed the proper values to the script, but I’d love to be able to do everything directly inside the script, thus creating a single DSC configuration file for each host, and I can recreate my environment.

      Is there any way to request the certificate and provide the proper values from that certificate?

      Full DSC Configuration file below…  Thanks in advance!

      Configuration Build-Pull01 {
      
          Param (
              [Parameter(Mandatory)]
              [pscredential]$CredDomain,
      
              [ValidateNotNullOrEmpty]
              [string]$CertificateFile,
      
              #[ValidateNotNullOrEmpty]
              #[string]$DSCCertThumbprint,
      
              [ValidateNotNullOrEmpty]
              [string]$DSCRegistration
      
          )
      
          Import-DscResource -ModuleName xPSDesiredStateConfiguration
          Import-DscResource -ModuleName ComputerManagementDsc
          Import-DscResource -ModuleName NetworkingDsc
          Import-DscResource -ModuleName PSDscResources
          Import-DscResource -ModuleName CertificateDsc
      
          Node localhost {
      
              LocalConfigurationManager {
                  ActionAfterReboot = 'ContinueConfiguration'
                  ConfigurationMode = 'ApplyOnly'
                  RebootNodeIfNeeded = $true
              }
      
              NetIPInterface EnableDHCP {
                  InterfaceAlias = $Node.IPInterfaceAlias
                  AddressFamily = $Node.IPAddressFamily
                  Dhcp = 'Enabled'
              }
      
              DnsServerAddress NewDnsAddress {
                  InterfaceAlias = $Node.IPInterfaceAlias
                  AddressFamily = $Node.IPAddressFamily
                  Validate = $true
                  DependsOn = '[NetIPInterface]EnableDHCP'
              }
      
              Computer JoinDomain {
                  Name = $Node.ComputerName
                  DomainName = $Node.IPDomainName
                  Credential = $CredDomain
                  DependsOn = '[DnsServerAddress]NewDnsAddress'
              }
      
              WindowsFeature DSCServiceInstall {
                  Ensure = 'Present'
                  Name = 'DSC-Service'
                  DependsOn = '[Computer]JoinDomain'
              }
      
              WaitForCertificateServices WaitForADCS {
                  CAServerFQDN = 'Cert01.dummydomain.local'
                  CARootName = 'dummydomain-CERT01-CA'
                  DependsOn = '[WindowsFeature]DSCServiceInstall'
              }
      
              CertReq PullCert {
                  Credential = $CredDomain
                  Subject = 'Pull01'#'CN=Pull01, OU=IT, O=dummydomain, L=City, S=CA, C=US'
                  KeyLength = 2048
                  CAServerFQDN = 'Cert01.dummydomain.local'
                  CARootName = 'dummydomain-CERT01-CA'
                  ProviderName = '"Microsoft RSA SChannel Cryptographic Provider"'
                  AutoRenew = $true
                  Exportable = $true
                  FriendlyName = 'PullServerCert'
                  KeyUsage = '0xa0'
                  RequestType = 'PKCS10'
                  KeyType = 'RSA'
                  CertificateTemplate = 'WebServer'
                  DependsOn = '[WaitForCertificateServices]WaitForADCS'
              }
      
              xDSCWebService PullServer {
                  Ensure = 'Present'
                  EndpointName = 'Pull01'
                  CertificateThumbPrint = (Get-ChildItem 'Cert:\LocalMachine\My\' | Where-Object { $_.Subject -eq 'CN=Pull01'}).Thumbprint.ToString()
                  Port = 8080
                  State = 'Started'
                  PhysicalPath = $Node.DSCPhysicalPath
                  ModulePath = $Node.DSCModulePath
                  ConfigurationPath = $Node.DSCConfigurationPath
                  RegistrationKeyPath = $Node.DSCRegistrationKeyPath
                  UseSecurityBestPractices = $true
                  DependsOn = '[CertReq]PullCert'
              }
      
              File RegistrationKeyFile {
                  Ensure = 'Present'
                  Type = 'File'
                  DestinationPath = $Node.FileDSCRegistrationPath
                  Contents = $DSCRegistration
                  DependsOn = '[xDSCWebService]PullServer'
              }
          }
      }
      
      $ConfigData = @{
          AllNodes = @(
              @{
                  NodeName                = 'localhost'
                  IPInterfaceAlias        = 'Ethernet0'
                  IPAddressFamily         = 'IPv4'
                  IPDomainName            = 'dummydomain.local'
                  ComputerName            = 'Pull01'            
                  DSCPhysicalPath         = "$env:SystemDrive\inetpub\PullServer"
                  DSCModulePath           = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules"
                  DSCConfigurationPath    = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration"
                  DSCRegistrationKeyPath  = "$env:PROGRAMFILES\WindowsPowerShell\DscService"
                  FileDSCRegistrationPath = "$env:ProgramFiles\WindowsPowerShell\DscService\RegistrationKeys.txt"
                  PSDScAllowDomainUser        = $true
                  PSDscAllowPlainTextPassword = $true
              }
          )
      }
      
      $CredDomain = Get-Credential -Message 'Enter Domain Credentials' -UserName 'dummydomain\administrator'
      
      $DSCRegistration = (New-Guid).ToString()
      
      Build-Pull01 -ConfigurationData $ConfigData -Verbose -CredDomain $CredDomain -DSCRegistration $DSCRegistration -CertificateFile $CertificateFile
      
      Start-DscConfiguration -Wait -Force -Path 'c:\Build-Pull01\' -Verbose

       

    • #144674
      Participant
      Topics: 4
      Replies: 15
      Points: 20
      Rank: Member

      DSC is a great technology. In my recently published book (), I devote a chapter to DSC. The supporting scripts are on GItHub at: https://github.com/doctordns/PowerShellCookBook2019/tree/master/Chapter%2010%20-%20Implementing%20Desired%20State%20Configuration)

      These show you how I created a pull server and how I careate a pull server using partial configuration (as well as using a push mechanism).

      Personally, I use Self-signed certificates for testing – as shown in the scripts I pointed out. You could easily change those out for Public Certs and proceed in thbe same way (a certificate is, after all, just a certificate).

    • #150833
      Participant
      Topics: 3
      Replies: 1
      Points: 7
      Rank: Member

      Thanks for the prompt reply.  I will have to dig deeper into partial configurations.  For now, I split the dsc configuration into two parts.  The first part brings the machine to the point where it would have been deployed from a template (name computer, setup network, join domain…).  The second configuration takes care of the rest.

      I’m sure this is not the “most correct” way to do it, but it works.

      Thanks Again!

Viewing 2 reply threads
  • The topic ‘Chicken / Egg Problem with Pull Server Creation’ is closed to new replies.