为亚马逊 SQS 实施 亚马逊云科技 架构完善的最佳实践 — 第 2 部分

作者: 帕斯卡尔·沃格尔 | 2023

本博客由高级解决方案架构师Chetan Makvana和高级解决方案架构师Hardik Vasa撰写。

这是由三部分组成的博客文章系列的第二部分,该系列演示了如何 使用 亚马逊云科技 架构 完善的框架实施 亚马逊简单队列服务 (Amazon SQ S ) 的最佳实践。

这篇博文介绍了使用 亚马逊云科技 架构完善 框架 的安全支 柱 和 可靠 性支柱 的最佳实践。该 系列第一部分中 介绍的 库存管理示例 将继续作为示例。

另请参见该系列的其他两个部分:

  • 为亚马逊 SQS 实施 亚马逊云科技 架构完善的最佳实践 — 第 1 部分:卓越运营
  • 为 Amazon SQS 实施 亚马逊云科技 架构完善的最佳实践 — 第 3 部分:性能效率、成本优化和可持续性

安全支柱

安全支柱 包括保护数据、系统和资产以及利用云技术来提高安全性的能力。该支柱建议采取影响安全的做法。使用这些最佳实践,您可以在数据传输(进出 SQS 时)和静止状态(存储在 SQS 中的磁盘上)时保护数据,或者控制谁可以使用 SQS 做什么。

最佳实践:配置服务器端加密

如果您的应用程序具有强制加密的 HIPAA、GDPR 或 PCI-DSS 等合规性要求,如果您希望提高数据安全性以防止未经授权的访问,或者如果您只是想简化发送到 SQS 队列的消息的密钥管理,则可以利用服务器端加密 (SSE) 来保护存储在 SQS 上的数据的隐私和完整性。

SQS 和 亚马逊云科技 密钥管理服务 (KMS) 为配置服务器端加密 提供了两个选项。SQS 管理的加密密钥 (SSE-SQS) 使用 亚马逊云科技 管理的密钥自动加密存储在 SQS 队列中的消息。创建队列时,默认情况下,此功能处于启用状态。如果您选择使用自己的 亚马逊云科技 KMS 密钥来加密和解密存储在 SQS 中的消息,则可以使用 SSE-KMS 功能。

Amazon SQS Encryption Settings

SSE-KMS 为加密密钥提供了更大的控制和灵活性,而 SSE-SQS 通过为您管理加密密钥来简化流程。这两个选项都可通过加密 SQS 队列中的静态数据来帮助您保护敏感数据并遵守监管要求。请注意,SSE-SQS 仅加密消息正文,而不加密消息属性。

第 1 部分 介绍的库存管理示例中 ,当库存更新文件被放入 亚马逊简单存储 服务 (Amazon S3) 存储 桶时,负责 CSV 处理的 亚马逊云科技 Lambda 函数会将传入消息发送到 SQS 队列。 SQS 使用 SQS-SSE 对队列中的这些消息进行加密。 当后端处理 Lambda 轮询队列中的消息时,加密的消息将被解密,并且该函数会将库存更新插入到 Amazon DynamoD B 中。

亚马逊云科技 云开发套件 (亚马逊云科技 CDK) 代码将 SSE-SQS 设置为默认加密密钥类型。但是,以下 亚马逊云科技 CDK 代码显示了如何使用 SSE-KMS 加密队列。

# Create the SQS queue with DLQ setting
queue = sqs.Queue(
    self,
    "InventoryUpdatesQueue",
    visibility_timeout=Duration.seconds(300),
    encryption=sqs.QueueEncryption.KMS_MANAGED,
)

最佳实践:使用访问策略实现最低权限访问

为了保护您在 亚马逊云科技 中的资源,实施最低权限访问至关重要。这意味着向用户和服务授予执行其任务所需的最低访问权限级别。最低权限访问权限可提供更高的安全性,使您能够满足合规性要求,并通过对谁访问了哪些资源和何时进行了清晰的审计跟踪来提供问责制。

通过使用访问策略实施最低权限访问,您可以帮助降低安全漏洞的风险,并确保只有授权用户和服务才能访问您的资源。 亚马逊云科技 身份和访问管理 (IAM ) 策略适用于用户、群组和角色,而基于资源的策略适用于 SQS 队列等 亚马逊云科技 资源。要实现最低权限访问权限,必须首先定义每个用户或服务需要哪些操作才能执行其任务。

