亚马逊AWS官方博客

使用 Amazon Verified Permissions 服务帮您简化管理应用程序授权流程 — 现已正式发布

在开发新应用程序或将现有应用程序集成到新环境中时,需要花费大量精力才能正确实施用户身份验证和授权。过去,可以构建自己的身份验证系统来完成这一操作,但现在可以使用如 Amazon Cognito 这样的外部身份提供程序。不过,授权逻辑通常要在代码中实现。

这开始的时候可能十分简便,为所有用户分配了其工作职能的角色。但是,随着时间的推移,这些权限变得越来越复杂。随着权限变得更加精细,角色的数量也随之增加。新的使用案例推动了对自定义权限的需求。例如,某个用户可能与另一个担任其他角色的用户共享文档,或者支持代理可能需要临时访问客户账户才能解决问题。管理代码中的权限容易出错,在审计权限和决定具体访问人和访问内容时,尤其当这些权限在不同的应用程序中以多种编程语言呈现时,将是一大难题。

re:Invent 2022 上,我们推出了 Amazon Verified Permissions 预览版,该服务为您的应用程序提供细粒度的权限管理和授权服务,可以在任何规模下使用。Amazon Verified Permissions 将权限集中到策略存储库中,帮助开发人员使用这些权限来授权用户在其应用程序中的操作。与身份提供程序简化身份验证的方式类似,策略存储库允许您以一致且可扩展的方式管理授权。

为了更好地定义细粒度权限,Amazon Verified Permissions 使用了 Cedar 套件,这是一种用于进行访问控制的开源策略语言和软件开发工具包(SDK)。您可以根据主体类型、资源类型和有效操作为您的授权模型定义架构。这样,创建策略时,将根据您的授权模型对其进行验证。可以使用模板简化类似策略的创建过程。对策略存储库的更改进行审计,以便可以查看到更改人和更改时间。

然后,可以通过 AWS 开发工具包将应用程序连接到 Amazon Verified Permissions,以授权访问请求。对于每个授权请求,均会检索和评估相关策略,以确定该操作是否被允许。您可以重现这些授权请求以确认权限是否按预期运行。

今天,我很高兴地宣布正式推出 Amazon Verified Permissions 服务,AWS 管理控制台增加了更多的新功能,为用户带来更加精简方便的操作体验。

让我们看看这项服务的具体使用方法。

使用 Amazon Verified Permissions 创建策略存储库
Amazon Verified Permissions 控制台中,选择创建策略存储库。策略存储库是存储策略和架构的逻辑容器。授权决策根据策略存储库中的所有策略做出。

可以使用不同的方法配置新的策略存储库。可以从引导式设置、示例策略存储库(例如照片共享应用程序、在线商店或任务管理器)或空策略存储库(建议高级用户使用)开始。选择引导式设置,为我的架构输入命名空间(MyApp),然后选择下一步

控制台屏幕截图。

资源是主体可以对之采取行动的对象。在我的应用程序中,具有可以创建、读取、更新和删除文档(资源)的用户(主体)。开始定义文档资源类型。

输入资源类型的名称并添加两个必填属性:

  • 所有者字符串),用于指定文档的所有者。
  • isPublic布尔值)用于标记任何人都可以阅读的公共文档。

控制台屏幕截图。

文档资源类型指定了四个操作:

  • DocumentCreate
  • DocumentRead
  • DocumentUpdate
  • DocumentDelete

控制台屏幕截图。

输入用户作为将在文档上使用这些操作的主体类型的名称。然后,选择下一步

控制台屏幕截图。

现在,配置用户主体类型。可以使用自定义配置来集成外部身份源,但在这种情况下,使用的是我之前创建的 Amazon Cognito 用户群体。选择连接用户群体

控制台屏幕截图。

在对话框中,选择用户群体所在的 AWS 区域,输入用户群体 ID,然后选择连接

控制台屏幕截图。

Amazon Cognito 用户群体已连接后,可以通过验证客户端应用程序 ID 来增加另一级别的保护。现在,选择不使用这个选项。

主体属性部分,选择策略中计划用于基于属性的访问控制的具体属性。选择 sub(主题),用于根据 OpenID Connect 规范识别最终用户。可以选择更多属性。例如,可以在策略中使用 email_verified 来仅向电子邮件已通过验证的 Amazon Cognito 用户授予权限。

控制台屏幕截图。

作为策略存储库创建工作的一部分,我创建了第一个策略用于为用户 danilop 提供权限读取 doc.txt 文档。

控制台屏幕截图。

在以下代码中,通过控制台可预览使用 Cedar 语言生成的策略。

permit(
  principal == MyApp::User::"danilop",
  action in [MyApp::Action::"DocumentRead"],
  resource == MyApp::Document::"doc.txt"
) when {
  true
};

最后,选择创建策略存储库

向策略存储库添加权限
现在策略存储库已创建,在导航窗格中选择策略。在创建策略下拉列表中,选择创建静态策略。静态策略包含评估所需的所有信息。在我的第二个策略中,允许任何用户阅读公共文档。默认情况下,所有操作都是禁止的,因此在策略效应中,选择允许

策略范围中,选中所有主体所有资源,然后选择 DocumentRead 操作。在策略部分,更改 when 条件子句,以限制对特定资源(isPublic 等于 true)的权限:

permit (
  principal,
  action in [MyApp::Action::"DocumentRead"],
  resource
)
when { resource.isPublic };

为策略输入描述内容并选择创建策略

对于第三个策略,创建另一个静态策略,以允许文档所有者拥有完全访问权限。同样,在策略效应中,选择“允许”,在策略范围中,选择所有主体所有资源。此时,选中所有操作

策略部分,更改 when 条件子句,以限制对特定资源(所有者等于主体的 sub)的权限:

