Dismissile Dismissile - 11 months ago 115
C# Question

Install a certificate for a local cluster

I have some code to authenticate with Azure Key Vault in order to retrieve some secrets. I am authentication using a client id and certificate instead of a client id and secret. This code works great in a normal console app:

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly);

var matchingCertificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (matchingCertificates.Count != 1)
{
return null;
}

return matchingCertificates[0];
}
finally
{
if (store != null) store.Close();
}


As soon as I try using this code in a stateful service application it is no longer able to find the certificate.

How can I install a certificate so that it is available to my local cluster?

Answer Source

Service Fabric applications run under the NETWORK SERVICE account, so you'll need to make sure that account has access/permissions to the certificate.

EDIT:

For a cluster running on your local box you do that by finding the certificate either using certmgr.msc or the relevant mmc snap-in and then right click > All Tasks > Manage Private Keys and then giving read permissions to NETWORK SERVICE.

For remote clusters in Azure, you can do that using a custom script extension on the VMs of the scale set that will run a PowerShell script that sets up the permissions you want. For example, it could do something like the following:

$certificate = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -eq $certificateThumbprint}

# Get file path
$certificateFilePath = "C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys\" + $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName

# Take ownership of the file so that permissions can be set
takeown /F $certificateFilePath

# Give the NETWORK SERVICE read permissions
$acl = (Get-Item $certificateFilePath).GetAccessControl('Access')
$rule = new-object System.Security.AccessControl.FileSystemAccessRule "NETWORK SERVICE","Read","Allow"
$acl.SetAccessRule($rule)
Set-Acl -Path $certificateFilePath -AclObject $acl