使用 Amazon QuickSight 执行安全的数据库回写

使用 Amazon QuickSight 执行安全的数据库回写

源节点: 2641420

亚马逊QuickSight 是一种可扩展、无服务器、由机器学习 (ML) 提供支持的商业智能 (BI) 解决方案,可以轻松连接到您的数据、创建交互式仪表板、访问支持 ML 的见解以及与数以万计的人共享视觉效果和仪表板内部和外部用户,无论是在 QuickSight 本身内还是嵌入到任何应用程序中。

回写是从 BI 仪表板内更新数据集市、数据仓库或任何其他数据库后端并在仪表板本身内近乎实时地分析更新数据的能力。 在本文中,我们展示了如何使用 QuickSight 执行安全的数据库回写。

用例概述

为了演示如何使用 QuickSight 启用回写功能,让我们考虑一家虚构的公司 AnyCompany Inc. AnyCompany 是一家专业服务公司,专门为其客户提供劳动力解决方案。 AnyCompany 确定在云中运行工作负载以支持其不断增长的全球业务需求是一种竞争优势,并使用云来托管其所有工作负载。 AnyCompany 决定改进其分支机构向客户提供报价的方式。 目前,分支机构手动生成客户报价,作为这一创新之旅的第一步,AnyCompany 正在寻求开发一种用于生成客户报价的企业解决方案,该解决方案能够在生成报价时动态应用本地定价数据。

AnyCompany目前使用 亚马逊Redshift 作为他们的企业数据仓库平台和 QuickSight 作为他们的 BI 解决方案。

构建新的解决方案会面临以下挑战:

  • AnyCompany 想要一个易于构建和维护的解决方案,他们不想投资构建单独的用户界面。
  • AnyCompany 希望扩展其现有 QuickSight BI 仪表板的功能,以支持报价生成和报价接受。 这将简化功能推出,因为他们的员工已经在使用 QuickSight 仪表板并享受 QuickSight 提供的易于使用的界面。
  • AnyCompany 想要存储报价谈判历史记录,包括生成的、审查的和接受的报价。
  • AnyCompany 想要构建一个包含报价历史数据的新仪表板,用于分析和业务洞察。

这篇博文介绍了从 QuickSight 向 Amazon Redshift 启用回写功能的步骤。 请注意,传统的 BI 工具是只读的,几乎没有更新源数据的选项。

解决方案概述

此解决方案使用以下 AWS 服务:

尽管此解决方案使用 Amazon Redshift 作为数据存储,但可以使用任何支持创建可调用 Lambda 的用户定义函数 (UDF) 的数据库来实施类似的方法。

下图显示了从 QuickSight 执行回写的工作流程。

解决方案的第一步是通过调用 Lambda 函数在 Amazon Redshift 中生成一组属性的哈希或消息摘要。 此步骤可防止请求篡改。 为了生成哈希,Amazon Redshift 调用了一个 标量 Lambda UDF. 这里使用的哈希机制是流行的 布莱克2 函数(在 Python 库中可用 哈希库). 为了进一步保护散列,使用了键控散列,这是一种更快、更简单的替代方法 基于散列的消息认证码 (HMAC)。 此密钥由 Secrets Manager 生成和存储,并且应该只能由允许的应用程序访问。 生成安全哈希后,它会返回到 Amazon Redshift 并合并到 Amazon Redshift 视图中。

将生成的报价写回 Amazon Redshift 由写回 Lambda 函数执行,并创建 API 网关 REST API 端点以保护请求并将其传递给写回函数。 回写函数执行以下操作:

  1. 根据从 QuickSight 收到的 API 输入参数生成哈希。
  2. 通过应用来自 Secrets Manager 的密钥对散列进行签名。
  3. 使用 compare_digest 方法将生成的散列与从输入参数接收的散列进行比较 哈马卡 模块。
  4. 验证成功后,将记录写入 Amazon Redshift 中的报价提交表。

以下部分提供了带有示例负载和代码片段的详细步骤。

生成哈希

哈希是使用 Amazon Redshift 中的 Lambda UDF 生成的。 此外,Secrets Manager 密钥用于对散列进行签名。 要创建散列,请完成以下步骤:

  1. 从创建 Secrets Manager 密钥 AWS命令行界面 (AWS CLI):
aws secretsmanager create-secret --name “name_of_secret” --description "Secret key to sign hash" --secret-string '{" name_of_key ":"value"}' --region us-east-1

  1. 创建 Lambda UDF 以生成用于加密的哈希:
