构建统一授权层以支持身份提供者与 Amazon Verified Permissions
关键要点
企业通常有员工和客户的身份提供者(IdP)。使用统一授权层可以简化多个身份系统的管理,通过集中控制API的访问政策,以提高管理效率。通过 Amazon Cognito、Verified Permissions 和 AWS Lambda Authorizer,可以实现多 IdP 的集成。实现这一方案时,需要注意政策的大小限制以及访问请求的慢速情况。企业往往为员工和客户设置不同的身份提供者IdP,虽然这使得访问控制与政策更加多样化,但同时也增加了管理多个身份系统的复杂性。通过构建统一的授权层,可以集中管理所有 API 的访问政策,无论用户的身份提供者如何,从而简化管理流程。统一的授权层会在允许 API 访问之前评估来自任何授权 IdP 的访问令牌,这样可以避免在 API 内部嵌入授权逻辑,并便于制定组织范围内的政策。
想象一下一个兽医诊所,它为员工设置了一个 IdP,而客户宠物的主人则使用另一个 IdP。员工和客户可能存在不同的登录要求,比如多因素认证MFA或额外的审计功能。因此,为客户和员工实施相同的访问控制策略可能并不明智。在这种情况下,诊所的排班应用程序将管理来自员工和客户的访问。通过实现统一授权层,排班应用程序不需要了解不同的 IdP 或令牌,授权层处理令牌的验证和政策的应用,比如允许员工全权访问约会数据,而仅限宠物主人查看他们宠物的记录。下面我们将展示如何使用多个 Amazon Cognito 用户池、Amazon Verified Permissions 和 AWS Lambda Authorizer 来构建一个统一的授权层。
体系结构概述
这个示例架构依赖于用户池多租户来进行用户验证,使用 Amazon Cognito 用户池为经过身份验证的用户分配一组临时和最小权限的凭证以访问应用。一旦用户经过认证,他们将通过 Lambda Authorizer 函数获得访问后台功能的授权。该函数与 Verified Permissions 接口,以根据用户属性应用适当的访问政策。
此示例架构基于一个有两类用户内部用户兽医和外部用户客户的应用场景,每类用户有特定的 API 访问权限。图 1 展示了用户请求的流动。
让我们逐步了解请请求流动:
有两个用户组外部客户和内部兽医。这两个组通过一个网络门户登录,该门户与 IdPAmazon Cognito进行身份验证。用户组试图通过 API Gateway 访问获取预约的 API,同时带上他们的 JWT 令牌与声明和客户端 ID。Lambda Authorizer 验证声明。注意: 如果 Cognito 作为 IdP,则 Verified Permissions 可以直接通过 IsAuthorizedWithToken API 授权用户。
在验证 JWT 令牌后,Lambda Authorizer 会使用关联的政策信息对 Verified Permissions 发起查询来检查请求。API Gateway 根据 Lambda Authorizer 返回的政策来评估是否允许或拒绝对资源的访问。如果允许,API Gateway 将访问该资源;如果拒绝,API Gateway 将返回 403 Forbidden 错误。注意: 为了进一步优化 Lambda Authorizer,可以根据需要缓存或禁用授权决定。启用缓存可以提升性能,因为在有缓存键匹配时,授权政策将从缓存返回。有关更多信息,请查看 使用 API Gateway 控制台配置 Lambda 授权器。
逐步指导
本指导展示了前面的场景,为支持兽医和客户的授权层设置。每组用户都有自己独特的 Amazon Cognito 用户池。
与每个 Cognito 池相关的 Verified Permissions 策略强制执行访问控制。在兽医池中,兽医只能访问自己患者的数据。同样,在客户池中,客户只能查看和访问自己的数据。这确保了兽医和客户之间的数据适当分段和安全。
内部政策plaintextpermit (principal in UserGroupAllVeterinarians action == ActionGET/appointment resource in UserGroupAllVeterinarians) when {principal == resourceVeterinarian }
外部政策plaintextpermit (principal in UserGroupAllClients action == ActionGET/appointment resource in UserGroupAllClients) when {principal == resourceowner}
示例内部和外部政策,以及 Cognito 作为 IdP,允许兽医用户通过一个 IdP 联合登录到应用,而外部客户必须使用另一个 IdP。通过与授权策略结合,这样您就可以为每个用户组创建和定制细粒度访问策略。
要使用策略存储验证访问请求,Lambda Authorizer 执行角色还需要 verifiedpermissionsIsAuthorized 操作。
尽管我们的示例 Verified Permissions 策略相对简单,但 Cedar 策略语言十分丰富,允许您根据业务需要自行定义规则。例如,您可以制定一项政策,使兽医只能在客户预约的当天访问客户记录。
实施示例架构
该架构基于用户池多租户进行用户验证。它使用 Amazon Cognito 用户池为经过身份验证的用户分配一组临时和最低权限凭证以进行应用访问。在验证用户后,他们将可以通过 Lambda 函数访问 APIs。该函数与 Verified Permissions 接口,以根据用户属性应用适当的访问政策。
先决条件
您需要以下先决条件:
已安装并配置好 AWS 命令行界面CLI。Python 39 或更高版本,以打包 Lambda 的 Python 代码。注意: 我们推荐您使用 虚拟环境 或 virtualenvwrapper 来隔离示例与您的其他 Python 环境。
拥有足够权限创建 Amazon Cognito 用户池、IAM 角色、Lambda 函数、IAM 策略和 API Gateway 实例的 AWS 身份和访问管理IAM 角色或用户。在 bash 脚本中进行 JSON 处理的 jq。在 Ubuntu/Debian 上安装,使用以下命令:
bashsudo aptget install jq

