BM-Bloggers

The blogs of Black Marble staff

Setting Enroll Permissions on ADCS Certificate Template using DSC

As part of the work I have been doing around generating and managing lab environments using Lability and DSC, one of the things I needed to do was change the permissions on a certificate template within a DSC configuration. Previously, when deploying to Azure, I used the PSPKI PowerShell modules within code executed by the Custom Script extension. I was very focused on sticking with DSC this time, which ruled out PSPKI. Whilst there is a DSC module available to configure Certificate Services itself, this does not extend to managing Certificate Templates.

Nobody seemed to have done exactly this before. I used the following links as references in creating the code:

Get Effective template permissions with PowerShell by Vadims Podāns

Duplicate AD Object Without Active Directory PS Tools

Add Object Specific ACEs using Active Directory PowerShell

Using Scripts to Manage Active Directory Security

The script finds the WebServer template and grants the Enroll extended permission to the Domain Computers AD group. This allows me to use xCertificate in the DSC configuration of domain member servers to request new certificates using the WebServer template.

Here is the code I include in my DSC configuration. $DomainCreds is a PSCredential object for the domain admin ( I create the AD domain in an earlier step using xActiveDirectory).

        #Enable Enroll on WebServer certificate template
        Script EnableWebServerEnroll {
            DependsOn = "[xAdcsCertificationAuthority]CertAuth"
            PsDscRunAsCredential = $DomainCreds
            GetScript = {
                return @{ 'Result' = $true}
            }
            TestScript = {
                #Find the webserver template in AD and grant the Enroll extended right to the Domain Computers
                $filter = "(cn=WebServer)"
                $ConfigContext = ([ADSI]"LDAP://RootDSE").configurationNamingContext
                $ConfigContext = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"

                $ds = New-object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$ConfigContext",$filter)
                $Template = $ds.Findone().GetDirectoryEntry()
                if ($Template -ne $null) {
                    $objUser = New-Object System.Security.Principal.NTAccount("Domain Computers")
                    # The following object specific ACE is to grant Enroll
                    $objectGuid = New-Object Guid 0e10c968-78fb-11d2-90d4-00c04f79dc55

                    ForEach ($AccessRule in $Template.ObjectSecurity.Access) {
                        If ($AccessRule.ObjectType.ToString() -eq $objectGuid) {
                            If ($AccessRule.IdentityReference -like "*$($objUser.Value)") {
                                Write-Verbose "TestScript: WebServer Template Enroll permission for Domain Computers exists. Returning True"
                                return $true
                            }
                        }
                    }
                }
                return $false
            }
            SetScript = {
                #Find the webserver template in AD and grant the Enroll extended right to the Domain Computers
                $filter = "(cn=WebServer)"
                $ConfigContext = ([ADSI]"LDAP://RootDSE").configurationNamingContext
                $ConfigContext = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"

                $ds = New-object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$ConfigContext",$filter)
                $Template = $ds.Findone().GetDirectoryEntry()

                if ($Template -ne $null) {
                    $objUser = New-Object System.Security.Principal.NTAccount("Domain Computers")
                    # The following object specific ACE is to grant Enroll
                    $objectGuid = New-Object Guid 0e10c968-78fb-11d2-90d4-00c04f79dc55
                    $ADRight = [System.DirectoryServices.ActiveDirectoryRights]"ExtendedRight"
                    $ACEType = [System.Security.AccessControl.AccessControlType]"Allow"
                    $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $objUser,$ADRight,$ACEType,$objectGuid
                    $Template.ObjectSecurity.AddAccessRule($ACE)
                    $Template.commitchanges()
                    Write-Verbose "SetScript: Completed WebServer additional permission"
                }
            }
        }

Speaking at Leeds DevOps on the 21st of July

I will be speaking at Leeds DevOps on the 21st of July on the subject of Desired State Configuration (DSC).

‘In the Windows world, due to its API based architecture, deployment is too often not as simple as copying an EXE and updating a text configuration file. Desired State Configuration is an attempt to ease the pain we suffer in this space. Providing a set of tools that can be leveraged by any set of deployment tools whether in a Windows or heterogeneous environment. In this session we will look at what DSC is, what resource are available and how to write your own’.

The event is at the The Node in Leeds, tickets are free and are available over on Eventbrite or meetup.com

Using Release Management vNext templates when you don’t want to use DSC scripts

Update 21 Aug 2015 - This post contains all the basic information, but there is an improved PowerShell script discussed in Using Release Management vNext templates when you don’t want to use DSC scripts – A better script


Many web sites are basically forms over data, so you need to deploy some DB schema and something like a MVC website. Even for this ’bread and butter’ work it is important to have an automated process to avoid human error. Hence the rise in use of release tools to run your DACPAC and MSDeploy packages.

