使用基于属性的角色映射控制对亚马逊 OpenSearch 服务控制面板的访问权限

亚马逊 OpenSearch 服务的联合用户通常需要根据其用户配置文件使用角色访问开放搜索控制面板。 OpenSearch Service 精细的访问控制 将经过身份验证的用户 映射到 OpenSearch 搜索角色,然后评估权限以确定如何处理用户的操作。但是,当企业级身份提供商 (IdP) 管理用户时,通常需要根据 IdP 用户属性动态映射用户到 OpenSearch Service 角色。映射用户的一种选择是使用 OpenSearch 服务 SAML 集成 并将用户组信息传递给 OpenSearch 服务。另一种选择是 Amazon Cognito 基于角色的访问控制 ,它支持基于规则 或基于令牌的映射。但是这两种方法都不支持任意角色映射逻辑。例如,当您需要解释多值用户属性以识别目标角色时。

这篇文章介绍如何使用亚马逊 Cognito 代币生成前的 亚马逊云科技 Lambda 触发器来实现自定义角色映射。 例如,我们使用通过 OpenID Connect (OIDC) 向亚马逊 Cognito 提供的多值属性。我们将介绍您如何完全控制此类用于 亚马逊云科技 身份和访问管理 (IAM) 角色查找的多值属性的映射逻辑和 过程。我们的方法适用于兼容 OIDC 的 IdP。为了使这篇文章自成一体,我们使用 Okta IdP 作为示例来完成设置。

解决方案概述

提供的解决方案使用代币生成前的 Lambda 函数拦截基于 Oicd 的 OpenSearch 仪表板登录过程。使用第三方 IdP 和 Amazon Cognito 作为中介登录 OpenSearch 控制面板包括以下几个步骤:

  1. 首先,用户对 OpenSearch 控制面板的初始请求被重定向到亚马逊 Cognito。
  2. Amazon Cognito 将请求重定向到 IdP 进行身份验证。
  3. 用户进行身份验证后,IdP 会将身份令牌(身份令牌)发送回 Amazon Cognito。
  4. Amazon Cognito 调用 Lambda 函数来修改获得的代币。我们使用 亚马逊 Dynamo DB 表来执行角色映射查询。修改后的令牌现在包含 IAM 角色映射信息。
  5. Amazon Cognito 使用此角色映射信息将用户映射到指定的 IAM 角色并提供角色证书。
  6. OpenSearch 服务将 IAM 角色证书映射到 OpenSearch 角色并应用精细的权限检查。

以下架构从用户的角度概述了登录流程。

Scope of solution

在后端,OpenSearch 控制面板在身份验证流程中集成了亚马逊 Cognito 用户池和亚马逊 Cognito 身份池。步骤如下:

  1. 进行身份验证并获取令牌。
  2. 查找代币属性和 IAM 角色映射,然后覆盖 Amazon Cognito 属性。
  3. 使用令牌兑换 OpenSearch 控制面板使用的 亚马逊云科技 证书。

以下架构显示了身份验证过程的后端视角。

Backend authentication flow

在本文的其余部分中,我们将介绍身份验证流程所需的配置,其中 Lambda 函数实现自定义角色映射逻辑。我们提供示例 Lambda 代码,用于根据具有以下结构的 DynamoDB 查询表将多值 OIDC 属性映射到 IAM 角色。

OIDC Attribute Value IAM Role
["attribute_a","attribute_b"] arn:aws:iam:: <aws-account-id> :role/ <role-name-01>
["attribute_a","attribute_x"] arn:aws:iam:: <aws-account-id> :role/ <role-name-02>

这篇文章中提出的解决方案的高级步骤如下:

  1. 为 OpenSearch 控制面板配置 Amazon Cognito 认证。
  2. 添加 IAM 角色以映射到 OpenSearch 服务角色。
  3. 配置 Okta IdP。
  4. 将第三方 OIDC IdP 添加到亚马逊 Cognito 用户池。
  5. 将 IAM 角色映射到 OpenSearch 服务角色。
  6. 创建 DynamoDB 属性角色映射表。
  7. 部署和配置代币生成前 Lambda 函数。
  8. 配置代币生成前 Lambda 触发器。
  9. 测试登录 OpenSearch 控制面板。