在 Mac 上通过 Homebrew 安装,使用以下命令:
bashbrew install jq
示例代码的 GitHub 仓库。您可以 下载它,也可以在终端中使用以下 Git 命令下载它。注意: 此示例代码应用于测试解决方案,而不应用于生产账户。
bash git clone https//githubcom/awssamples/amazoncognitoavpapigatewaygit cd amazoncognitoavpapigateway
要实现此参考架构,您将使用以下服务:
Amazon Verified Permissions 是帮助您在构建和部署的应用中实施和强制细粒度授权的服务,例如人力资源系统和银行应用程序。Amazon API Gateway 是一项完全托管的服务,开发者可利用其创建、发布、维护、监控并保护 API,支持任何规模。AWS Lambda 是一项无服务器计算服务,允许您运行代码而无需配置或管理服务器,创建负载感知集群扩展逻辑,维护事件集成或管理运行时。Amazon Cognito 提供可以扩展到数百万用户的身份存储,支持社交和企业身份联合,并提供先进的安全功能,以保护您的消费者和业务。注意: 我们在 useast1 AWS 区域测试了此架构。在选择地区之前,请确保必要的服务Amazon Verified Permissions、Amazon Cognito、API Gateway 和 Lambda在这些地区可用 的相关信息。
部署示例架构
在您从 GitHub 下载示例代码的目录中,首先运行以下命令来打包 Lambda 函数。然后运行下一条命令以生成随机的 Cognito 用户密码,并创建前面部分描述的资源。
注意: 在此情况下,您生成随机用户密码仅用于演示目的。请在生产实现中遵循用户密码最佳实践。bash bash /helpersh packagelambdafunctions成功完成文件打包。 bash /helpersh cfcreatestackgenpassword成功创建 CloudFormation 堆栈。
验证 Cognito 用户创建
运行以下命令在浏览器中打开 Cognito UI,然后使用您的凭据登录。这验证之前的命令成功创建了 Cognito 用户。
注意: 当您运行这些命令时,它们会返回您应该使用的用户名和密码。
betternet加速器对内部用户池域用户bash bash /helpersh opencognitointernaldomainui打开 Cognito UI网址 xxxxxxxxx请使用以下凭据登录用户名 cognitouser密码 xxxxxxxx
对外部用户池域用户bash bash /helpersh opencognitoexternaldomainui打开 Cognito UI网址 xxxxxxxxx请使用以下凭据登录用户名 cognitouser密码 xxxxxxxx
验证登录时的 Cognito JWT
由于您尚未安装响应重定向请求的 Web 应用程序,Cognito 将重定向到 localhost,这可能显示为错误。重要的是,在成功登录后,您的浏览器导航栏中会出现类似以下的 URL。
plaintexthttp//localhost/#idtoken=eyJraWQiOiJicVhMYWFlaTl4aUhzTnY3W
测试 API 配置
在保护 API 以确保仅授权用户可以访问之前,让我们验证配置是否正确,以及 API Gateway 是否提供 API。以下命令向 API Gateway 发起 curl 请求,以从 API 服务获取数据。
bash bash /helpersh curlapi
API 以检查 PIT123 的预约细节网址 https//epgst74zffexecuteapiuseast1amazonawscom/dev/appointment/PIT123响应:{appointment {id PIT123 name Dave Pet Onyx Dog 2y 3m Phone Number 1234567 Visit History Patient History from last visit with primary vet Assigned Veterinarian Jane}}
API 以检查 PIT124 的预约细节网址 https//epgst74zffexecuteapiuseast1amazonawscom/dev/appointment/PIT124响应:{appointment {id PIT124 name Joy Pet Jelly Dog 6y 2m Phone Number 1368728 Visit History None Assigned Veterinarian Jane}}
API 以检查 PIT125 的预约细节网址 https//epgst74zffexecuteapiuseast1amazonawscom/dev/appointment/PIT125响应:{appointment {id PIT125 name Dave Pet Sassy Cat 1y Phone Number 1398777 Visit History Patient History from last visit with primary vet Assigned Veterinarian Adam}}
保护 API
下一步,您将部署一个 Verified Permissions 策略存储和一个 Lambda Authorizer。策略存储包含用户授权的策略。Lambda Authorizer 验证用户的访问令牌并通过 Verified Permissions 授权用户。
更新和创建资源
运行以下命令以更新现有资源并创建一个 Lambda Authorizer 和 Verified Permissions 策略存储。
bash bash /helpersh cfupdatestack成功更新 CloudFormation 堆栈。
测试自定义授权者设置
从以下请求开始您的测试,该请求不包括访问令牌。
注意: 等待几分钟以允许 API Gateway 部署,然后再运行以下命令。bash bash /helpersh curlapiAPI 以检查 PIT123 的预约细节网址 https//epgst74zffexecuteapiuseast1amazonawscom/dev/appointment/PIT123响应:{messageUnauthorized}
API 以检查 PIT124 的预约细节网址 https//epgst74zffexecuteapiuseast1amazonawscom/dev/appointment/PIT124响应:{messageUnauthorized}
API 以检查 PIT125 的预约细节网址 https//epgst74zffexecuteapiuseast1amazonawscom/dev/appointment/PIT125响应:{messageUnauthorized}
架构以“未授权”消息拒绝了请求,这时 API Gateway 期待请求中的 Authorization区分大小写标头。如果没有授权标头,API Gateway 会在到达 Lambda Authorizer 之前拒绝请求。这是一种过滤掉没有包含所需信息的请求的方法。
使用以下命令进行下一次测试。在此测试中,您传递了所需的标头,但令牌无效,因为它不是由 Cognito 发出的,而是存储在 /helpersh 中的简单 JWT。要了解如何解码和验证 JWT,请参阅 解码并验证 Cognito JSON 令牌。
bash bash /helpersh curlapiinvalidtoken{MessageUser is not authorized to access this resource}
这次消息不同。Lambda Authorizer 收到了请求并将令牌识别为无效,回应的消息为“用户未被授权访问此资源。”
要成功请求保护 API,您的代码必须执行以下步骤:
使用用户名和密码对 Cognito 用户池进行身份验证。获得令牌ID 令牌、访问令牌和刷新令牌。进行 HTTPS (TLS) 请求到 API Gateway,并在 headers 中传递访问令牌。为了完成测试,程序化地登录到 Cognito UI,获取有效的访问令牌,并请求访问 API Gateway。运行以下命令调用内部和外部的保护 API。
bash /helpersh curlprotectedinternaluserapi
获取 API URL,Cognito 用户名、Cognito 用户密码和 Cognito ClientId用户 Jane密码 Paword20230417171132资源 PIT123网址 https//16qyz501mgexecuteapiuseast1amazonawscom/dev/appointment/PIT123
正在进行身份验证以获得 accesstoken访问令牌 eyJraWQiOiJIaVRvckxxxxxxxxxx6BfCBKASA
响应:{appointment {id PIT123 name Dave Pet Onyx Dog 2y 3m Phone Number 1234567 Visit History Patient History from last visit with primary vet Assigned Veterinarian Jane}}
用户 Adam密码 Paword20230417171132资源 PIT123网址 https//16qyz501mgexecuteapiuseast1amazonawscom/dev/appointment/PIT123
正在进行身份验证以获得 accesstoken访问令牌 eyJraWQiOiJIaVRvckxxxxxxxxxx6BfCBKASA
响应:{MessageUser is not authorized to access this resource}
用户 Adam密码 Paword20230417171132资源 PIT125网址 https//16qyz501mgexecuteapiuseast1amazonawscom/dev/appointment/PIT125
正在进行身份验证以获得 accesstoken访问令牌 eyJraWQiOiJIaVRvckxxxxxxxxxx6BfCBKASA
响应:{appointment {id PIT125 name Dave Pet Sassy Cat 1y Phone Number 1398777 Visit History Patient History from last visit with primary vet Assigned Veterinarian Adam}}
现在调用外部用户池用户进行访问请求
bash /helpersh curlprotectedexternaluserapi用户 Dave密码 Paword20230417171132资源 PIT123网址 https//16qyz501mgexecuteapiuseast1amazonawscom/dev/appointment/PIT123
正在进行身份验证以获得 accesstoken访问令牌 eyJraWQiOiJIaVRvckxxxxxxxxxx6BfCB