Azure 部署的 Service Fabric 应用程序的 KeyVaultReference 支持

构建云应用程序时,常见的难题是搞清楚如何安全地将机密分发到应用程序并管理这些机密。 Service Fabric KeyVaultReference 支持可以让该过程变得简单。 配置该支持后,你可以引用 Key Vault 的应用程序定义中存储的机密 URL,Service Fabric 将提取该机密并使用它激活应用程序。 使用“SF 托管”版本的功能时,Service Fabric 还可以监视 Key Vault,并在轮换保管库中的机密时自动触发滚动式应用程序参数升级。

将机密传送到 Service Fabric 中的应用程序的选项

将机密传送到 Service Fabric 应用程序的经典方法是声明加密参数。 这涉及对加密证书加密机密和将这些加密机密传递给应用程序。 此方法有一些缺点:需要管理加密证书、在部署管道中泄露机密,以及无法查看附加到已部署应用程序的机密的元数据。 同样,轮换机密需要应用程序部署。 除非运行的是独立群集,否则我们不再建议使用加密参数。

另一个选项是使用机密存储引用。 通过此体验可以集中管理应用程序机密,更好地了解已部署机密的元数据,并且可以集中管理加密证书。 在运行独立 Service Fabric 群集时,有些人可能更喜欢这种机密管理风格。

当前的建议是尽可能使用 Service Fabric 应用程序的托管标识减少对机密的依赖。 托管标识可用于对 Azure 存储、Azure SQL 等直接进行身份验证。 这意味着,访问支持 Microsoft Entra 身份验证的 Azure 服务时,无需管理单独的凭据。

如果无法将托管标识作为客户端使用,我们建议使用 KeyVaultReferences。 应使用 KeyVaultReferences,而不是使用托管标识直接转到 Key Vault。 KeyVaultReferences 有助于提高应用程序的可用性,因为它会在滚动升级期间强制更改机密。 在缓存机密并从群集中提供机密时,它还会进行更好地进行缩放。 如果应用程序当前使用加密参数,则应用程序代码中只需极少更改即可使用 KeyVaultReferences。 应用程序可以继续期待获得单个机密,并且该机密在过程的生存期内是一样的。

先决条件

  • Service Fabric 应用程序的托管标识

    Service Fabric KeyVaultReference 支持使用应用程序的托管标识代表应用程序获取机密。 必须通过 ARM 部署应用程序,并为其分配托管标识。 可遵循此文档为应用程序启用托管标识。

  • 中心机密存储 (CSS)。

    中心机密存储 (CSS) 是 Service Fabric 的已加密本地机密缓存。 此功能使用 CSS 来保护和保留机密,并在从 Key Vault 中获取机密。 使用 KeyVaultReferences 则需要启用此系统服务。 遵循本文档来启用和配置 CSS。

  • 向应用程序的托管标识授予对 Key Vault 的访问权限

    参考此文档来了解如何向托管标识授予对 Key Vault 的访问权限。 另请注意,如果使用系统分配的托管标识,则只会在部署应用程序之后才创建托管标识。 这可能会产生争用条件,在这种情况下,应用程序将在授予标识对保管库的访问权限之前尝试访问机密。 系统分配的标识的名称将为 {cluster name}/{application name}/{service name}

KeyVaultReferences 与托管的 KeyVaultReferences

KeyVaultReferences 的基本思想不是将应用程序参数的值设置为机密,而是将其设置为 Key Vault URL,该 URL 随后在激活应用程序时解析为机密值。 例如,在 Key Vault 中,单个机密 https://my.vault.azure.cn/secrets/MySecret/ 可以有多个版本,例如 https://my.vault.azure.cn/secrets/MySecret/<oid1><oid2>。 使用 KeyVaultReference 时,该值应为带版本的引用 (https://my.vault.azure.cn/secrets/MySecret/<oid1>)。 例如,如果将保管库中的该机密轮换为 <oid2>,则应触发应用程序升级为新引用。 使用 ManagedKeyVaultReference 时,该值应为无版本的引用 (https://my.vault.azure.cn/secrets/MySecret/)。 Service Fabric 将解析最新的实例 <oid1>,并使用该机密激活应用程序。 如果将保管库中的机密轮换为 <oid2>,Service Fabric 将自动触发应用程序参数升级以代表你移动到 <oid2>

注意

从 Service Fabric 7.2 CU5 版本开始,Service Fabric 应用程序的 KeyVaultReference(带版本的机密)支持已正式发布。 建议在使用此功能之前升级到此版本。

备注

从 Service Fabric 9.0 开始,Service Fabric 应用程序的托管 KeyVaultReference(无版本的机密)支持已正式发布。

在应用程序中使用 KeyVaultReferences

可以使用 KeyVaultReferences

作为环境变量

<EnvironmentVariables>
      <EnvironmentVariable Name="MySecret" Type="KeyVaultReference" Value="<KeyVaultURL>"/>
</EnvironmentVariables>
string secret =  Environment.GetEnvironmentVariable("MySecret");