在库存管理示例中,CSV 处理 Lambda 函数除了解析库存更新文件并将库存记录发送到 SQS 队列进行进一步处理外,不执行任何其他任务。为确保该函数有权向 SQS 队列发送消息,请向该 SQS 队列授予 Lambda 函数承担的 IAM 角色的访问权限。通过向 SQS 队列授予 Lambda 函数的 IAM 角色的访问权限,您可以建立安全且受控的通信渠道。Lambda 函数只能与 SQS 队列进行交互,并且没有可能危及系统安全性的不必要的访问权限或权限。

# Create pre-processing Lambda function
csv_processing_to_sqs_function = _lambda.Function(
    self,
    "CSVProcessingToSQSFunction",
    runtime=_lambda.Runtime.PYTHON_3_8,
    code=_lambda.Code.from_asset("sqs_blog/lambda"),
    handler="CSVProcessingToSQSFunction.lambda_handler",
    role=role,
    tracing=Tracing.ACTIVE,
)

# Define the queue policy to allow messages from the Lambda function's role only
policy = iam.PolicyStatement(
    actions=["sqs:SendMessage"],
    effect=iam.Effect.ALLOW,
    principals=[iam.ArnPrincipal(role.role_arn)],
    resources=[queue.queue_arn],
)

queue.add_to_resource_policy(policy)

最佳实践:仅允许使用 aws: SecureTransport 通过 HTTPS 进行加密连接

必须采用安全可靠的方法在 亚马逊云科技 服务与本地环境或其他外部系统之间传输数据。使用 HTTPS,基于网络的攻击者无法使用中间人之类的攻击来窃听或操纵网络流量。

使用 SQS,您可以使用队列策略中的 aws: SecureTransport 条件密钥选择仅允许通过 HTTPS 进行加密连接。在这种情况下,任何通过非安全 HTTP 发出的请求都会收到来自 SQS 的 400 InvalidSecurity 错误。

在库存管理示例中,CSV 处理 Lambda 函数将库存更新发送到 SQS 队列。为了确保安全的数据传输,Lambda 函数使用 SQS 提供的 HTTPS 端点。这可以保证 Lambda 函数和 SQS 队列之间的通信保持加密状态并抵御潜在的安全威胁。

# Create an IAM policy statement allowing only HTTPS access to the queue
secure_transport_policy = iam.PolicyStatement(
    effect=iam.Effect.DENY,
    actions=["sqs:*"],
    resources=[queue.queue_arn],
    conditions={
        "Bool": {
            "aws:SecureTransport": "false",
        },
    },
)

最佳实践:使用基于属性的访问控制 (ABAC)

一些用例需要精细的访问控制。例如,根据用户角色、环境、部门或位置对用户进行授权。此外,需要根据用户属性的变化进行动态授权。在这种情况下,您需要基于用户属性的访问控制机制。

基于属性的访问控制 (ABAC) 是一种授权策略,它根据附加到用户和 亚马逊云科技 资源的标签定义权限。使用 ABAC,您可以使用标签为队列配置 IAM 访问权限和策略。因此,ABAC 使您能够轻松扩展权限管理。您可以使用为每个业务角色创建的标签在 IAM 中创建单一权限策略,添加新资源时无需再更新策略。

适用于 SQS 队列的 ABAC 支持两个关键用例:

  • 基于标签的访问控制:使用标签控制对 SQS 队列的访问权限,包括控制平面和数据平面 API 调用。
  • 创建时标记:在创建 SQS 队列时强制使用标签,并拒绝创建没有标签的 SQS 资源。

可靠性支柱

可靠性支柱 包括工作负载在预期时间内正确、持续地执行其预期功能的能力。通过利用本支柱中概述的最佳实践,您可以增强在 SQS 中管理消息的方式。

最佳实践:配置死信队列

在分布式系统中,当消息在子系统之间流动时,可能无法立即处理某些消息。这可能是因为消息已损坏或下游处理暂时不可用。在这种情况下,不良消息阻止队列中的其他消息是不理想的。