先决条件

在本演练中,您应该具备以下先决条件:

  • 具有 OpenS earch 服务域 亚马逊云科技 账户
  • 支持 OpenID Connect 并在授权令牌中添加多值属性的第三方 IdP。在这篇文章中,我们使用 attributes_array 作为该属性的名称,使用 Okta 作为 IdP 提供商。你可以创建一个 Okta 开发者版 免费账户来测试设置。

为 OpenSearch 控制面板配置 Amazon Cognito 认证

修改认证令牌需要您配置 OpenSearch 服务域以使用 Amazon Cognito 进行身份验证。有关说明,请参阅为 OpenSearc h 控制面板配置 Amazon Cognito 认证。

Lambda 函数通过设置 cognito: preferred_role 声明来实现自定义角色映射(有关更多信息,请参阅基于角色 的访问控制)。 为了正确解释此声明,请将 Amazon Cognito 身份池设置为 从代 币中选择角色 。 然后,Amazon Cognito 身份池使用 cogn ito: preferred_role 声明的值来选择 正确的 IAM 角色。以下屏幕截图显示了在配置 OpenSearch 服务的 Amazon Cognito 身份验证期间创建的 Amazon Cognito 身份池中的所需设置。

Cognito role mapping configuration

添加 IAM 角色以映射到 OpenSearch 角色

用于映射到 OpenSearch 角色的 IAM 角色需要信任策略,以便经过身份验证的用户可以代入这些角色。信任策略需要引用在 OpenSearch 服务配置 Amazon Cognito 身份验证期间创建的 Amazon Cognito 身份池。使用自定义信任策略创建至少一个 IAM 角色。有关说明,请参阅 使用自定义信任策略 创建角色 。IAM 角色不需要附加权限策略。有关信任策略示例,请参阅 基于角色的访问控制

配置 Okta IdP

在本节中,我们描述了在 Okta 提供的令牌中包含多值 attribute_array 属性的配置步骤。有关更多信息,请参阅使用自定义 声明 自定义从 Okta 返回的代币 。我们使用 Okta 用户界面来执行配置。Okta 还提供了一个 API,你可以用它来编写脚本和自动执行设置。

第一步是将 attributes_array 属性添加到 Okta 用户配置文件中。

  1. 在 “ 目录 配置文件编辑器” 下使用 Okta 的 配置文件编辑器
  2. 选择 “ 用户”(默认) ,然后选择 “ 添加属性”
  3. 添加具有显示名称和变量名 at tributes_array 类型 为字符串数组 的属性

以下屏幕截图显示了添加自定义属性后的 Okta 默认用户配置文件。

Okta user profile editor

  1. 接下来,使用 Okta 的用户管理界面在 “目录,人物” 下 为用户添加 att ributes_array 属性值。
  2. 选择一个用户并选择 “ 个人资料 ” 。
  3. 选择 “编辑” 并输入属性值。

以下屏幕截图显示了用户配置文件中 attributes_array 属性值的示例。

Okta user attributes array

下一步是将 attributes_array 属性添加到身份验证过程中生成的 ID 令牌中。

  1. 在 Okta 控制台上,选择 安全 API 并选择 默认 的 授权服务器。
  2. 选择 “ 声明 ” ,然后选择 “ 添加声明 ” ,将 attributes_array 属性添加为 ID 令牌的一部分。
  3. 输入 openid 作为作用域,输入 user .attributes_array 作为属性值。

这引用了用户个人资料中先前创建的属性。

Add claim to ID token

  1. 接下来,使用 Amazon Cognito 创建联合应用程序。有关说明,请参阅 如何在亚马逊 Cognito 用户池中将 Okta 设置为 OpenID Connect 身份提供商

最后一步将 Okta 应用程序分配给 Okta 用户。

  1. 导航到 “ 目录 ” 、“ 人员 ” ,选择用户,然后选择 “ 分配应用程序 ” 。
  2. 选择您在上一步中创建的应用程序。

将第三方 OIDC IdP 添加到亚马逊 Cognito 用户池

