0
votes

In my current ASP.NET Core project I'm using Azure Active Directory authentication with X509Certificate to access Key Vault. Certificate needs to be installed on a machine to allow application to access it and finally read values from Key Vault. Right now I'm working on migrating this application to Azure Service Fabric. I've uploaded the certificate to Key Vault, modified ARM template by adding:

"osProfile": {
    "secrets": [
        {
          "sourceVault": {
            "id": "{KeyVaultIdHere}"
          },
          "vaultCertificates": [
            {
              "certificateUrl": "{CertificateUrlHere}",
              "certificateStore": "My"
            }
          ]
        }
      ]
},

But when I deploy my application to Azure Service Fabric it seems like it doesn't have access to the certificate. Do I understand correctly that when I create cluster with such ARM template, certificate is being installed in LocalMachine\My Store? If yes, is it possible, that os user under which application is running doesn't have access to the private key of the ceritficate? When I was running cluster on my local computer I had to give special permission to ASF local cluster user to read private key. Maybe the same needs to be done for ASF on Azure? How can do it? Thanks in advance.

2
I've remoted to virtual machine from ASF cluster and it turned out that there are missing private key permissions on this certificate. But I can't manually set it, as "Administrators" have only "read" permission on this certificate. For this reason I will try to modify ARM template so it "unblocks" private key for NETWORK_SERVICE under which ASF cluster is running.Adam Sobaniec
ACLing for NETWORK_SERVICE should already be done automatically when provisioning certs. What's your code like for accessing KeyVault? Perhaps your methods are defaulting to look in cert:\currentuser\my, which of course is not correct for SF!Mardoxx
My methods are looking at localmachine/my store for sure. It works fine when I run ASF local cluster. Interesting is, what you mentioned, that NETWORK_SERVICE should have access to private key for such certificate installed using ARM template. Apparently, it doesn't. Only System has full access to it. There is also Administrators group mentioned, but only Read permission is there.Adam Sobaniec

2 Answers

1
votes

Ok, so the solution was to modify ARM template in such way that it gives access to certificate private key for NETWORK SERVICE user. To do this, one need to write proper powershell (like here: https://social.technet.microsoft.com/Forums/windowsserver/en-US/1557e379-26a8-46d0-bf26-d32176395085/how-to-grant-permission-to-private-key-from-powershell?forum=winserverpowershell) and attach CustomScriptExtension in ARM template (virtualMachineProfile/extensionProfile/extensions). It can be done only during ARM deployment, because for some reason Administrators have only Read access on a certificate installed via ARM template.

1
votes

Here is one of the application manifests from one of my applications.

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="S-Innovations.ServiceFabric.GatewayApplicationType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="GatewayService_InstanceCount" DefaultValue="-1" />
    <Parameter Name="AzureADServicePrincipal" DefaultValue="" />
    <Parameter Name="TenantId" DefaultValue="" />
    <Parameter Name="ApplicationStorageAccountId" DefaultValue="" />
    <Parameter Name="AzureResourceManagerCertThumbrint" DefaultValue="C03BB5A6410741CDD2927B4FF88C3E67215A393B" />
    <Parameter Name="Azure.KeyVault.Uri" DefaultValue="https://earthml-core-k3ci.vault.azure.net/" />
    <Parameter Name="ASPNETCORE_ENVIRONMENT" DefaultValue="Development" />
  </Parameters>
  <!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion 
       should match the Name and Version attributes of the ServiceManifest element defined in the 
       ServiceManifest.xml file. -->
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="S-Innovations.ServiceFabric.GatewayServicePkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides>
      <ConfigOverride Name="Config">
        <Settings>
          <Section Name="AzureResourceManager">
            <Parameter Name="AzureADServicePrincipal" Value="[AzureADServicePrincipal]" IsEncrypted="true" />
            <Parameter Name="TenantId" Value="[TenantId]" />
            <Parameter Name="ApplicationStorageAccountId" Value="[ApplicationStorageAccountId]" />
            <Parameter Name="Azure.KeyVault.Uri" Value="[Azure.KeyVault.Uri]" />
          </Section>
        </Settings>
      </ConfigOverride>
    </ConfigOverrides>
    <EnvironmentOverrides CodePackageRef="Code">
      <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="[ASPNETCORE_ENVIRONMENT]" />
    </EnvironmentOverrides>
    <Policies>
      <RunAsPolicy CodePackageRef="Code" UserRef="Admin" EntryPointType="All" />
    </Policies>
  </ServiceManifestImport>
  <DefaultServices>
    <!-- The section below creates instances of service types, when an instance of this 
         application type is created. You can also create one or more instances of service type using the 
         ServiceFabric PowerShell module.

         The attribute ServiceTypeName below must match the name defined in the imported ServiceManifest.xml file. -->
    <Service Name="GatewayService">
      <StatelessService ServiceTypeName="GatewayServiceType" InstanceCount="[GatewayService_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
    <Service Name="GatewayServiceManagerActorService" GeneratedIdRef="ef5ab963-c061-486e-bb1c-84bf1c2fc7e1|Persisted">
      <StatefulService ServiceTypeName="GatewayServiceManagerActorServiceType">
        <UniformInt64Partition PartitionCount="2" LowKey="-9223372036854775808" HighKey="9223372036854775807" />
      </StatefulService>
    </Service>
  </DefaultServices>
  <Principals>
    <Users>
      <User Name="Service1" AccountType="NetworkService" />
      <User Name="Admin">
        <MemberOf>
          <SystemGroup Name="Administrators" />
        </MemberOf>
      </User>
    </Users>
  </Principals>
  <Policies>
    <SecurityAccessPolicies>
      <SecurityAccessPolicy ResourceRef="MyCert" PrincipalRef="Service1" ResourceType="Certificate" />
    </SecurityAccessPolicies>
  </Policies>
  <Certificates>
    <SecretsCertificate X509FindValue="[AzureResourceManagerCertThumbrint]" Name="MyCert" />
  </Certificates>
</ApplicationManifest>

I been using that without any of the issues you mention that the application not having access to the certificate. Maybe this can help you making your arm scripts simpler :)