实现 Azure OpenAI 无密钥身份验证
与许多 Azure API 一样,Azure OpenAI 服务允许开发人员使用API密钥或无密钥(通过Entra ID)进行身份验证。由于尽量避免使用密钥是安全最佳实践,因此我们在本文中将详细介绍如何使开发人员轻松地迁移到无密钥 Azure OpenAI 身份验证。如果您想立即行动,这里还提供了一个新的无密钥部署模板。
密钥的风险
首先让我们来谈谈API密钥的风险,使用密钥很省心,因为设置看起来很简单——你只需要一个端点URL和密钥:
|
|
但是在代码库中使用API密钥可能会导致各种问题。举几个例子:
- 密钥可能被开发人员不小心放入了源代码控制库中,可能因为某个开发人员将
getenv()
调用替换为一个硬编码的字符串,或者是因为某个开发人员将.env
文件添加到提交中。 - 一旦将密钥放入源代码控制中,它们将在内部被公开,并且由于恶意行为者可以访问代码库,因此它们也面临更大的外部泄露风险。
- 在大型公司中,多个开发人员可能在不知情的情况下使用相同的密钥,使用彼此的资源,并发现由于配额错误而导致服务失败。
我见过所有这些情况的发生,我不希望它们发生在其他开发人员身上。更安全的方法是使用身份验证令牌,因为它们是动态获得的,具有有限的生命周期,并且不会以明文形式存储。
使用 Entra ID 验证 Azure OpenAI
该代码使用 OpenAI Python 包和 Azure Python SDK 进行 Azure OpenAI 身份验证。
|
|
和基于密钥的代码的区别:
- 该代码使用
DefaultAzureCredential
与 Azure 进行身份验证,它会遍历许多可能的凭据类型,直到找到一个有效的 Azure 登录身份。 - 代码根据凭据获取 Azure OpenAI 令牌提供商,并将其设置为
azure_ad_token_provider
,SDK 将在必要时使用该令牌提供商获取访问令牌,甚至为我们刷新令牌。
本地访问 Azure OpenAI
下一步是确保运行代码的人有权访问 Azure OpenAI 服务。默认情况下,即使你自己创建了 Azure OpenAI 服务,你也不会有权限。这是一个安全措施,以确保你不会意外地从本地机器访问生产资源(当你的代码处理数据库写操作时,尤其有帮助)。
要访问 Azure OpenAI 资源,您需要“Cognitive Services OpenAI User”角色(Role ID为“5e0bd9bd-7b93-4f28-af87-19fc36ad61bd”),可以使用 Azure Portal、Azure CLI 或 ARM/Bicep 进行分配。
使用 Azure CLI 分配角色
首先,设置以下环境变量:
- PRINCIPAL_ID: 您登录账户的主ID。您可以通过运行
az ad signed-in-user show --query id -o tsv
命令使用 Azure CLI 获取该ID,或者您可以打开 Azure 门户,搜索“Microsoft Entra ID”,选择“用户”选项卡,筛选您的账户,然后复制位于您的电子邮件地址下方的“object ID”。 - SUBSCRIPTION_ID: 登录账号的订阅ID,可以在 Azure Portal 中 Azure OpenAI 资源的 Overview 页面看到。
- RESOURCE_GROUP: Azure OpenAI 资源的资源组。
然后使用 Azure CLI 运行以下命令:
|
|
使用 ARM/Bicep 分配角色
我们使用 Azure Developer CLI 部署所有示例,该工具依赖于 Bicep 文件来声明基础设施即代码。这使得部署更加可复用,因此对于部署生产应用程序来说是一个很好的方法。
这个 Bicep 资源创建角色,假设设置了 principalId
参数:
|
|
你也可以看出这个main.bicep的示例是如何使用模块来设置角色的。
使用 Azure Portal 分配角色
如果您无法使用这些自动化方法(首选方法),也可以使用Azure门户创建该角色:
- 打开 Azure OpenAI 资源
- 从左侧导航中选择“访问控制(IAM)”
- 在顶部菜单中选择“添加”
- 搜索“Cognitive Services User”,并在搜索结果中选择它
- 选择“Assign access to: User, group, or service principal”
- 搜索您的电子邮件地址
- 选择“Review and assign”
从生产环境主机访问 Azure OpenAI
下一步是确保您的部署应用程序也可以使用 DefaultAzureCredential
令牌访问 Azure OpenAI 资源。这需要设置一个托管身份,并为托管身份分配相同的角色。有两种托管身份:系统分配的和用户分配的。所有 Azure 托管平台都支持托管身份。我们将以 App Service 和系统分配的身份为例开始。
为应用服务管理身份
下面是如何在 Bicep 代码中创建一个具有系统分配标识的应用服务:
|
|
有关更多详细信息,请参阅《Managed Identity for App Service》一文。
为托管标识分配角色
角色分配过程对于主机和对于用户基本相同,但是主体ID必须设置为托管标识的主体ID,并且主体类型为“ServicePrincipal”。
例如,这个 Bicep 为一个 App Service 系统分配的标识分配角色:
|
|
Azure 容器应用的用户分配身份
也可以使用与上面类似的方法为 Azure 容器应用程序分配系统身份。下面的示例是使用用户分配的身份,以便在 ACA 应用程序被提供之前,我们可以给出对 Azure 容器注册中心的相同身份访问。这就是用户分配身份的优势,能跨多个 Azure 资源重用。
首先,我们在容器应用 Bicep 资源之外创建一个新的身份:
|
|
然后我们把这个标识赋给容器应用 Bicep 资源:
|
|
当使用用户分配的标识时,我们需要修改对 AzureDefaultCredential
的调用,以告诉它使用哪个标识,因为您可能有多个用户分配的标识(而不仅仅是宿主环境的单个系统分配的标识)。
下面的代码从环境变量中获取身份的ID,并将其指定为 Managed Identity 凭证的 client_id
:
|
|
在本地 Docker 容器中访问 Azure OpenAI
现在你应该能够在本地开发和生产中访问 Azure OpenAI。除非你正在使用本地 Docker 容器进行开发。默认情况下,Docker 容器没有访问任何本地凭据的方法,所以你会在日志中看到身份验证错误。过去,可以通过使用 volumes 来访问凭据,但自从 Azure 开始加密本地凭据后,如何在本地容器内轻松地进行身份验证就成了悬而未决的问题。
我们有一些替代的选择:
- 在 Docker 容器中使用本地开发密钥。这会带来我们之前讨论过的密钥问题,但在本地非生产部署中使用密钥可以降低使用密钥的风险。
- 使用 Azure OpenAI 兼容的端点运行本地模型(通过llamafile或ollama),你会看到模型的答案有相当大的差异,所以当你在应用程序的提示工程方面工作时,你不会想这样做。
- 出于本地开发的目的,可以在容器外运行该应用程序。如果您希望享受本地容器化的好处,仍然可以在 VS Code Dev Container 中运行它,它确实允许进行 Azure 身份验证。这通常是我所采取的方法。
混合做法
正如你所看到的,没有密钥就无法完全直接地对 Azure OpenAI 进行身份验证,这取决于你在本地如何开发以及你在哪里部署。
下面的代码在环境变量中设置密钥时使用密钥,在环境变量中设置身份ID时使用用户分配的管理身份,否则使用 DefaultAzureCredential
。
|
|
放心使用无密钥身份验证
以下是一些帮助您在 OpenAI 项目中实现无密钥身份验证的示例:
- azure-openai-keyless:仅使用
azd
为本地用户帐户分配 OpenAI 和 RBAC 角色。 - openai-chat-backend-fastapi: 使用
azd
为本地用户账户和 Azure Container App 用户分配的身份提供 OpenAI 和 RBAC 角色。 - azure-search-openai-demo:使用
azd
为本地用户账户和 App Service 系统身份配置 OpenAI 和 RBAC 角色。
- 原文作者:BeanHsiang
- 原文链接:https://beanhsiang.github.io/post/2024-04-17-keyless-authentication-with-azure-openai/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。