import boto3 import base64
import json
from hashlib import blake2b
from botocore.exceptions import ClientError def get_secret(): #This key is used by the Lambda function to further secure the hash. secret_name = "<name_of_secret>" region_name = "<aws_region_name>" # Create a Secrets Manager client session = boto3.session.Session() client = session.client(service_name='secretsmanager', region_name=<aws_region_name> ) # In this sample we only handle the specific exceptions for the 'GetSecretValue' API. # See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html # We rethrow the exception by default. try: get_secret_value_response = client.get_secret_value(SecretId=secret_name) except Exception as e: raise e if "SecretString" in get_secret_value_response: access_token = get_secret_value_response["SecretString"] else: access_token = get_secret_value_response["SecretBinary"] return json.loads(access_token)[<token key name>] SECRET_KEY = get_secret()
AUTH_SIZE = 16 def sign(payload): h = blake2b(digest_size=AUTH_SIZE, key=SECRET_KEY) h.update(payload) return h.hexdigest().encode('utf-8') def lambda_handler(event, context):
ret = dict() try: res = [] for argument in event['arguments']: try: msg = json.dumps(argument) signed_key = sign(str.encode(msg)) res.append(signed_key.decode('utf-8')) except: res.append(None) ret['success'] = True ret['results'] = res except Exception as e: ret['success'] = False ret['error_msg'] = str(e) return json.dumps(ret)

  1. 定义 Amazon Redshift UDF 以调用 Lambda 函数来创建哈希:
CREATE OR REPLACE EXTERNAL FUNCTION udf_get_digest (par1 varchar)
RETURNS varchar STABLE
LAMBDA 'redshift_get_digest'
IAM_ROLE 'arn:aws:iam::<AWSACCOUNTID>role/service-role/<role_name>';

AWS身份和访问管理 上一步中的 (IAM) 角色应附加以下策略才能调用 Lambda 函数:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": "arn:aws:lambda:us-east-1:<AWSACCOUNTID>1:function:redshift_get_digest" }
}

  1. 从 Secrets Manager 获取密钥。

Lambda 函数使用此密钥来进一步保护散列。 这在 获取秘密 在步骤 2 中的功能。

在 QuickSight 中设置 Amazon Redshift 数据集

报价生成控制面板使用以下 Amazon Redshift 视图。

创建一个使用前面所有列以及哈希列的 Amazon Redshift 视图:

create view quote_gen_vw as select *, udf_get_digest ( customername || BGCheckRequired || Skill|| Shift ||State ||Cost ) from billing_input_tbl

记录将类似于以下屏幕截图。

前面的视图将用作 QuickSight 数据集来生成报价。 将使用数据集创建 QuickSight 分析。 对于近乎实时的分析,您可以使用 QuickSight 直接查询模式。

创建 API 网关资源

回写操作由 QuickSight 调用 API 网关资源启动,该资源调用 Lambda 回写函数。 作为在 QuickSight 中创建计算字段以调用回写 API 的先决条件,您必须首先创建这些资源。

API Gateway 使用映射模板创建为 URL 查询字符串参数的参数来保护和调用回写 Lambda 函数。 使用 Lambda 代理集成可以避免映射参数。

创建使用 Lambda 函数(在下一步中创建)作为集成类型的方法类型 GET 的 REST API 资源。 有关说明,请参阅 在 Amazon API Gateway 中创建 REST API在 API Gateway 中设置 Lambda 集成.

以下屏幕截图显示了为传递给 API 网关的每个参数创建查询字符串参数的详细信息。

以下屏幕截图显示了为传递给 API 网关的每个参数创建映射模板参数的详细信息。

创建 Lambda 函数

创建一个新的 Lambda 函数供 API 网关调用。 Lambda 函数执行以下步骤:

  1. 通过 API 网关从 QuickSight 接收参数并对连接的参数进行哈希处理。

