Service Fabric:通过证书使用 Azure KeyVault 进行身份验证:"KeySet does not exist"

Service Fabric: Authenticating with Azure KeyVault via cert: "KeySet does not exist"

这是我要启用的场景:

我希望通过客户端证书从我的 Web 服务应用程序(azure 服务结构)向 azure keyvault 进行身份验证。

这些是我要执行的步骤:

  1. 将证书添加到我的 keyvault in azure(自签名)
  2. 通过 azure powershell (pfx) 下载证书
  3. 创建 Azure 应用程序实例以识别我的应用程序
  4. 将证书与应用相关联
  5. 为 Azure 应用程序创建服务主体
  6. 授予委托人访问密钥库的权限

一切看起来都不错。当我启动我的服务(本地服务结构集群)并尝试连接到 keyvault 以检索我存储在其中的密钥+值时,出现错误:

CryptographicException: "KeySet does not exist"

当我尝试在运行时检查 X509Certificate2 对象的 PrivateKey 属性 值时,它抛出相同的异常。

找到证书,并且私钥存在(我通过MMC以及一些命令行工具验证了这一点)。

我可以缺少什么?对于这种失败,我能想到的唯一原因是服务结构用户上下文(我认为是网络服务)没有查看私钥的权限?它存储在 "LocalMachine" 证书库中,在 Personal”文件夹(也称为 "My")。据我所知,应用程序应该能够在没有特殊权限的情况下从 LocalMachine 存储中读取?

好的,我的猜测是正确的。我明确授予 Network Service 用户(本地服务结构集群运行的用户上下文)访问私钥文件的权限。现在我可以使用 keyvault 进行身份验证了。

cacls.exe "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{private-key-filename}" /e /g "Network Service":R

我通过工具程序找到了私钥位置"FindPrivateKey.exe"

findprivatekey.exe My LocalMachine -t "{thumbprint}" -a

工具可以从https://www.microsoft.com/en-us/download/confirmation.aspx?id=21459

获得

(源代码示例位于目录\WCF\Setup\FindPrivateKey\CS\FindPrivateKey.sln,需要自行构建)

另一种更简单的方法来授予 NETWORK SERVICE 用户对证书私钥的权限(比我的其他答案更容易):

  1. 在 MMC 中打开证书管理单元:WIN + R -> 输入 mmc -> 文件 -> Add/Remove 管理单元 -> 添加证书 (计算机帐户)。
  2. 找到您的证书 -> 右键单击​​并选择所有 Tasks/Manage 私钥
  3. 授予NETWORK SERVICE用户Read权限

我 运行 遇到了同样的问题,g运行 对 Network Service 的读取权限对我有用。还有另一种方法 运行 运行 作为本地系统用户的高权限服务描述如下:

https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-run-script-at-service-startup

您可以将 Service Fabric ApplicationManifest.xml 修改为

  1. 定义本地机器对应的服务主体
  2. 使用该服务主体运行创建的服务结构包

最终 ApplicationManifest.xml 看起来像:

<?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">
  ...
  <ServiceManifestImport>
    ...
    <Policies>
      <RunAsPolicy CodePackageRef="Code" UserRef="LocalSystemUser" /> <!-- 2. run service fabric as defined principal -->
    </Policies>
  </ServiceManifestImport>

  <Principals>
    <Users>
      <User Name="LocalSystemUser" AccountType="LocalSystem" /> <!-- 1. define principal -->
    </Users>
  </Principals>
</ApplicationManifest>