SQS 中的@@ 死信队列 (DLQ) 可以提供额外的容错层、简化调试、提供重试机制以及将有问题的消息与主队列分开,从而提高应用程序的可靠性。通过将 DLQ 整合到应用程序架构中,您可以构建更强大、更可靠的系统,该系统可以处理错误并保持较高的性能和可用性。

在库存管理示例中,DLQ 在增加消息灵活性和防止出现一条错误消息阻碍其他消息处理的情况方面起着至关重要的作用。如果后端 Lambda 函数在多次尝试后失败,则库存更新消息将重定向到 DLQ。通过检查这些未使用的消息,您可以排除故障,然后使用 DL Q redrive 功能将其重新驱动到主队列或自定义目的地。 您还可以通过以 编程方式 使用 一组 API 来自动重启。这可确保准确的库存更新并防止数据丢失。

以下 亚马逊云科技 CDK 代码片段显示了如何为源队列创建 DLQ 以及如何设置 DLQ 策略以仅允许来自源 SQS 队列的消息。建议不要将 max_receive_count 值设置为 1,尤其是在使用 Lambda 函数作为使用者时,以免在 DLQ 中积累大量消息。

# Create the Dead Letter Queue (DLQ)
dlq = sqs.Queue(self, "InventoryUpdatesDlq", visibility_timeout=Duration.seconds(300))

# Create the SQS queue with DLQ setting
queue = sqs.Queue(
    self,
    "InventoryUpdatesQueue",
    visibility_timeout=Duration.seconds(300),
    dead_letter_queue=sqs.DeadLetterQueue(
        max_receive_count=3,  # Number of retries before sending the message to the DLQ
        queue=dlq,
    ),
)
# Create an SQS queue policy to allow source queue to send messages to the DLQ
policy = iam.PolicyStatement(
    effect=iam.Effect.ALLOW,
    actions=["sqs:SendMessage"],
    resources=[dlq.queue_arn],
    conditions={"ArnEquals": {"aws:SourceArn": queue.queue_arn}},
)
queue.queue_policy = iam.PolicyDocument(statements=[policy])

最佳实践:通过配置正确的可见性超时及时处理消息

设置适当的可见性超时对于在 SQS 中高效处理消息至关重要。可见性超时是指从队列中轮询消息后,SQS 阻止其他使用者接收和处理消息的时段。

要确定应用程序的理想可见性超时,请考虑您的具体用例。如果您的应用程序通常在几秒钟内处理消息,请将可见性超时设置为几分钟。这可确保多个消费者不会同时处理消息。如果您的应用程序需要更多时间来处理消息,可以考虑将其分解为较小的单元或对其进行批处理以提高性能。

如果消息处理失败并返回到队列,则在可见性超时时间过后才能再次对其进行处理。增加可见性超时将增加应用程序的整体延迟。因此,在降低消息重复的可能性和维护响应式应用程序之间取得平衡非常重要。

在库存管理示例中,设置正确的可见性超时有助于应用程序快速失败并缩短消息处理时间。由于 Lambda 函数通常在毫秒内处理消息,因此在以下 亚马逊云科技 CDK 代码片段中将可见性超时设置为 30 秒。

queue = sqs.Queue(
    self,
    " InventoryUpdatesQueue",
    visibility_timeout=Duration.seconds(30),
)

建议将 SQS 队列可见性超时设置为 Lambda 函数超时 值的至少六倍,再加上 maximumBatchingWindowinSeconds 的值。 这允许 Lambda 函数在调用失败时重试消息。

结论

这篇博文探讨了使用 亚马逊云科技 架构完善框架的安全支柱和可靠性支柱的 SQS 最佳实践。我们将讨论确保 SQS 安全性的各种最佳实践和注意事项。通过遵循这些最佳实践,您可以使用 SQS 创建强大而安全的消息传送系统。我们还强调容错和及时处理消息是使用 SQS 构建可靠应用程序的重要方面。

本博客文章系列的下一部分 重点介绍 亚马逊云科技 架构完善框架的 性能效率支柱 、 成本优化 支柱和 可持续发展支柱 ,并探讨 SQS 的最佳实践。

如需更多无服务器学习资源,请访问 无服务器世界