如何使用 API 管理中的客户端证书身份验证确保 API 安全
适用于:所有 API 管理层级
API 管理提供的功能可确保使用客户端证书和相互 TLS 身份验证安全地访问 API(即,客户端到 API 管理)。 你可以验证连接客户端提供的证书,并使用策略表达式,对照所需的值检查证书属性。
若要了解如何使用客户端证书保护对 API 后端服务的访问(即,从 API 管理到后端),请参阅如何使用客户端证书身份验证保护后端服务。
有关 API 授权的概念概述,请参阅 API 管理中对 API 的身份验证和授权。
证书选项
对于证书验证,API 管理可以根据 API 管理实例中管理的证书进行检查。 如果选择使用 API 管理来管理客户端证书,则可以使用以下选项:
- 引用 Azure Key Vault 中托管的证书
- 直接在 API 管理中添加证书文件
建议使用密钥保管库证书,因为它有助于提高 API 管理安全性:
- 密钥保管库中存储的证书可以在服务上重复使用
- 粒度访问策略 可应用到密钥保管库中存储的证书
- 密钥保管库中更新的证书会在 API 管理中自动轮换。 在密钥保管库中更新后,API 管理中的证书会在 4 小时内更新。 你还可以使用 Azure 门户或通过管理 REST API 手动刷新证书。
先决条件
如果尚未创建 API 管理服务实例,请参阅创建 API 管理服务实例。
需要有权访问证书以及 Azure 密钥保管库中用于管理的密码,或上传到 API 管理服务。 证书必须采用 CER 或 PFX 格式。 允许使用自签名证书。
如果使用自签名证书,还应在 API 管理实例中安装受信任的根和中间 CA 证书。
注意
“消耗”层不支持用于证书验证的 CA 证书。
密钥保管库集成的先决条件
如果还没有密钥保管库,请创建一个。 有关创建密钥保管库的步骤,请参阅快速入门:使用 Azure 门户创建密钥保管库。
若要创建证书或将证书导入密钥保管库,请参阅快速入门:使用 Azure 门户从 Azure 密钥保管库设置和检索证书。
在 API 管理实例中启用系统分配的或用户分配的托管标识。
配置对密钥保管库的访问权限
在门户中导航到你的密钥保管库。
在左侧菜单中,选择“访问配置”,并记下配置的权限模型。
根据权限模型,为 API 管理托管标识配置密钥保管库访问策略或 Azure RBAC 访问。
添加密钥保管库访问策略:
- 在左侧菜单中,选择“访问策略”。
- 在“访问策略”页上,选择“+ 创建”。
- 在“权限”选项卡上的“机密权限”下,选中“获取”和“列出”,然后选择“下一步”。
- 在“主体”选项卡上的“选择主体”中,搜索托管标识的资源名称,然后选择“下一步”。 如果你使用系统分配的标识,则主体为你的 API 管理实例的名称。
- 再次选择“下一步”。 在“查看 + 创建”选项卡上,选择“创建”。
配置 Azure RBAC 访问:
- 在左侧菜单中,选择“访问控制(IAM)”。
- 在“访问控制(IAM)”页上,选择“添加角色分配”。
- 在“角色”选项卡上,选择“密钥保管库机密用户”。
- 在“成员”选项卡上,选择“托管标识”>“+ 选择成员”。
- 在“选择托管标识”页上,选择系统分配的托管标识或与 API 管理实例关联的用户分配的托管标识,然后选择“选择”。
- 选择“查看 + 分配”。
Key Vault 防火墙要求
如果在密钥保管库上启用了 Key Vault 防火墙,则具有以下附加要求:
必须使用 API 管理实例的“系统分配的”托管标识来访问密钥保管库。
在 Key Vault 防火墙中,启用“允许受信任的 Microsoft 服务绕过此防火墙”选项。
在选择要添加到 Azure API 管理的证书或机密时,请确保允许本地客户端 IP 地址临时访问密钥保管库。 有关详细信息,请参阅配置 Azure Key Vault 网络设置。
完成配置后,可以在密钥保管库防火墙中阻止客户端地址。
虚拟网络要求
如果 API 管理实例部署在虚拟网络中,则还应配置下列网络设置:
- 在 API 管理子网上,启用 Azure Key Vault 的服务终结点。
- 配置一个网络安全组 (NSG) 规则,以允许指向 AzureKeyVault 和 AzureActiveDirectory 服务标记的出站流量。
有关详细信息,请参阅在 VNET 中设置 Azure API 管理时使用的网络配置。
添加密钥保管库证书
请参阅密钥保管库集成的先决条件。
重要
将密钥保管库证书添加到 API 管理实例时,必须有权列出密钥保管库中的机密。
注意
在 API 管理中使用密钥保管库证书时,请注意不要删除证书、密钥保管库或用于访问密钥保管库的托管标识。
将密钥保管库证书添加到 API 管理:
在 Azure 门户,导航到 API 管理实例。
在“安全性”下,选择“证书”。
选择“证书”>“+ 添加”。
在“Id”中,输入所选的名称。
在“证书”下,选择“密钥保管库”。
输入密钥保管库证书的标识符,或选择“选择”来选择密钥保管库中的证书。
重要
如果你自己输入密钥保管库证书标识符,请确保它不包含版本信息。 否则,在密钥保管库中更新后,证书不会在 API 管理中自动轮换。
在“客户端标识”中,选择一个系统分配的托管标识,或一个现有的用户分配的托管标识。 了解如何在 API 管理服务中添加或修改托管标识。
注意
标识需要从密钥保管库获取和列出证书的权限。 如果你尚未配置对密钥保管库的访问权限,则 API 管理会提示你,你可以让其自动为标识配置必要的权限。
选择 添加。
选择“保存”。
上传证书
将客户端证书上传到 API 管理:
在 Azure 门户,导航到 API 管理实例。
在“安全性”下,选择“证书”。
选择“证书”>“+ 添加”。
在“Id”中,输入所选的名称。
在“证书”下,选择“自定义”。
浏览以选择证书 .pfx 文件并输入其密码。
选择 添加。
选择“保存”。
注意
如果只想使用证书向 API 管理验证客户端,可以上传 CER 文件。
启用 API 管理实例,以接收和验证客户端证书
开发人员、基本、标准和高级层
若要在开发人员层、基本层、标准层或高级层中通过 HTTP/2 接收和验证客户端证书,必须在“自定义域”边栏选项卡上启用“协商客户端证书”设置,如下所示。
消耗层
若要在“消耗”层中接收并验证客户端证书,必须在“自定义域”边栏选项卡上启用“请求客户端证书”设置,如下所示。
用于客户端证书的策略
使用 validate-client-certificate 策略验证客户端证书的一个或多个属性,该客户端证书用于访问托管在 API 管理 API 实例中的 API。
配置策略以验证一个或多个属性,包括证书颁发者、主题、指纹、是否根据联机吊销列表验证证书等。
使用上下文变量的证书验证
还可使用 context
变量创建策略表达式以检查客户端证书。 以下各节中的示例显示了使用 context.Request.Certificate
属性和其他 context
属性的表达式。
注意
如果通过应用程序网关公开 API 管理网关终结点,相互证书身份验证可能无法正常工作。 这是因为应用程序网关充当第 7 层负载均衡器,会与后端 API 管理服务建立一个不同的 SSL 连接。 由于此原因,客户端在初始 HTTP 请求中附加的证书不会转发到 APIM。 但有一个解决方法,就是使用服务器变量选项来传输证书。 有关详细说明,请参阅相互身份验证服务器变量。
重要
- 从 2021 年 5 月开始,仅当 API 管理实例的
hostnameConfiguration
将negotiateClientCertificate
属性设置为 True 时,context.Request.Certificate
属性才会请求证书。negotiateClientCertificate
默认设置为 false。 - 如果在客户端中禁用了 TLS 重新协商,可能会在使用
context.Request.Certificate
属性请求证书时看到 TLS 错误。 如果发生这种情况,请在客户端中启用 TLS 重新协商设置。
检查颁发者和使用者
可以将以下策略配置为检查客户端证书的颁发者和使用者:
<choose>
<when condition="@(context.Request.Certificate == null || !context.Request.Certificate.Verify() || context.Request.Certificate.Issuer != "trusted-issuer" || context.Request.Certificate.SubjectName.Name != "expected-subject-name")" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
注意
若要禁止检查证书吊销列表,请使用 context.Request.Certificate.VerifyNoRevocation()
而不是 context.Request.Certificate.Verify()
。
如果客户端证书是自签名证书,则必须将根(或中间)CA 证书上传到 API 管理,context.Request.Certificate.Verify()
和 context.Request.Certificate.VerifyNoRevocation()
才能正常工作。
检查指纹
可以将以下策略配置为检查客户端证书的指纹:
<choose>
<when condition="@(context.Request.Certificate == null || !context.Request.Certificate.Verify() || context.Request.Certificate.Thumbprint != "DESIRED-THUMBPRINT-IN-UPPER-CASE")" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
注意
若要禁止检查证书吊销列表,请使用 context.Request.Certificate.VerifyNoRevocation()
而不是 context.Request.Certificate.Verify()
。
如果客户端证书是自签名证书,则必须将根(或中间)CA 证书上传到 API 管理,context.Request.Certificate.Verify()
和 context.Request.Certificate.VerifyNoRevocation()
才能正常工作。
针对已上传到 API 管理的证书检查指纹
以下示例演示如何针对已上传到 API 管理的证书,检查客户端证书的指纹:
<choose>
<when condition="@(context.Request.Certificate == null || !context.Request.Certificate.Verify() || !context.Deployment.Certificates.Any(c => c.Value.Thumbprint == context.Request.Certificate.Thumbprint))" >
<return-response>
<set-status code="403" reason="Invalid client certificate" />
</return-response>
</when>
</choose>
注意
若要禁止检查证书吊销列表,请使用 context.Request.Certificate.VerifyNoRevocation()
而不是 context.Request.Certificate.Verify()
。
如果客户端证书是自签名证书,则必须将根(或中间)CA 证书上传到 API 管理,context.Request.Certificate.Verify()
和 context.Request.Certificate.VerifyNoRevocation()
才能正常工作。
提示
本文中所述的客户端证书死锁问题可以通过多种方式表现出来,例如:请求冻结、请求在超时后生成 403 Forbidden
状态代码、context.Request.Certificate
为 null
。 此问题通常会影响内容长度约为 60KB 或更大的 POST
和 PUT
请求。
若要防止出现此问题,请在“自定义域”边栏选项卡上为所需主机名启用“协商客户端证书”设置,如本文档的第一个图像所示。 在“消耗”层中,此功能不可用。