作为文件装载到容器中

  • 将一个节添加到 settings.xml

    定义类型为 KeyVaultReference、值为 <KeyVaultURL>MySecret 参数

    <Section Name="MySecrets">
        <Parameter Name="MySecret" Type="KeyVaultReference" Value="<KeyVaultURL>"/>
    </Section>
    
  • <ConfigPackagePolicies> 中引用 ApplicationManifest.xml 中的新节

    <ServiceManifestImport>
        <Policies>
        <IdentityBindingPolicy ServiceIdentityRef="MyServiceMI" ApplicationIdentityRef="MyApplicationMI" />
        <ConfigPackagePolicies CodePackageRef="Code">
            <!--Linux container example-->
    
            <ConfigPackage Name="Config" SectionName="MySecrets" EnvironmentVariableName="SecretPath" MountPoint="/var/secrets"/>
            <!--Windows container example-->
    
            <!-- <ConfigPackage Name="Config" SectionName="dbsecrets" EnvironmentVariableName="SecretPath" MountPoint="C:\secrets"/> -->
    
        </ConfigPackagePolicies>
        </Policies>
    </ServiceManifestImport>
    
  • 使用服务代码中的机密

    <Section Name=MySecrets> 下面列出的每个参数将是 EnvironmentVariable SecretPath 指向的文件夹下的某个文件。 下面的 C# 代码段演示如何从应用程序中读取 MySecret。

    string secretPath = Environment.GetEnvironmentVariable("SecretPath");
    using (StreamReader sr = new StreamReader(Path.Combine(secretPath, "MySecret"))) 
    {
        string secret =  sr.ReadToEnd();
    }
    

    备注

    MountPoint 控制将在其中装载包含机密值的文件的文件夹。

作为容器存储库密码的引用

 <Policies>
      <ContainerHostPolicies CodePackageRef="Code">
        <RepositoryCredentials AccountName="MyACRUser" Type="KeyVaultReference" Password="<KeyVaultURL>"/>
      </ContainerHostPolicies>

在应用程序中使用托管 KeyVaultReferences

首先,除了其他必需的 CSS 配置外,还必须通过升级群集定义来添加 EnableSecretMonitoring 设置以启用机密监视:

"fabricSettings": [
    {
        "name": "CentralSecretService",     
        "parameters": [
            {
                "name": "EnableSecretMonitoring",
                "value": "true"
            },
            {
                "name":  "DeployedState",
                "value":  "enabled"
            },
            {
                "name" : "EncryptionCertificateThumbprint",
                "value": "<thumbprint>"
            },
            {
                "name":  "MinReplicaSetSize",
                "value":  "<size>"
            },
            {
                "name":  "TargetReplicaSetSize",
                "value":  "<size>"
            }
        ]
    }
],

注意

默认值可能在将来变为 true

群集升级完成后,可以升级用户应用程序。 例如,在可以使用 KeyVaultReference 的任何位置,还可以使用 ManagedKeyVaultReference。

    <Section Name="MySecrets">
        <Parameter Name="MySecret" Type="ManagedKeyVaultReference" Value="[MySecretReference]"/>
    </Section>

在指定 ManagedKeyVaultReferences 中的主要区别在于,它们无法在应用程序类型清单中硬编码。 它们必须声明为应用程序级参数,并且必须在 ARM 应用程序定义中重写它们。

以下内容摘录自格式标准的清单

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest ApplicationTypeName="MyAppType" ApplicationTypeVersion="1.0.0">
  <Parameters>
    <Parameter Name="MySecretReference" DefaultValue="" />
  </Parameters>
  <ServiceManifestImport>
    <EnvironmentOverrides CodePackageRef="Code">
      <EnvironmentVariable Name="MySecret" Value="[MySecretReference]" Type="ManagedKeyVaultReference" />
    </EnvironmentOverrides>
    <Policies>
      <IdentityBindingPolicy ServiceIdentityRef="MySvcIdentity" ApplicationIdentityRef="MyAppIdentity" />
    </Policies>
  </ServiceManifestImport>
  <Principals>
    <ManagedIdentities>
      <ManagedIdentity Name="MyAppIdentity" />
    </ManagedIdentities>
  </Principals>
</ApplicationManifest>

和应用程序资源定义:

{
    "type": "Microsoft.ServiceFabric/clusters/applications",
    "name": "MyApp",
    "identity": {
        "type" : "userAssigned",
        "userAssignedIdentities": {
            "[variables('userAssignedIdentityResourceId')]": {}
        }
    },
    "properties": {
        "parameters": {
            "MySecretReference": "https://my.vault.azure.cn/secrets/MySecret/"
        },
        "managedIdentities": [
            {
            "name" : "MyAppIdentity",
            "principalId" : "<guid>"
            }
        ]
    }
}

将 ManagedKeyVaultReference 声明为应用程序参数,同时在部署时重写参数,这样 Service Fabric 才能成功管理已部署机密的生命周期。

后续步骤