我们正在根据多值 OIDC 属性中提供的信息实现角色映射。身份验证令牌需要包含此属性。如果您遵循前面描述的 Okta 配置,则该属性会自动添加到用户的 ID 令牌中。如果您使用其他 IdP,则可能需要明确请求该属性。为此,请将属性名称添加到 Amazon Cogn ito 中 IdP 的 授权范围 列表中。

有关如何设置第三方 IdP 和 Amazon Cognito 用户池之间的联合以及如何请求其他属性的说明,请参阅 向用户池添加 OIDC 身份提供商 。 有关 Okta 的详细介绍,请参阅 如何在 Amazon Cognito 用户池中将 Okta 设置为 OpenID Connect 身份提供商

通过 OIDC 请求令牌后,您需要将该属性映射到 Amazon Cognito 用户池属性。有关说明,请参阅为 您的用户池 指定身份提供商属性映射 。以下屏幕截图显示了 Amazon Cognito 控制台上生成的配置。

Amazon Cognito user pool attribute mapping

将 IAM 角色映射到开放搜索服务角色

登录后,OpenSearch Service 根据代币生成前 Lambda 触发 器在 cognito: preferred_role 声明中设置的 IAM 角色 ARN,将用户映射到 O penSearch 服务角色。这需要在 OpenSearch 服务中进行角色映射。要将此类角色映射添加到 IAM 后端角色,请参阅将 角色 映射到用户 。以下屏幕截图显示了 OpenSearch 仪表板控制台上的角色映射。

Amazon OpenSearch Service role mappings

创建属性角色映射表

对于此解决方案,我们使用 DynamoDB 存储用户到 IAM 角色的映射。 有关说明,请参阅 创建表 并定义名为 Key 的分区键,类型为 String 您需要在后续步骤中使用表名来配置 Lambda 函数。

下一步是将映射信息写入表中。映射条目包含以下属性:

  • Key — 包含按逗号分隔的字母顺序排列的属性值的字符串
  • RoLearn — 带有 IAM 角色 ARN 的字符串,属性值组合应映射到该字符串

有关如何向 DynamoDB 表中添加数据的详细信息,请参阅 使用控制台或 亚马逊云科技 CLI 将数据 写入表

例如,如果先前配置的 OIDC 属性 attrib utes_array 包含三个值,即属性 _a 、属性_ b 和 属性_ c ,则映射表中的条目看起来像以下屏幕截图 中的 表行 1。

Amazon DynamoDB table with attribute-role mappings

部署和配置代币生成前 Lambda 函数

Lambda 函数实现自定义角色映射逻辑。Lambda 函数接收 Amazon Cognito 事件作为输入,并从中提取属性信息。 它使用属性信息在 DynamoDB 表中进行查找,并检索 cognito: preferred_role 的值。 照 Lambda 入门 中的步骤创建 Node.js Lambda 函数并插入以下源代码:

const AWS = require("aws-sdk");
const tableName = process.env.TABLE_NAME;
const unauthorizedRoleArn = process.env.UNAUTHORIZED_ROLE;
const userAttributeArrayName = process.env.USER_POOL_ATTRIBUTE;
const dynamodbClient = new AWS.DynamoDB({apiVersion: "2012-08-10"});
exports.lambdaHandler = handlePreTokenGenerationEvent

async function handlePreTokenGenerationEvent (event, context) {
    var sortedAttributeList = getSortedAttributeList(event);
    var lookupKey = sortedAttributeList.join(',');
    var roleArn = await lookupIAMRoleArn(lookupKey);
    appendResponseWithPreferredRole(event, roleArn);
    return event;
}

function getSortedAttributeList(event) {
    return JSON.parse(event['request']['userAttributes'][userAttributeArrayName]).sort();
}

async function lookupIAMRoleArn(key) {
    var params = {
        TableName: tableName,
        Key: {
          'Key': {S: key}
        },
        ProjectionExpression: 'RoleArn'
      };
    try {
        let item = await dynamodbClient.getItem(params).promise();
        return item['Item']['RoleArn']['S'];
    } catch (e){
        console.log(e);
        return unauthorizedRoleArn; 
    }
}