以下代码示例使用 Lambda 函数的事件对象从 API 网关调用中检索参数:

 customer= event['customer’]) bgc = event['bgc']

该函数执行哈希逻辑,如 创建散列 使用 QuickSight 传递的串联参数更早一步。

  1. 将散列输出与散列参数进行比较。

如果这些不匹配,则不会发生回写。

  1. 如果哈希匹配,则执行回写。 通过使用从 QuickSight 传递的参数从表中生成查询来检查报价生成表中是否存在记录:
query_str = "select * From tbquote where cust = '" + cust + "' and bgc = '" + bgc +"'" +" and skilledtrades = '" + skilledtrades + "' and shift = '" +shift + "' and jobdutydescription ='" + jobdutydescription + "'"

  1. 根据查询结果完成以下操作:
    1. 如果前面的组合不存在记录,则使用状态为已生成的所有参数生成并运行插入查询。
    2. 如果前面的组合存在记录,则生成并运行状态为审查中的插入查询。 现有组合的 quote_Id 将被重复使用。

创建 QuickSight 视觉对象

此步骤涉及创建一个表视觉对象,它使用计算字段将参数传递给 API 网关并调用前面的 Lambda 函数。

  1. 添加一个名为 Generate Quote 的 QuickSight 计算字段以保存 API 网关托管 URL,该 URL 将被触发以将报价历史记录写回 Amazon Redshift:
concat("https://xxxxx.execute-api.us-east-1.amazonaws.com/stage_name/apiresourcename/?cust=",customername,"&bgc=",bgcheckrequired,"&billrate=",toString(billrate),"&skilledtrades=",skilledtrades,"&shift=",shift,"&jobdutydescription=",jobdutydescription,"&hash=",hashvalue)

  1. 创建 QuickSight 表视觉对象。
  2. 添加必填字段,例如客户、技能和成本。
  3. 添加生成报价计算字段并将其设置为超链接。

选择此链接会将记录写入 Amazon Redshift。 当 Lambda 函数对参数执行哈希时,返回相同的哈希值是有责任的。

以下屏幕截图显示了一个示例表视觉效果。

写入 Amazon Redshift 数据库

Lambda 函数获取并使用 Secrets Manager 密钥来生成用于比较的散列。 仅当散列与参数中传递的散列相匹配时,才会执行回写。

以下 Amazon Redshift 表将捕获由 Lambda 函数填充的报价历史记录。 绿色记录代表报价的最新记录。

注意事项和后续步骤

使用安全哈希可防止在调用回写 URL 时篡改浏览器窗口中可见的有效负载参数。 为了进一步保护回写 URL,您可以采用以下技术:

  • 在只有 QuickSight 用户可以访问的私有 VPC 中部署 REST API。
  • 为了防止重放攻击,可以与哈希函数一起生成时间戳,并作为附加参数传递到回写 URL 中。 然后可以修改后端 Lambda 函数以仅允许在某个基于时间的阈值内进行回写。
  • 关注 API 网关 访问控制保安 最佳做法。
  • 减轻 面向公众的 API 的潜在拒绝服务。

您可以进一步增强此解决方案以在打开回写 URL 时呈现基于 Web 的表单。 这可以通过在后端 Lambda 函数中动态生成 HTML 表单来支持附加信息的输入来实现。 如果您的工作负载需要大量需要更高吞吐量或并发性的回写,则可以使用专门构建的数据存储,例如 Amazon Aurora PostgreSQL 兼容版 可能是更好的选择。 有关详细信息,请参阅 从 Aurora PostgreSQL 数据库集群调用 AWS Lambda 函数. 然后可以使用这些更新将这些更新同步到 Amazon Redshift 表中 联合查询.

结论

这篇博文展示了如何将 QuickSight 与 Lambda、API 网关、Secrets Manager 和 Amazon Redshift 结合使用来捕获用户输入数据并安全地更新您的 Amazon Redshift 数据仓库,而无需离开您的 QuickSight BI 环境。 该解决方案无需为数据库更新或插入操作创建外部应用程序或用户界面,并减少了相关的开发和维护开销。 API 网关调用也可以使用密钥或令牌来保护,以确保 API 网关只接受来自 QuickSight 的调用。 这将在后续帖子中介绍。


作者简介

斯里坎特·巴赫蒂 是 Amazon QuickSight 的专业全球首席解决方案架构师。 他的职业生涯始于一名顾问,并曾在多个私人和政府组织工作。 后来他在 PerkinElmer Health and Sciences & eResearch Technology Inc 工作,负责设计和开发高流量 Web 应用程序、高度可扩展和可维护的数据管道,用于使用 AWS 服务和无服务器计算的报告平台。

拉吉·西瓦苏布拉马尼亚姆 是 AWS 的高级解决方案架构师,专注于分析。 Raji 专门为全球财富 500 强和财富 100 强公司构建端到端企业数据管理、商业智能和分析解决方案。 她在集成医疗保健数据和分析方面拥有丰富的经验,涉及各种医疗保健数据集,包括托管市场、医生定位和患者分析。

时间戳记:

更多来自 AWS 大数据