permit(principal, action, resource)
when { resource.owner == principal.sub };

在我的应用程序中,我需要针对非文档所有者的特定用户允许读取权限。为了简化这一流程,创建了一个策略模板。借助这一策略模板,我从使用占位符作为其某些值(例如主体或资源)的模板来创建策略。模板中的占位符是以 ? 字符开头的关键字。

在导航窗格中,选择策略模板,然后选择创建策略模板。接着,输入描述内容并使用以下策略模板正文。使用此模板时,可以为占位符 ?principal?resource 指定值。

permit(
  principal == ?principal,
  action in [MyApp::Action::"DocumentRead"],
  resource == ?resource
);

我完成了策略模板的创建。现在,使用这个模板来简化策略创建过程。在导航窗格中选择策略,然后在创建策略下拉列表中选择创建模板链接的策略。选择刚创建的策略模板并选择下一步

如果要向用户(danilop)提供特定文档(new-doc.txt)的访问权限,只需发送以下值(请注意,MyApp 是策略存储库的命名空间):

  • 对于主体MyApp::User::"danilop"
  • 对于资源MyApp::Document::"new-doc.txt"

我完成了策略创建。接下来测试这些策略是否按预期运行。

在控制台中测试策略
在我的应用程序中,可以使用 AWS SDK 来运行授权请求。控制台提供了一种方法来模拟应用程序将要执行的操作。在导航窗格中选择测试台。为了简化测试,使用视觉模式。作为替代方案,可以选择使用与 SDK 中相同的 JSON 语法。

作为主体,我发送了 janedoe 用户。作为资源,我使用了 requirements.txt 。该文档不是公共文档(isPublicfalse),并且所有者属性等于 janedoesub。在操作中,选择 MyApp::Action::"DocumentUpdate"

运行授权请求时,我可以向其他实体发送有关与请求相关的主体和资源的更多信息。现在,先把这部分留空。

选择顶部的运行授权请求来查看基于当前策略做出的决定。正如预期,该决定是允许的。在这里,还可以查看到授权请求满足的具体策略。在这种情况下,策略允许文档所有者拥有完全访问权限。

可以测试其他值。如果将文档的所有者和操作更改为 DocumentRead,则决策被拒绝。如果随后将资源属性 isPublic 设置为 true,则决定是允许的,因为有一项策略允许所有用户阅读公共文档。

处理权限中的群组
我的应用程序中的管理用户要有权限删除任何文档。为此,我为管理员用户创建了一个角色。首先,在导航窗格中选择架构,然后选择编辑架构。在实体类型列表中,选择添加一个新的实体类型。接着,使用角色作为类型名称,并添加。然后,在实体类型中选择用户,并编辑它,将角色添加为父级。保存更改并创建了以下策略:

permit (
  principal in MyApp::Role::"admin",
  action in [MyApp::Action::"DocumentDelete"],
  resource
);

测试台中,运行授权请求来检查用户 jeffbarr 能否删除 (DocumentDelete) 资源 doc.txt。由于他不是资源的所有者,因此请求被拒绝。

现在,在其他实体中,添加以 jeffbarr 作为标识符的 MyApp::User 实体。作为父级,添加以管理员作为标识符的 MyApp::Role 实体,然后确认。控制台发出警告消息指出,实体 MyApp::Role::"admin" 已被引用,但其他实体数据中并未包含。选择添加该实体,解决这个问题。

再次运行授权请求时,请求被允许,原因是在其他实体中,主体(jeffbarr)是管理员

在您的应用程序中使用 Amazon Verified Permissions
在我的应用程序中,可以使用 isAuthorized API 操作(如果主体来自外部身份来源,则使用 isAuthrizedWithToken)运行授权请求。

例如,以下 Python 代码使用适用于 Python 的 Amazon SDK(Boto3) 来检查用户是否有权限读取文档。授权请求使用我刚创建的策略存储库。

import boto3
import time

verifiedpermissions_client = boto3.client("verifiedpermissions")

POLICY_STORE_ID = "XAFTHeCQVKkZhsQxmAYXo8"

def is_authorized_to_read(user, resource):

    authorization_result = verifiedpermissions_client.is_authorized(
        policyStoreId=POLICY_STORE_ID,
        principal={"entityType": "MyApp::User", "entityId": user},
        action={"actionType": "MyApp::Action", "actionId": "DocumentRead"},
        resource={"entityType": "MyApp::Document", "entityId": resource}
    )

    print('Can {} read {} ?'.format(user, resource))

    decision = authorization_result["decision"]

    if decision == "ALLOW":
        print("Request allowed")
        return True
    else:
        print("Request denied")
        return False

if is_authorized_to_read('janedoe', 'doc.txt'):
    print("Here's the doc...")

if is_authorized_to_read('danilop', 'doc.txt'):
    print("Here's the doc...")

我运行这段代码后,正如预期,输出内容与之前运行的测试一致。

janedoe 能读取 doc.txt 文档吗?
请求被拒绝
danilop 能读取 doc.txt 文档吗?
请求已允许
这是文档...

可用性和定价
Amazon Verified Permissions 现已在所有商用 AWS 区域提供,但不包括位于中国的区域。

使用 Amazon Verified Permissions 时,您只需根据授权请求的数量和向服务发出的 API 调用数量为实际用量支付费用。有关更多信息,请参阅 Amazon Verified Permissions 定价

通过 Amazon Verified Permissions,您可以使用 Cedar 策略语言配置细粒度权限,并简化应用程序的代码。通过这种方式,权限可以保留在集中存储区中,并且更易于审计。在此处,您可以阅读关于我们如何通过自动推理和差分测试构建 Cedar 的详细信息。

使用 Amazon Verified Permissions 管理应用程序的授权。

Danilo