Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
本文介绍如何管理用于保护 Azure Service Fabric 群集中的通信的证书。 它是对 Service Fabric 群集安全性的补充和对 Service Fabric 中基于 X.509 证书的身份验证的说明。
先决条件
在开始之前,你应该熟悉基本的安全性概念和 Service Fabric 公开的用于配置群集安全性的控制措施。
免责声明
本文将证书管理的理论方面与涵盖服务、技术等具体细节的动手示例相结合。 由于这里的大部分受众都是Microsoft内部的,因此本文指的是特定于 Azure 的服务、技术和产品。 如果某些 Microsoft 特定的细节不适用于你的情况,可以随时在文章末尾的评论区寻求详细说明或相关指导。
定义证书管理
正如你在本文的姊妹篇 Service Fabric 群集中基于 X.509 证书的身份验证中了解到的那样,证书是一个加密对象,它实质上会将非对称密钥对与描述其所表示的实体的属性绑定。
但是,证书也是一个“易变质”对象,因为它的生存期有限并且容易遭到攻击。 从安全的角度来看,意外泄露或成功攻击可能会使证书变得无用。 此特性意味着需要定期更改证书或针对响应安全事件更改证书。
证书管理的另一个方面(也是一个完全独立的主题)是保护证书私钥或机密,这些私钥或机密保护那些涉及证书获得和预配过程的实体的标识。
我们将“证书管理”描述为用于获取证书并将它们安全可靠地传输到需要这些证书的位置的流程和过程。
某些管理操作(例如注册、策略设置和授权控制)不在本文的讨论范围内。 其他操作(如预配、续订、重新生成或吊销)仅与 Service Fabric 有间接关系。 尽管如此,本文还是会大致介绍一下这些内容,因为了解这些操作可以帮助你正确保护群集。
你的直接目标很可能是尽可能地实现证书管理自动化,以便确保群集的不间断可用性。 由于该过程无需用户接触,因此还需要提供安全性保证。 使用 Service Fabric 群集,可以实现此目标。
本文的其余部分首先解构证书管理,然后重点介绍如何启用自动滚动更新。
具体来说,它涵盖以下主题:
- 关于所有者和平台之间的属性分离的假设
- 证书从颁发到使用的长流程
- 证书轮换:原因、方式和时间
- 可能会出什么错?
本文未涵盖以下主题:
- 保护和管理域名
- 报名参加证书课程
- 设置授权控件以强制实施证书颁发。
有关这些主题的信息,请参阅你最喜欢的公钥基础结构 (PKI) 服务的注册机构 (RA)。 如果你是 Microsoft 内部人员,可以联系 Azure 安全团队。
证书管理中涉及的角色和实体
Service Fabric 群集中的安全方法是“群集所有者声明它,Service Fabric 运行时强制执行它”的一个例子。这意味着参与群集运行的所有证书、密钥或其他标识凭据几乎都不来自该服务本身。 它们都是由群集所有者声明的。 群集所有者还负责将证书预配到群集中,根据需要续订这些证书,并且始终帮助确保其安全性。
更具体地说,群集所有者必须确保:
Service Fabric 自身将承担以下职责:
- 定位与群集定义中的声明匹配的证书
- 根据实际需要,向 Service Fabric 控制的实体授予相应私钥的访问权限
- 严格按照已制定的安全性最佳做法和群集定义来验证证书
- 在证书即将过期或无法执行基本的证书验证步骤时发出警报
- (在一定程度上)验证主机的基础配置是否满足群集定义中与证书相关的方面的要求
由此可见,证书管理负担(以活动操作的形式)完全落在群集所有者身上。 后续部分将详细介绍每个管理操作,包括可用机制及其对群集的影响。
证书的历程
让我们快速概述一下在 Service Fabric 群集环境中证书从颁发到使用的整个过程:
域所有者向 PKI 的 RA 注册他们希望与后续证书关联的域名或主体。 这些证书继而构成该域名或主体的所有权凭证。
域所有者还在 RA 中指定授权请求者的身份,即有权请求注册特定域或主体的证书的实体。
然后,获得授权的请求者通过机密管理服务注册到证书中。 在 Azure 中,所选的机密管理服务为 Azure Key Vault,它可以安全地存储机密和证书并允许获得授权的实体检索它们。 Key Vault 还会根据关联证书策略,续订并重新更新证书的密钥。 Key Vault 使用 Microsoft Entra ID 作为标识提供者。
获得授权的检索者(也称为预配代理)会从密钥保管库中检索证书(包括其私钥),并将其安装在用于托管群集的计算机上。
Service Fabric 服务(在每个节点上以提升的权限运行)将证书访问权限授予那些被授权的 Service Fabric 实体;这些实体由本地组指定,并划分为 ServiceFabricAdministrators 和 ServiceFabricAllowedUsers。
Service Fabric 运行时会访问并使用证书来建立联合身份验证,或者对获得授权的客户端发出的入站请求进行身份验证。
预配代理监视密钥保管库证书,并在检测到续订时触发预配流程。 然后,群集所有者会根据需要更新群集定义,以指示更新证书的意图。
预配代理或群集所有者还负责清除和删除未使用的证书。
就本文而言,上述序列中的前两个步骤大多是不相关的。 它们唯一的关联是,证书的使用者公用名称是在群集定义中声明的 DNS 名称。
证书颁发和预配流程如下图所示:
对于通过指纹声明的证书
对于凭借主体通用名称声明的证书
证书申请
Key Vault 文档中详细介绍了证书注册这一主题。 此处提供了一个概要,用于实现连续性和更容易进行参考。
在继续使用 Azure 的情况下,如果使用 Key Vault 作为机密管理服务,则获得授权的证书请求者必须至少具有密钥保管库所有者授予的对密钥保管库的证书管理权限。 随后,请求者按照以下步骤申请证书:
请求者在 Key Vault 中创建证书策略,该策略指定证书的域/使用者、所需的颁发者、密钥类型和长度、预期的密钥用法,等等。 有关详细信息,请参阅 Azure Key Vault 中的证书。
请求者使用在上一步中指定的策略在同一保管库中创建证书。 此过程生成一个密钥对作为保管库对象,以及一个使用私钥签名的证书签名请求,然后将该请求转发给指定的颁发者以进行签名。
在证书颁发者(也称为证书颁发机构 (CA))回复签名证书后,结果将被整合到密钥保管库中,证书数据可如下使用:
- 在
{vaultUri}/certificates/{name}下:包含公钥和元数据的证书 - 在
{vaultUri}/keys/{name}下:证书的私钥,可用于加密操作(包装/解包、签名/验证) - 在
{vaultUri}/secrets/{name}下:包含私钥的证书,可作为不受保护的 PFX 或 PEM 文件下载。
- 在
请回想一下,密钥保管库中的证书包含按时间顺序排列的共享策略的证书实例列表。 证书版本根据此策略的生存期和续订属性创建。 强烈建议不要让保管库证书共享使用者、域或 DNS 名称,因为在一个群集中,若要从不同的保管库证书预配证书实例,并且这些证书的使用者相同,但其他属性(例如颁发者、密钥用法等)却存在实质性的差异,则可能会造成中断。 此时,密钥保管库中存在一个可供使用的证书。 现在让我们探索该过程的其余部分。
证书预配
我们提到过“预配代理”,这是一个实体,用于从密钥保管库检索证书(包括其私钥),并将其安装在群集的每个主机上。 (请回想一下,Service Fabric 不预配证书。)
在本文的上下文中,群集将托管在 Azure 虚拟机 (VM) 或虚拟机规模集的集合上。 在 Azure 中,可使用以下机制将证书从保管库预配到 VM/VMSS。 与之前一样,这假定预配代理先前已由密钥保管库所有者授予对密钥保管库的获取权限。
即席:操作员从密钥保管库中检索证书(以 PFX/PKCS #12 或 PEM 的形式),并将其安装在每个节点上。
出于多种原因(包括从安全性到可用性在内的各种原因),不建议使用即席机制,我们在这里不对其进行进一步的讨论。 有关详细信息,请参阅 Azure 虚拟机规模集常见问题解答。
在部署过程中,作为虚拟机规模集的 机密:计算服务使用第一方标识,代表运维人员从启用了模板部署的保管库中检索证书,并将其安装在虚拟机规模集的每个节点上,如Azure 虚拟机规模集常见问题解答中所述。
注意
此方法仅允许预配进行了版本控制的机密。
通过使用 Key Vault VM 扩展, 这可让你使用无版本声明来预配证书,并定期刷新观察到的证书。 在这种情况下,VM/VMSS 应该有一个托管标识,该标识已被授予对包含观察到的证书的密钥保管库的访问权限。
基于 VMSS/计算的预配具有安全性和可用性方面的优势,但也存在限制。 根据设计,它要求将证书声明为进行版本控制的机密。 此要求使基于 VMSS/计算的预配仅适用于使用由指纹声明的证书进行保护的群集。
相比之下,基于 Key Vault VM 扩展的配置总是安装每个观察到的证书的最新版本,因此它仅适用于通过使用者公用名声明的证书保护的集群。 不要对由实例声明(即通过指纹)的证书使用自动刷新预配机制(例如 Key Vault VM 扩展)。 失去可用性的风险非常大。
还存在其他预配机制,但此处提到的方法是 Azure Service Fabric 群集当前接受的选项。
证书的消耗和监控
如前所述,Service Fabric 运行时负责查找和使用在群集定义中声明的证书。 Service Fabric 群集中基于 X.509 证书的身份验证一文详细介绍了 Service Fabric 如何实现出示和验证规则,此处不再赘述。 本文将介绍访问和权限授予和监视。
请回想一下,Service Fabric 中的证书用于多种目的,从联合层中的相互身份验证到管理终结点的传输层安全性 (TLS) 身份验证,不一而足。 这需要不同的组件或系统服务才能访问证书的私钥。 Service Fabric 运行时会定期扫描证书存储,并查找每个已知出示规则的匹配项。
对于每个匹配的证书,都会找到相应的私钥,并更新其自定义访问控制列表,以包括授予需要这些权限的标识的权限(通常为读取和执行)。
此过程被非正式地称为“ACLing”。 该过程每分钟运行一次,还涵盖应用证书,例如用于加密设置的证书或终端点证书。 ACLing 遵循出示规则,因此请务必记住:通过指纹声明的证书和未进行后续群集配置更新的自动刷新的证书将不可访问。
证书轮换
注意
Internet 工程任务组 (IETF) RFC 3647 正式将续订定义为颁发与要替换的证书具有相同属性的证书。 颁发者、使用者的公钥和信息将被保留。 重新生成密钥 是颁发具有新密钥对的证书,而没有限制颁发者是否可以更改。 由于区别可能很重要(试想一下在颁发者固定的情况下通过使用者公用名称来声明证书),本文使用中性术语“轮换”来涵盖这两种场景。 请记住,在非正式使用 续订 时,它是指 重新生成密钥。
如前所述,Key Vault 支持自动证书轮换。 也就是说,关联证书策略定义了在密钥保管库中证书轮换的时间点,这可以是证书到期前的天数或其总生存期的百分比。 必须在此时间点之后、现在的旧证书过期之前调用预配代理,然后才能将此新证书分发到群集的所有节点。
Service Fabric 通过在群集中当前正在使用的证书的到期日期早于预先确定的间隔发生时引发运行状况警告来帮助此过程。 配置为观察密钥保管库证书的自动预配代理(Key Vault VM 扩展)会定期轮询密钥保管库,检测轮换,并检索和安装新证书。 通过 VM/VMSS 的“机密”功能执行预配时,需要一位获得授权的操作员使用与新证书对应的版本化 Key Vault URI 来更新 VM/VMSS。
现已将轮换后的证书预配给了所有节点。 现在,假设应用于群集证书的轮换是由使用者公用名称声明的,让我们看看接下来会发生什么:
对于群集内部和传入的新连接,Service Fabric 运行时会查找并选择最近颁发的匹配证书( NotBefore 属性的最大值)。 这是对早期版本的 Service Fabric 运行时的更改。
现有连接将保持活动状态,或以自然方式过期或终止,内部处理程序会收到通知已存在新的匹配项。
注意
目前,对于 7.2 CU4 版本及更高版本,Service Fabric 选择具有最大(最近颁发的)NotBefore 属性值的证书。 在 7.2 CU4 之前的版本中,Service Fabric 会选择有效证书中 "NotAfter"(失效日期)值为最大(到期最晚)的证书。
这将转换为以下重要观察结果:
群集或托管的应用程序的可用性优先于用于轮换证书的指令。 群集最终会聚合到新证书上,但没有计时保证。 结果就是:
观察者可能无法立即看出替换后的证书已完全取代其前身。 强制立即替换当前使用的证书的唯一方法是重新启动主机。 重启 Service Fabric 节点是不够的,因为构成群集中租约连接的内核模式组件不受影响。 另请注意,重启 VM/VMSS 可能会导致暂时丢失可用性。 对于应用程序证书,只需重启各自的应用程序实例即可。
引入不符合验证规则的重密钥证书将会中断群集。 这方面最常见的示例是出现意外的颁发者:群集证书是在颁发者固定的情况下通过使用者公用名称来声明的,但轮换后的证书是由新的或未声明的颁发者颁发的。
证书清理
目前,Azure 中没有可以显式删除证书的预配。 确定特定证书是否在特定时间使用通常是一项非琐碎的任务。 相比于群集证书,应用程序证书更加难以进行上述确定。 Service Fabric 本身(而不是预配代理)在任何情况下都不会删除由用户声明的证书。 对于标准预配机制来说,会出现以下情况:
只要声明为 VM/VMSS 机密的证书在 VM/VMSS 定义中被引用并且可以从密钥保管库中检索,它们就会被预配。 如果删除了密钥保管库机密或证书,将使后续 VM/VMSS 部署失败。 同样,如果禁用密钥保管库中的机密版本,也会使引用该机密版本的 VM/VMSS 部署失败。
通过 Key Vault VM 扩展预配的早期版本的证书不一定存在于 VM/VMSS 节点上。 代理仅检索并安装当前版本,它不会删除任何证书。 重映像一个通常每月会发生的节点,会将证书存储重置为操作系统映像的内容,因此较早版本的证书将被隐式删除。 请注意,扩大虚拟机规模集将仅导致安装的只是当前的已观察到的证书版本。 请勿假设节点在已安装证书方面的同质性。
简化管理:自动续期示例
到目前为止,本文已经介绍了各种机制、限制,概述了复杂的规则和定义,并对中断进行了极端预测。 现在是时候设置自动证书管理来避免所有这些问题了。 让我们在平台即服务 (PaaS) v2 虚拟机规模集上运行的 Azure Service Fabric 群集的上下文中执行此操作,使用 Key Vault 进行机密管理,并利用托管标识,如下所示:
- 证书的验证从指纹固定更改为使用者 + 颁发者固定。 来自特定颁发者的具有特定主题的任何证书都同样受信任。
- 证书的注册和获取在受信任的存储 (Key Vault) 中进行,并由代理(此处为 Key Vault VM 扩展)进行刷新。
- 证书的预配不再在部署时进行,也不再基于版本(像 Azure 计算资源提供程序那样),而是使用无版本的 Key Vault URI 在部署后进行。
- 通过用户分配的托管身份授予对密钥保管库的访问权限,这些托管身份是在部署期间创建并分配给虚拟机缩放集的。
- 部署后,代理(Key Vault VM 扩展)轮询并刷新在虚拟机规模集的每个节点上观察到的证书。 因此,证书轮换是完全自动化的,因为 Service Fabric 会自动获取最新的有效证书。
此序列可以完全脚本化和自动化,它可以在不让用户接触的情况下对某个已配置为证书自动滚动更新的群集进行初始部署。 后续部分提供了详细的步骤,其中包含混合使用 PowerShell cmdlet 和 JSON 模板的片段。 可以使用与 Azure 交互时所有支持的方法来实现相同的功能。
注意
此示例假定密钥保管库中已存在证书。 如本文前面所述,注册和续订 Key Vault 管理的证书需要先手动完成一些前提步骤。 对于生产环境,请使用 Key Vault 管理的证书。 我们包含了一个特定于 Microsoft 内部 PKI 的示例脚本。
注意
证书自动滚动更新仅适用于 CA 颁发的证书。 使用自签名证书(包括那些在 Azure 门户中部署 Service Fabric 群集期间生成的证书)毫无意义,但如果声明颁发者指纹与叶证书的指纹相同,则对于本地或开发人员托管的部署仍然适用。
起点
为了简单起见,让我们假定采用以下开始状态:
- Service Fabric 群集存在,并使用通过指纹声明的 CA 颁发的证书进行保护。
- 此证书存储在密钥库中,并作为虚拟机规模集的机密进行预配。
- 将使用同一证书将群集转换为基于通用名称的证书声明,以便可由使用者和颁发者对其进行验证。 如果不是这种情况,请获取用于此目的的 CA 颁发的证书,并通过指纹将其添加到群集定义中。 在 Azure 中为 Service Fabric 群集添加或删除证书中介绍了此过程。
下面是来自对应于此类状态的模板的 JSON 摘录。 此摘录省略了许多必需的设置,仅说明了与证书相关的内容。
"resources": [
{ ## VMSS definition
"apiVersion": "[variables('vmssApiVersion')]",
"type": "Microsoft.Compute/virtualMachineScaleSets",
"name": "[variables('vmNodeTypeName')]",
"location": "[variables('computeLocation')]",
"properties": {
"virtualMachineProfile": {
"extensionProfile": {
"extensions": [
{
"name": "[concat('ServiceFabricNodeVmExt','_vmNodeTypeName')]",
"properties": {
"type": "ServiceFabricNode",
"autoUpgradeMinorVersion": true,
"publisher": "Microsoft.Azure.ServiceFabric",
"settings": {
"clusterEndpoint": "[reference(parameters('clusterName')).clusterEndpoint]",
"nodeTypeRef": "[variables('vmNodeTypeName')]",
"dataPath": "D:\\SvcFab",
"durabilityLevel": "Bronze",
"certificate": {
"thumbprint": "[parameters('primaryClusterCertificateTP')]",
"x509StoreName": "[parameters('certificateStoreValue')]"
}
},
"typeHandlerVersion": "1.1"
}
},}},
"osProfile": {
"adminPassword": "[parameters('adminPassword')]",
"adminUsername": "[parameters('adminUsername')]",
"secrets": [
{
"sourceVault": {
"id": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
},
"vaultCertificates": [
{
"certificateStore": "[parameters('certificateStoreValue')]",
"certificateUrl": "[parameters('clusterCertificateUrlValue')]"
},
]}]
},
},
{ ## cluster definition
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters",
"name": "[parameters('clusterName')]",
"location": "[parameters('clusterLocation')]",
"certificate": {
"thumbprint": "[parameters('primaryClusterCertificateTP')]",
"x509StoreName": "[parameters('certificateStoreValue')]"
},
}
]
上述代码实质上表示,在 Key Vault URI json [parameters('primaryClusterCertificateTP')] 中找到的具有指纹 json [parameters('clusterCertificateUrlValue')] 的证书已通过指纹声明为群集的唯一证书。
接下来,让我们设置所需的其他资源,以确保证书的自动轮换。
设置必备资源
如前所述,作为虚拟机规模集机密预配的证书由 Azure 计算资源提供程序服务从密钥保管库中检索。 它通过代表部署操作员使用其第一方标识来实现此目标。 此过程将因自动续期而变化。 将改为使用分配给虚拟机规模集的托管标识,并且该标识拥有对保管库中机密的 GET 权限。
应同时部署下一个摘录。 它们被单独列出,仅供详细分析和说明。
首先定义一个用户分配的标识(包含默认值作为示例)。 有关详细信息,请参阅官方文档。
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"userAssignedIdentityName": {
"type": "string",
"defaultValue": "sftstuaicus",
"metadata": {
"description": "User-assigned managed identity name"
}
},
},
"variables": {
"vmssApiVersion": "2018-06-01",
"sfrpApiVersion": "2018-02-01",
"miApiVersion": "2018-11-30",
"kvApiVersion": "2018-02-14",
"userAssignedIdentityResourceId": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]"
},
"resources": [
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[parameters('userAssignedIdentityName')]",
"apiVersion": "[variables('miApiVersion')]",
"location": "[resourceGroup().location]"
},
]}
接下来,授予此标识对密钥保管库机密的访问权限。 有关最新信息,请参阅官方文档。
"resources":
[{
"type": "Microsoft.KeyVault/vaults/accessPolicies",
"name": "[concat(parameters('keyVaultName'), '/add')]",
"apiVersion": "[variables('kvApiVersion')]",
"properties": {
"accessPolicies": [
{
"tenantId": "[reference(variables('userAssignedIdentityResourceId'), variables('miApiVersion')).tenantId]",
"objectId": "[reference(variables('userAssignedIdentityResourceId'), variables('miApiVersion')).principalId]",
"dependsOn": [
"[variables('userAssignedIdentityResourceId')]"
],
"permissions": {
"secrets": [
"get",
"list"
]}}]}}]
在下一步中,你将执行以下操作:
- 将用户分配的标识分配给虚拟机规模集。
- 声明虚拟机规模集对托管标识创建以及授予其密钥保管库访问权限结果的依赖性。
- 声明 Key Vault VM 扩展,并要求它在启动时检索观察到的证书。 有关详细信息,请参阅适用于 Windows 的 Key Vault VM 扩展官方文档。
- 更新 Service Fabric VM 扩展的定义,具体取决于 Key Vault VM 扩展,并将群集证书声明从指纹转换为公用名称。
注意
这些更改是作为一个步骤进行的,因为它们属于同一资源的范围。
"parameters": {
"kvvmextPollingInterval": {
"type": "string",
"defaultValue": "3600",
"metadata": {
"description": "kv vm extension polling interval in seconds"
}
},
"kvvmextLocalStoreName": {
"type": "string",
"defaultValue": "MY",
"metadata": {
"description": "kv vm extension local store name"
}
},
"kvvmextLocalStoreLocation": {
"type": "string",
"defaultValue": "LocalMachine",
"metadata": {
"description": "kv vm extension local store location"
}
},
"kvvmextObservedCertificates": {
"type": "array",
"defaultValue": [
"https://sftestcus.vault.azure.cn/secrets/sftstcncluster",
"https://sftestcus.vault.azure.cn/secrets/sftstcnserver"
],
"metadata": {
"description": "kv vm extension observed certificates versionless uri"
}
},
"certificateCommonName": {
"type": "string",
"defaultValue": "cus.cluster.sftstcn.system.servicefabric.azure-int",
"metadata": {
"description": "Certificate Common name"
}
},
},
"resources": [
{
"apiVersion": "[variables('vmssApiVersion')]",
"type": "Microsoft.Compute/virtualMachineScaleSets",
"name": "[variables('vmNodeTypeName')]",
"location": "[variables('computeLocation')]",
"dependsOn": [
"[variables('userAssignedIdentityResourceId')]",
"[concat('Microsoft.KeyVault/vaults/', concat(parameters('keyVaultName'), '/accessPolicies/add'))]"
],
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[variables('userAssignedIdentityResourceId')]": {}
}
},
"virtualMachineProfile": {
"extensionProfile": {
"extensions": [
{
"name": "KVVMExtension",
"properties": {
"publisher": "Microsoft.Azure.KeyVault",
"type": "KeyVaultForWindows",
"typeHandlerVersion": "1.0",
"autoUpgradeMinorVersion": true,
"settings": {
"secretsManagementSettings": {
"pollingIntervalInS": "[parameters('kvvmextPollingInterval')]",
"linkOnRenewal": false,
"observedCertificates": "[parameters('kvvmextObservedCertificates')]",
"requireInitialSync": true
}
}
}
},
{
"name": "[concat('ServiceFabricNodeVmExt','_vmNodeTypeName')]",
"properties": {
"type": "ServiceFabricNode",
"provisionAfterExtensions" : [ "KVVMExtension" ],
"publisher": "Microsoft.Azure.ServiceFabric",
"settings": {
"certificate": {
"commonNames": [
"[parameters('certificateCommonName')]"
],
"x509StoreName": "[parameters('certificateStoreValue')]"
}
},
"typeHandlerVersion": "1.0"
}
},
] } ## extension profile
}, ## VM profile
"osProfile": {
"adminPassword": "[parameters('adminPassword')]",
"adminUsername": "[parameters('adminUsername')]",
}
}
]
虽然未在上述代码中显式列出,但请注意,密钥保管库证书 URL 已从虚拟机规模集的 OsProfile 部分中删除。
最后一步是更新群集定义,将证书声明从指纹更改为公用名称。 我们还将绑定颁发者指纹:
"parameters": {
"certificateCommonName": {
"type": "string",
"defaultValue": "cus.cluster.sftstcn.system.servicefabric.azure-int",
"metadata": {
"description": "Certificate Common name"
}
},
"certificateIssuerThumbprint": {
"type": "string",
"defaultValue": "1b45ec255e0668375043ed5fe78a09ff1655844d,d7fe717b5ff3593764f4d90654d86e8362ec26c8,3ac7c3cac8de0dd392c02789c8be97474f456960,96ea05926e2e42cc207e358668be2c316857fb5e",
"metadata": {
"description": "Certificate issuer thumbprints separated by comma"
}
},
},
"resources": [
{
"apiVersion": "[variables('sfrpApiVersion')]",
"type": "Microsoft.ServiceFabric/clusters",
"name": "[parameters('clusterName')]",
"location": "[parameters('clusterLocation')]",
"properties": {
"certificateCommonNames": {
"commonNames": [{
"certificateCommonName": "[parameters('certificateCommonName')]",
"certificateIssuerThumbprint": "[parameters('certificateIssuerThumbprint')]"
}],
"x509StoreName": "[parameters('certificateStoreValue')]"
},
]
此时,你可以在单个部署中运行前面提到的更新。 Service Fabric 资源提供程序服务就其而言会将群集升级划分为几个步骤,这在将群集证书从指纹转换为公用名称一节中有详细描述。
分析和观察
本部分概述了本文中所介绍的概念和过程,并引吸引了人们对某些其他重要方面的兴趣。
关于证书预配
作为预配代理的 Key Vault VM 扩展以预定的频率连续运行。 如果无法检索到观察到的证书,它会继续尝试下一个证书,然后休眠直到下一个周期。 作为群集启动代理的 Service Fabric VM 扩展需要声明的证书,否则群集无法形成。 这反过来意味着,Service Fabric VM 扩展只能在成功检索群集证书之后运行,在此处由 json "provisionAfterExtensions" : [ "KVVMExtension" ]" 子句表示,以及由 Key Vault VM 扩展的 json "requireInitialSync": true 设置表示。
这是向 Key Vault VM 扩展指示:首次运行时(在部署或重启后)必须循环访问其观察到的证书,直到全部下载成功。 如果将此参数设置为“false”,则在检索群集证书失败的情况下,群集部署也会失败。 相反,如果在要求初始同步时所使用的已观察到的证书的列表不正确或无效,则会导致 Key Vault VM 扩展失败,并再次导致群集部署失败。
证书链接(已介绍)
你可能已注意到 Key Vault VM 扩展 linkOnRenewal 标志,以及它已设置为 false 这一事实。 此设置将探讨此标志控制的行为及其对群集功能的影响。 此行为特定于 Windows。
根据其定义:
"linkOnRenewal": <Only Windows. This feature enables auto-rotation of SSL certificates, without necessitating a re-deployment or binding. e.g.: false>,
用于建立 TLS 连接的证书通常通过 Schannel 安全支持提供程序作为句柄获取。 也就是说,客户端不直接访问证书本身的私钥。 Schannel 支持以证书扩展 CERT_RENEWAL_PROP_ID 的形式重定向或链接凭据。
如果设置了此属性,则其值表示续订证书的指纹,因此 Schannel 将改为尝试加载链接的证书。 事实上,S通道会遍历这个链接的列表(希望是无循环的),直到最终找到没有续订标记的最终证书。 如果使用得当,此功能可以很好地缓解因证书过期等原因导致的可用性损失。
在其他情况下,它可能引起难以诊断和应对的故障。 S 通道无条件地执行证书在其续订属性上的遍历,而不考虑主题、颁发者或用于客户端验证的结果证书的其他特定属性。 生成的证书可能没有关联的私钥,或者该密钥尚未被 ACL 授予其预期使用者。
如果启用了链接,则 Key Vault VM 扩展在从密钥保管库检索观察到的证书时,将尝试查找匹配的现有证书,以便通过续订扩展属性来链接它们。 匹配仅基于主题备用名称 (SAN),如果有两个现有证书,则匹配有效,如以下示例所示:A: 证书名称 (CN) = "Alice's accessories",SAN = {"alice.universalexports.com"},更新 = '' B: CN = "Bob's bits",SAN = {"bob.universalexports.com", "bob.universalexports.net"},更新 = ''
假设证书 C 通过 Key Vault VM 扩展检索:CN = "Mallory's malware", SAN = {"alice.universalexports.com", "bob.universalexports.com", "mallory.universalexports.com"}
证书 A 的 SAN 列表完全包含在 C 的 SAN 列表中,因此 A.renewal = C.thumbprint。 证书 B 的 SAN 列表与 C 的 SAN 列表有交集,但未完全包含在其中,因此 B.renewal 保持为空。
在使用证书 A 时,在此状态下调用 AcquireCredentialsHandle (S-channel) 的任何尝试实际上最终都会将 C 发送到远程方。 在使用 Service Fabric 的情况下,群集的传输子系统使用 S-channel 进行相互身份验证,因此上述行为直接影响群集的基本通信。 继续前面的示例,假设 A 是群集证书,接下来发生的情况取决于:
- 如果 C 的私钥没有加入访问控制列表(ACL)到 Service Fabric 所运行的账户,你会看到无法获取私钥的错误(SEC_E_UNKNOWN_CREDENTIALS 或类似错误)。
- 如果 C 的私钥可访问,则会看到其他节点返回的授权失败(CertificateNotMatched、未授权等)。
在任一情况下,传输都会失败,群集可能会关闭。 具体表现各不相同。 更糟糕的是,链接取决于续订顺序,而续订顺序取决于 Key Vault VM 扩展中已观察到的证书的列表顺序、密钥保管库中的续订计划或甚至那些会改变检索顺序的暂时性错误。
若要缓解此类事件,我们建议你采取以下措施:
不要混淆不同密钥库证书的主题备用名称。 每个存储库证书应具备明确的用途,其主题和 SAN 应通过具体的特性反映出这一点。
在 SAN 列表中包括主题通用名称(即字面意思:
CN=<subject common name>)。如果您不确定如何进行,在更新通过 Key Vault VM 扩展预配的证书时禁用链接。
注意
禁用链接是 Key Vault VM 扩展的顶级属性,不能为单个观察到的证书设置。
为什么应使用用户分配的托管标识? 使用它会产生什么影响?
从前面的 JSON 片段可以明显看出,需要对操作和更新进行特定的排序,才能保证转换成功并维护群集的可用性。 具体而言,虚拟机规模集资源会声明并使用其标识在单个(从用户的角度来看)更新中检索机密。
用于启动群集的 Service Fabric VM 扩展取决于 Key Vault VM 扩展是否完成,而这又取决于观察到的证书是否成功检索。
Key Vault VM 扩展使用虚拟机规模集的标识来访问密钥保管库,这意味着在部署虚拟机规模集之前,密钥保管库上的访问策略必须已更新。
若要处理托管标识的创建或将其分配给其他资源,部署操作员除了需要订阅或资源组中的必需角色 (ManagedIdentityOperator) 外,还必须具有管理模板中引用的其他资源所需的角色。
从安全性角度来看,回想一下,可以将虚拟机规模集视为与其 Azure 标识相关的安全边界。 这意味着托管在 VM 上的任何应用程序原则上都可以获得表示 VM 的访问令牌。 托管标识访问令牌是从未经身份验证的实例元数据服务终结点获取的。 如果认为 VM 是共享环境或多租户环境,则可能不会指示检索群集证书的此方法。 不过,它是适用于证书自动滚动更新的唯一预配机制。
故障排除和常见问题解答
问:如何以编程方式注册到 Key Vault 托管的证书?
找到 Key Vault 文档中的颁发者名称,然后将其替换为以下脚本:
$issuerName=<depends on your PKI of choice>
$clusterVault="sftestcus"
$clusterCertVaultName="sftstcncluster"
$clusterCertCN="cus.cluster.sftstcn.system.servicefabric.azure-int"
Set-AzKeyVaultCertificateIssuer -VaultName $clusterVault -Name $issuerName -IssuerProvider $issuerName
$distinguishedName="CN=" + $clusterCertCN
$policy = New-AzKeyVaultCertificatePolicy `
-IssuerName $issuerName `
-SubjectName $distinguishedName `
-SecretContentType 'application/x-pkcs12' `
-Ekus "1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.2" `
-ValidityInMonths 4 `
-KeyType 'RSA' `
-RenewAtPercentageLifetime 75
Add-AzKeyVaultCertificate -VaultName $clusterVault -Name $clusterCertVaultName -CertificatePolicy $policy
# poll the result of the enrollment
Get-AzKeyVaultCertificateOperation -VaultName $clusterVault -Name $clusterCertVaultName
问:如果证书是由未声明或未指定的颁发者颁发的,会发生什么情况? 在哪里可以获取指定 PKI 的活动颁发者的详尽列表?
如果证书声明指定颁发者指纹,并且证书的直接颁发者未包含在固定颁发者列表中,则证书被视为无效,无论其根是否受客户端信任。 因此,必须确保颁发者列表是最新的,这一点非常重要。 引入新的颁发者是一种罕见事件,应在开始颁发证书之前广而告之。
通常情况下,根据 IETF RFC 7382 的要求,PKI 会发布和维护认证实践声明。 除其他信息外,该声明还包括所有活跃的发行者。 以编程方式检索此列表可能因 PKI 不同而异。
对于微软内部 PKI,请务必查阅相关用于获取授权颁发者的终端和 SDK 的内部文档。 群集所有者负责定期查看此列表,以确保其群集定义包括 所有 预期的颁发者。
问:是否支持多个 PKI?
是的。 你不能在群集清单中用相同的值声明多个 CN 项,但可以列出与同一 CN 对应的多个 PKI 中的颁发者。 建议不要这样做,证书透明度规范可能会阻止颁发此类证书。 然而,作为一种从一个 PKI 迁移到另一个 PKI 的方法,这是一种可接受的机制。
问:如果当前群集证书不是由 CA 颁发的,或者没有所需的使用者,该怎么办?
获取具有预期主题的证书,并通过指纹将其作为次要证书添加到群集的定义中。 升级成功完成后,再次启动群集配置升级,以将证书声明转换为公用名称。