In the Microsoft space this might lead to the question of how Desired State Configuration (DSC) can help? I, and others, have posted in the past about how DSC can be used to achieve this type of deployment, but this can be complex and you have to ask is DSC the best way to manage DACPAC and MSDeploy packages? Or is DSC better suited to only the configuration of your infrastructure/OS features?

You might ask why would you not want to use DSC, well the most common reason I see is that you need to provide deployment script to end clients who don’t use DSC, or you have just decided want basic PowerShell. Only you will be able to judge which is the best for your systems, but I thought it worth outlining an alternative way to do deployment of these package using Release Management vNext pipelines that does not make use of DSC.

Background

Let us assume we have a system with a SQL server and a IIS web server that have been added to the Release Management vNext environment. These already have SQL and IIS enabled, maybe you used DSC for that?

The vNext release template allows you to run either DSC or PowerShell on the machines, we will ignore DSC, so what can you do if you want to use simple PowerShell scripts?

Where do I put my Scripts?

We will place the PowerShell scripts (and maybe any tools they call) under source control such that they end up in the build drops location, thus making it easy for Release Management to find them, and allowing the scripts (and tools) to be versioned.

Deploying a DACPAC

The script I have been using to deploy DACPACs is as follows

# find the script folder
$folder = Split-Path -parent $MyInvocation.MyCommand.Definition
Write-Verbose "Deploying DACPAC $SOURCEFILE using script in '$folder'"
& $folder\sqlpackage.exe /Action:Publish /SourceFile:$folder\..\$SOURCEFILE /TargetServerName:$TARGETSERVERNAME /TargetDatabaseName:$TARGETDATABASENAME | Write-Verbose -Verbose

Note that:

  1. First it finds the folder it is running in, this is the easiest way to find other resource I need
  2. The only way any logging will end up in the Release Management logs is if is logged at the verbose level i.e. write-verbose “your message” –verbose
  3. I have used a simple & my.exe to execute my command, but pass the output via the write-verbose cmdlet to make sure we see the results. The alternative would be to use invoke-process
  4. SQLPACKAGE.EXE (and its associated DLLs) are located in the same SCRIPTS folder as the PowerShell script and are under source control. Of course you could make sure any tools you need are already installed on the target machine.

I pass the three parameters need for the strips as custom configuration

image

Remember that you don’t have to be the SQL server to run SQLPACKAGE.EXE, it can be run remotely (that is why in the screen shot above the ServerName is ISS IIS8 not SQL as you might expect)

Deploying a MSDeploy Package

The script I use to deploy the WebDeploy package this is as follows

function Update-ParametersFile
{
    param
    (
        $paramFilePath,
        $paramsToReplace
    )

    write-verbose "Updating parameters file '$paramFilePath'" -verbose
    $content = get-content $paramFilePath
    $paramsToReplace.GetEnumerator() | % {
        Write-Verbose "Replacing value for key '$($_.Key)'" -Verbose
        $content = $content.Replace($_.Key, $_.Value)
    }
    set-content -Path $paramFilePath -Value $content

}


# the script folder
$folder = Split-Path -parent $MyInvocation.MyCommand.Definition
write-verbose "Deploying Website '$package' using script in '$folder'" -verbose

Update-ParametersFile -paramFilePath "$folder\..\_PublishedWebsites\$($package)_Package\$package.SetParameters.xml" -paramsToReplace @{
      "__DataContext__" = $datacontext
      "__SiteName__" = $siteName
      "__Domain__" = $Domain
      "__AdminGroups__" = $AdminGroups

}

write-verbose "Calling '$package.deploy.cmd'" -verbose
& "$folder\..\_PublishedWebsites\$($package)_Package\$package.deploy.cmd" /Y | Write-Verbose -verbose

Note that:

  1. First I declare a function that I use to replace the contents of the package.setparameters.xml file, a key step in using binary promotion and WebDeploy
  2. Again I finds the folder the script is running in so I can locate other resources
  3. I then declare the parameters I need to replace and call the replacement function 
  4. Finally I call the package.deploy.cmd command, and pass the output via the write-verbose to pass the output to the Release Management logs

This is called as follows

image

Summary

So I think these reusable scripts give a fairly  easy way to make use of  vNext Release Management pipelines. They can also easily be given to clients who just want to manually run something.

My DSC session is up at TechDays Online 2015 On-Demand

A couple of weeks ago I presented on DSC and Release Management as part of the Microsoft UK TechDays Online 2015 event. All the sessions from this three day event are now available on demand at TechDays Online 2015 on-demand sessions.

You do seem to have to register/login to see the content, so I can’t deep link to my session, but browsing the catalogue is a good idea there are some great sessions