dsccommunity / CertificateDsc

DSC resources to simplify administration of certificates on a Windows Server.
https://dsccommunity.org
MIT License
122 stars 69 forks source link

How to set permissions on private key after importing cert via DSC #47

Open plraustin opened 7 years ago

plraustin commented 7 years ago

After importing pfx file how to set permissions on private key with DSC?

e.g., After loading cert into localcomputer \ my store how would one set IIS_IUSRS access to private key for use with IIS site using DSC process?

PlagueHO commented 7 years ago

Hi @plraustin - this is a really good question.

There isn't currently a resource that can be used to assign access to private keys to other local or domain accounts. This does seem like a good idea for a resource and wouldn't be too difficult to implement (based on the work I'm currently doing).

But in the meant time, you could use xScript to do this fairly easily.

Are you importing the certificate with xCertificateImport or are you requesting it using xCertReq?

StefanSchoof commented 7 years ago

I build for my use this (ugly) workaround:

        Script Certicate
        {
            GetScript = { 
                $store = "My"
                $thumbprint = "xxxx"

                $cert = Get-ChildItem "Cert:\LocalMachine\$store" | where {$_.Thumbprint -like $thumbprint}
                $path = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"
                @{Result = $path }
            }
            TestScript = { 
                $store = "My"
                $thumbprint = "xxxx"
                $userName = "IIS AppPool\DefaultAppPool"

                $cert = Get-ChildItem "Cert:\LocalMachine\$store" | where {$_.Thumbprint -like $thumbprint}
                $path = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"

                $acl = get-acl $path
                ($acl.Access | Where {$_.IdentityReference -eq $userName}) -ne $null
            }
            SetScript = {
                $store = "My"
                $thumbprint = "xxxx"
                $userName = "IIS AppPool\DefaultAppPool"

                $cert = Get-ChildItem "Cert:\LocalMachine\$store" | where {$_.Thumbprint -like $thumbprint}
                $path = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"

                $acl = get-acl $path
                $rule = new-object security.accesscontrol.filesystemaccessrule $userName, "Read", allow
                $acl.AddAccessRule($rule)
                set-acl $path $acl
            }
        }
guillemsola commented 6 years ago

As per my experience, current powershell implementation cannot be used to import a PFX certificate and then assign permissions. As this DSC module is using the standard PS mechanism is affected too.

My current alternative is not to use the DSC module to import a certificate where I need special rights. See this example implementation using other .Net classes. See this blogpost for more technical details.

Configuration ImportPfxCertificate {
    param(
                [PSCredential] $AdminCreds,
        [String] $CertificateFile,
        [String] $ThumbPrint,
        [String] $PrivateKeyPwd,
        [String] $CertUserName
    )

    Import-DscResource -ModuleName PSDesiredStateConfiguration

    Script InstallPfxCert
    {
        Getscript = {
            $Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -Argumentlist "My", LocalMachine
            $Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
            $cert = $Store.Certificates | Where Thumbprint -eq $using:thumbprint
            $Store.Close()

            @{Result = $cert }
        }
        TestScript = {
            $Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -Argumentlist "My", LocalMachine
            $Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
            $cert = $Store.Certificates | Where Thumbprint -eq $using:thumbprint
            $Store.Close()

            $cert -ne $null
        }
        SetScript = {
            $pwd = ConvertTo-SecureString $using:PrivateKeyPwd -AsPlainText -Force
            $flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
            $Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($using:CertificateFile, $pwd, $flags)

            $Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -Argumentlist "MY", LocalMachine
            $Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
            $Store.Add($Certificate)
            $Store.Close()
        }
        PsDscRunAsCredential = $AdminCreds
        Dependson = "[xRemoteFile]SpPfxCertFile"
    }

    Script SetCerticatePermission
    {
        GetScript = { 
            $Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -Argumentlist "MY", LocalMachine
            $Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
            $cert = $Store.Certificates | Where Thumbprint -eq $using:thumbprint
            $Store.Close()
            $path = "$($env:ProgramData)\Microsoft\Crypto\RSA\MachineKeys\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"
            @{Result = $path }
        }
        TestScript = { 
            $Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -Argumentlist "MY", LocalMachine
            $Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
            $cert = $Store.Certificates | Where Thumbprint -eq $using:thumbprint
            $Store.Close()
            $path = "$($env:ProgramData)\Microsoft\Crypto\RSA\MachineKeys\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"

            $acl = get-acl $path
            ($acl.Access | Where {$_.IdentityReference -eq $using:CertUserName}) -ne $null
        }
        SetScript = {
            $Store = New-Object System.Security.Cryptography.X509Certificates.X509Store -Argumentlist "MY", LocalMachine
            $Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
            $cert = $Store.Certificates | Where Thumbprint -eq $using:thumbprint
            $Store.Close()

            $PKFile = Get-ChildItem "$env:ProgramData\Microsoft\Crypto\RSA\MachineKeys\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"
            $PKAcl = $PKFile.GetAccessControl("Access")
            $ReadAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($using:CertUserName, [System.Security.AccessControl.FileSystemRights]::Read, [System.Security.AccessControl.AccessControlType]::Allow)
            $PKAcl.AddAccessRule($ReadAccessRule)
            Set-Acl $PKFile.FullName $PKAcl
        }
        DependsOn = "[Script]InstallPfxCert"
    }
}
twerthi commented 5 years ago

I wrote a module for this issue, https://github.com/twerthi/xCertificatePermission