function appendResponseWithPreferredRole(event, roleArn){
    event.response = {
        'claimsOverrideDetails': {
            'groupOverrideDetails': {
                'preferredRole': roleArn
            }
        }
    };
}

Lambda 函数需要三个环境变量。有关添加以下条 目的说明,请参阅 使用 亚马逊云科技 Lambda 环境 变量:

  • 表名 — 先前创建的 DynamoDB 表的名称。此表用于查询。
  • UNAUTHORIZED_ ROLE — 在查找表中找不到映射时使用的 IAM 角色的 ARN。
  • USER_POOL_ATTRIBUTE — 用于 IAM 角色查询的 Amazon Cognito 用户池属性。在我们的示例中,此属性被命名为 custom : attributes_array

以下屏幕截图显示了最终配置。

AWS Lamba function configuration

Lambda 函数需要权限才能访问 DynamoDB 查找表。按如下方式设置权限:将以下策略附加到 Lambda 执行角色(有关说明,请参阅 Lambda 执行角色 ),并提供区域、亚马逊云科技 账号和 DynamoDB 表名:

{
    "Statement": [
        {
            "Action": [
                "dynamodb:GetItem",
                "dynamodb:Scan",
                "dynamodb:Query",
                "dynamodb:BatchGetItem",
                "dynamodb:DescribeTable"
            ],
            "Resource": [
                "arn:aws:dynamodb:<region>:<accountid>:table/<table>",
                "arn:aws:dynamodb:<region>:<accountid>:table/<table>/index/*"
            ],
            "Effect": "Allow"
        }
    ]
}

Lambda 函数的配置现已完成。

配置代币生成前 Lambda 触发器

最后一步,向 Amazon Cognito 用户池中添加代币生成前触发器,并引用新创建的 Lambda 函数。有关详细信息,请参阅使用 Lambda 触发器 自定义用户池工作流程 。 以下屏幕截图显示了配置。

Amazon Cognito pre-token generation trigger configuration

此步骤完成了设置;Amazon Cognito 现在根据 OIDC 属性中提供的值将用户映射到 OpenSearch 服务角色。

测试 OpenSearch 仪表板的登录信息

下图显示了具有用户配置文件 属性 attribute_array 和值的 Okta 用户1 的示例登录流程和相应的屏幕截图: ["attribute_ a”、“attribute_b”、“attribute_c” ]。

Testing of solution

清理

为了避免将来产生费用,请删除作为本文一部分创建的 OpenSearch 服务域、Amazon Cognito 用户池和身份池、Lambda 函数和 DynamoDB 表。

结论

在这篇文章中,我们演示了如何使用通过 OIDC 属性提供的值设置与 OpenSearch 服务角色的自定义映射。我们 使用代币生成前 Amazon Cognito Lambda 触发器和用于查询的 DynamoDB 表动态设置 cognito: preferred_role 声明 。该解决方案能够处理动态多值用户属性,但除了简单查找之外,您还可以使用其他应用程序逻辑对其进行扩展。这篇文章中的步骤是概念验证。如果您计划将其开发成高效的解决方案,我们建议您实施 Okta 和 亚马逊云科技 安全最佳实践

这篇文章仅重点介绍了如何使用 Amazon Cognito 对 Lambda 触发器的支持来实现自定义身份验证需求的一个用例。如果您对更多详细信息感兴趣,请参阅 如何使用 Cognito 代币生成前触发器自定义 ID 代币中的声明


作者简介

Portrait Stefan Stefan Appel 是 亚马逊云科技 的高级解决方案架构师。10 多年来,他一直支持企业客户采用云技术。在加入 亚马逊云科技 之前,Stefan 曾在软件架构、产品管理和 IT 运营部门任职。他的职业生涯始于基于事件的系统的研究。在业余时间,他喜欢徒步旅行,并沿着蒂阿拉罗阿走遍了新西兰。

Portrait Modood Modood Alvi 是亚马逊网络服务 (亚马逊云科技) 的高级解决方案架构师。Modood 热衷于数字化转型,致力于帮助全球大型企业客户加速采用和迁移到云端。Modood在软件开发领域拥有十多年的经验,曾在SAP和保时捷数字等公司担任过各种技术职务。Modood 获得了斯图加特大学的计算机科学文凭。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。