使用亚马逊验证权限实现大规模的细粒度授权
由 Abhishek Panday 和 Jeremy Ware 于 2024 年 3 月 26 日发布于 高级(300)、亚马逊验证权限、安全、身份与合规性、技术指导永久链接评论 分享
实现用户身份验证和授权自定义应用程序需要大量的精力。 我们将探讨如何使用亚马逊验证权限来简化这一过程并提高效率。
关键要点
用户身份验证和授权的实现往往需要大量努力。亚马逊验证权限提供集中权限管理,简化授权逻辑。支持的技术包括批量授权和响应缓存,以提升应用程序性能。适用于用户界面UI和 API 的细粒度权限管理。在开发自定义应用程序时,身份验证和授权的实现要求相当高。通常客户会使用像 亚马逊 Cognito 这样的外部身份提供商IdP。然而,授权逻辑一般是通过编码来实现的。这种方式容易出错,尤其是在权限模型变得复杂时,同时在审计权限和判断谁可以访问什么资源时也会带来问题。根据 通用弱点枚举 (CWE) 发布的 2023 年前 25 名最危险的软弱点 中,有四项与错误授权相关。
在 reInforce 2023 上,我们推出了 亚马逊验证权限,这是一种细粒度的权限管理服务,旨在帮助您集中管理应用程序中的权限。验证权限可以在策略存储中集中管理权限,并允许开发者在其应用程序内使用这些权限来授权用户操作。权限是以 Cedar 政策的形式表达的。更多关于集中管理权限及将其以政策形式表达的好处,可以在 应用开发中的基于策略的访问控制 中了解。
在本文中,我们将探讨如何在授权所有请求的同时提供更快和更丰富的用户体验。您将学习两种技术批量授权和响应缓存以提高应用程序的效率。我们将描述如何在列出授权资源和操作以及加载多个网页组件时应用这些技术。
用例
您可以使用验证权限来执行控制用户在用户界面UI级别能看到什么,以及在 API 级别能执行什么操作的权限。
UI 权限:允许开发者控制用户在应用程序中可以看到什么。开发者在 UI 中强制执行权限,以控制用户可以查看的资源列表和他们能够采取的操作。例如,在银行应用程序中,UI 级别的权限可能决定是否启用转账按钮。API 权限:允许开发者控制用户在应用程序中可以执行的操作。开发者控制代表用户发出的单个 API 调用的访问。例如,在银行应用程序中,API 级别的权限可能决定用户是否被允许从某个账户发起资金转账。Cedar 提供一致且易于理解的政策,适用于 UI 和 API 级别。例如,可以在 UI 级别检查单个政策,以决定是否显示转账按钮,并在 API 级别检查,以确定是否有权发起资金转账。
挑战
验证权限可以用于实施细粒度的 API 权限。客户应用程序可以使用验证权限基于集中管理的 Cedar 政策,以低延迟来授权 API 请求。应用程序通过调用该服务的 IsAuthorized API 来授权这些请求,响应包含请求是允许还是拒绝。客户对单个授权请求的延迟表示满意,但他们希望我们帮助提高涉及多个授权请求的用例的性能。他们通常提到两种用例:
复合授权:当一个高级别的 API 操作涉及多个低级别的操作,每个操作都有其自己的权限时,需要复合授权。这需要应用程序多次请求验证权限以授权用户操作。例如,在银行应用程序中,加载信用卡对账单需要三次 API 调用:GetCreditCardDetails、GetCurrentStatement 和 GetCreditLimit。这需要分别请求验证权限。UI 权限:开发者通过对每个资源进行授权 API 调用来实现 UI 权限。每次请求都会涉及一条 API 调用,而在所有请求完成之前,UI 不能呈现。或者,为了实现资源中心化视图,应用程序可以对多个主体发出调用,以确定哪些人有访问权限。解决方案
在本文中,我们展示了两种技术,以优化基于 API 权限和 UI 权限的应用程序延迟。
批量授权:允许您在单个 API 调用中做出最多 30 个授权决策。此功能于 2023 年 11 月发布。更多信息请参见 新功能公告 和 API 规格。响应缓存:允许您在策略执行点如 亚马逊 API 网关、AWS AppSync 或 AWS Lambda中缓存授权响应。您可以使用原生执行点缓存例如 API 网关缓存或托管缓存服务,如 亚马逊 ElastiCache。解决为每个 API 调用执行权限授权而不影响性能的问题
复合授权是指单个用户操作导致多个授权调用的情况。您可以结合批量授权和响应缓存来提高效率。应用程序对验证权限进行单个批量授权请求,以确定每个组件 API 调用是否被允许,并缓存响应。此缓存随后在序列中的每个组件 API 调用中引用。
示例应用程序 用例、用户角色和权限
我们使用一家玩具商店的在线订单管理应用程序来演示如何应用批量授权和响应缓存来提升用户体验和应用程序性能。
该应用程序的一项功能是允许商店员工处理在线订单。
用户角色
该应用程序由两类用户使用:
包装助手负责挑选、打包和发货订单。 他们被分配到特定部门。商店经理负责监督商店的运营。用例
该应用程序支持以下用例:
列出订单:用户可以列出订单。用户只能看到他们拥有查看权限的订单。打包助手可以列出其部门的所有订单。商店经理可以列出其商店的所有订单。图 1 显示了打包助手 Julian 在 软玩具 部门的订单。
图 1:Julian 在软玩具部门的订单
订单操作:用户可以对订单采取某些操作。应用程序根据用户的权限启用相关的 UI 元素。打包助手可以选择 获取箱子大小 和 标记为已发货 ,如图 2 所示。商店经理可以选择 获取箱子大小 、 标记为已发货 、 取消订单 和 转发到不同的仓库。图 2:Julian 作为打包助手可用的操作
查看订单:用户可以查看特定订单的详细信息。当用户查看订单时,应用程序加载详细信息、标签和收据。图 3 显示了打包助手 Julian 可执行的操作。图 3:Julian 的订单详情,显示允许的操作
策略设计
该应用程序使用验证权限作为集中策略存储。 这些策略使用 Cedar 表达。应用程序使用 使用策略模板进行角色管理 的方法来实施基于角色的访问控制。我们鼓励您阅读 Cedar 中使用基于角色的访问控制的最佳实践 以确定这一方法是否适合您的用例。
在示例应用程序中,商店所有者角色的策略模板如下:
奈云加速器下载plaintextpermit ( principal == principal action in [ avpsampletoystoreActionOrderActions avpsampletoystoreActionAddPackAssociate avpsampletoystoreActionAddStoreManager avpsampletoystoreActionListPackAssociates avpsampletoystoreActionListStoreManagers ] resource in resource)
当用户被分配角色时,应用程序通过传递用户和商店,从相应的模板创建策略。例如,为商店所有者创建的策略如下:
plaintextpermit ( principal == avpsampletoystoreUsertestuserpoolsubstoremanageruser action in [ avpsampletoystoreActionOrderActions avpsampletoystoreActionAddPackAssociate avpsampletoystoreActionAddStoreManager avpsampletoystoreActionListPackAssociates avpsampletoystoreActionListStoreManagers ] resource in avpsampletoystoreStoretoy store 1)
有关该应用程序策略设计的更多信息,请参阅 应用程序的自述文件。
用例 设计与实施
在本节中,我们讨论高层设计、基本集成的挑战,以及您如何使用上述技术来降低延迟和成本。
列出订单
图 4:列出订单的架构
如图 4 所示,列出订单的过程为:
用户访问托管在 AWS Amplify 的应用程序。用户通过亚马逊 Cognito 进行身份验证并获取身份令牌。应用程序使用 Amplify 加载订单页面。 控制台调用 API ListOrders 来加载订单。该 API 托管在 API 网关中,并由 Lambda 授权函数保护。Lambda 函数从内存数据存储中收集实体信息,以制定 isAuthorized 请求。然后,Lambda 函数调用验证权限以授权请求。 该函数检查数据存储中每个订单的验证权限。如果验证权限返回拒绝,则用户无法获得该订单。如果验证权限返回允许,则请求将继续执行。挑战
图 5 显示应用程序多次依次调用 IsAuthorized。多次顺序调用会导致页面加载缓慢,增加基础设施成本。
图 5:对 IsAuthorized 的重复调用图
使用批量授权减少延迟
如果转向使用批量授权,应用程序可以通过一次 API 调用接收 30 个授权决策。如图 6 所示,授权时间从接近 800 毫秒减少到 79 毫秒,提供了更好的用户体验。
图 6:通过使用批量授权减少的延迟
订单操作
图 7:订单操作架构
如图 7 所示,获取订单的授权操作的过程为:
用户访问 Amplify 上的应用程序登录页面。应用程序调用 API 网关的订单操作 API。应用程序发送请求以发起订单操作,以向用户显示仅授权的操作。Lambda 函数从内存数据存储中收集实体信息,以制定 isAuthorized 请求。Lambda 函数随后向验证权限检查每个订单操作。如果验证权限返回拒绝,则操作被舍弃。如果验证权限返回允许,则请求继续,并将操作添加到后续请求中,以便向验证权限提供用户界面的操作列表。
挑战
与列出订单一样,图 8 显示应用程序仍在多次顺序调用 IsAuthorized。这意味着页面的加载速度较慢,对基础设施成本的影响也增加。
图 8:对 IsAuthorized 的重复调用图
使用批量授权再度减少延迟
若再添加一层,通过再次使用批量授权,应用程序可以通过单次 API 调用获得所有决策。如图 9 所示,授权时间从接近 500 毫秒减少到 150 毫秒,从而改善用户体验。
图 9:图表展示批量授权的效果
查看订单
图 10:查看订单的架构
查看订单的过程,如图 10 所示:
用户访问托管在 Amplify 上的应用程序。用户通过亚马逊 Cognito 进行身份验证并获取身份令牌。应用程序调用 API 网关托管的三个 API。三个 API 分别是:获取订单详情、获取标签和获取收据,依次针对用户 UI 进行加载。每个上述 API 都由 Lambda 授权程序保护,并在每次调用时启动。Lambda 函数从内存数据存储中收集实体信息,以制定 isAuthorized 请求。对于每个 API,重复上述步骤。在加载页面时,Lambda 授权程序被调用三次。Lambda 函数调用验证权限以授权请求。如果验证权限返回拒绝,则请求被拒绝,并返回 HTTP 未授权响应 (403)。如果验证