甘南州屿庙神教35号
办公时间:上午9:00-下午6:00

项目展示

首页 / Our Projects /使用 RDS 数据 API 实施行级安全性 数据库博客

使用 RDS 数据 API 实施行级安全性 数据库博客

2026-01-27 13:04:27

利用 RDS 数据 API 强化行级安全性

关键要点

行级安全性通过用户属性限制可以访问的数据行。PostgreSQL 提供对行级安全性的支持,可以基于策略进行用户数据访问控制。RDS 数据 API 提供了一种简化数据库交互的方法,消除了连接管理的复杂性。本文示范了如何在 Amazon Aurora PostgreSQL 兼容版中实现行级安全性。

随着应用程序处理更多用户和敏感数据的需求,实施强有力的安全控制显得至关重要。其中,通过行级安全性来增强安全性、满足复杂的访问需求是一种可行的方案。行级安全性允许根据用户属性限制对特定行数据的访问。

PostgreSQL 是一种流行的开源关系数据库引擎,支持行级安全性,行级安全性策略保证用户只能查看或修改那些明确授权的数据。在多租户应用中,合适的连接管理策略十分重要。

在 PostgreSQL 中,每个新数据库连接需要创建一个新的操作系统进程即父 PostgreSQL 进程的子进程。随着连接数量的增加,这一进程创建过程的开销可能成为瓶颈,影响性能。在弹性扩展计算环境中,连接管理不当是导致 PostgreSQL 数据库性能问题的主要原因之一。使用RDS 数据 API可以消除管理连接或处理复杂连接池逻辑的需求。想了解更多关于 RDS 数据 API 的信息,请参考为 Amazon Aurora Serverless v2 和 Amazon Aurora 提供的 Data API。

本文将展示如何在 Amazon Aurora PostgreSQL 兼容版中使用 RDS 数据 API 和 PostgreSQL 功能实现行级安全性。通过学习本文,您将了解如何在 AWS 上构建安全且可扩展的多租户 PostgreSQL 架构。

在本文中所使用的模式适用于具有专用实例和Amazon Aurora Serverless v2 的 Aurora PostgreSQL 集群。有关 RDS 数据 API 的更多信息,请参见使用 RDS 数据 API。

解决方案概述

在接下来的部分中,我们将提供示例代码,以设置和测试行级安全性,并使用 RDS 数据 API。您可以使用命令行工具如 psql或在 Amazon RDS 控制台上的查询编辑器运行这些步骤。

前提条件

为便于您按照本文步骤进行操作,您需要以下资源:

一个具有AWS 身份与访问管理IAM权限的 AWS 账号,以创建 Aurora PostgreSQL 数据库。一台 Aurora PostgreSQL 实例专用或 Serverless v2,版本需为 1311 或更高。有关支持版本的完整列表,请参阅与 Aurora PostgreSQL Serverless v2 和专用版本的 Data API。可选:PostgreSQL psql 命令行工具。有关安装说明,请参见连接至运行 PostgreSQL 数据库引擎的 DB 实例。安装有Boto3库的 Python。

使用 RDS 数据 API 不要求直接访问数据库,因此您可以从本地开发环境运行 Python 脚本。运行psql的机器需要能够连接到 Aurora 集群。

创建共享租户架构

创建一个租户表架构以实现行级安全性。租户表是多个租户共享的,必须严格控制以确保特定租户只可以读取或写入其自己的 accountbalance。运行以下命令以创建并填充表格:

sqlCREATE TABLE tenant ( tenantid integer PRIMARY KEY tenantname text accountbalance numeric )

INSERT INTO tenant VALUES (1 Tenant1 50000) (2 Tenant2 60000) (3 Tenant3 40000)

创建租户隔离策略

该架构是多租户软件即服务SaaS应用的一部分。通过对 tenantid 创建策略来强制实施租户隔离。该策略使用 currentsetting() 函数将提供的 tenantid 与会话中设置的 ID 进行比较,定义如下:

sqlCREATE POLICY tenantpolicy ON tenant USING (tenantid = currentsetting(tenantid)integer)

启用行级安全性

接下来,在租户表以及您希望实施租户隔离的任何其他表上启用行级安全性策略:

sqlALTER TABLE tenant ENABLE ROW LEVEL SECURITY

创建应用用户

本文中的示例使用一个共享应用用户用于所有租户。使用该模式时,创建一个AWS Secrets Manager的密钥来存储将使用 RDS 数据 API 的每个用户的登录信息。有关其他数据访问模式的更多详细信息,请参见为您的 SaaS 应用选择合适的 PostgreSQL 数据访问模式。使用以下命令创建应用用户:

sqlCREATE ROLE appuser WITH LOGIN PASSWORD lt任何强密码gtGRANT SELECT ON tenant TO appuser

测试行级隔离

最后,当以应用用户身份登录时,使用以下查询测试行级隔离这些步骤必须使用 psql 执行:

sql 更改用户为 appuserSET ROLE TO appuser

在未设置 tenantid 变量的情况下测试SELECT FROM tenantERROR unrecognized configuration parameter tenantid

设置当前 tenantid 为 1SET tenantid = 1

验证只返回 tenantid = 1 的行SELECT FROM tenant

tenantid tenantname accountbalance 1 Tenant1 50000(1 row)

可以把行级安全性策略视为自动应用于 SELECT 语句的 WHERE 子句。作为最佳实践,您仍然应该明确在 SQL 语句中包含 WHERE 子句,以过滤仅属于该租户的数据。这为防止错误配置提供了额外的防御层。

传统连接管理

在探索 RDS 数据 API 之前,理解传统的连接管理方法是很重要的。从应用程序开始,数据访问层需要使用驱动程序连接到数据库。这意味着您必须在应用程序中包含驱动程序并保持其更新。如果您通过 SSL 连接到数据库,则需要将证书打包为应用的一部分,以便建立连接。

随着多个租户的入驻,可能会有许多打开的数据库连接。这会导致高频率地打开和关闭连接,从而耗尽数据库的内存和计算资源。

为了防止在数据库和客户端上开启和关闭连接带来的开销,通常会引入客户端连接池。这使您能够惰性实例化您指定大小的连接池并重用这些连接,减少新连接打开和关闭的开销。然而,现代应用程序,特别是 web 应用程序,具有高并发性并且常常会自动扩展,以增加额外的计算能力来满足变化的用户活动。如果这些计算单元中每个都有一个客户端连接池,这会迅速增加数据库的压力。

为了减轻分布式应用中的连接管理开销,通常会使用集中式连接池技术。一些流行的选项包括Amazon RDS Proxy、pgBouncer或pgpool。以下图表展示了一种实施方案。

应用程序客户端池与集中式连接池的组合是一种有效的数据库连接管理策略。集中式连接池的一个优点是您无需对应用程序进行任何更改;您的数据访问层可以继续透明地使用相同的连接逻辑。但需要注意以下几个考虑事项:

它引入了潜在的瓶颈或单点故障。它需要监控和调整客户端和集中式连接池的大小,以应对租户数量和活动的增长。应用程序与集中连接池之间,集中连接池与数据库之间均需要网络连接。它的固定成本与使用模式和利用率无关。需要在应用中包含数据库驱动程序。

使用 RDS 数据 API

使用 RDS 数据 API,应用程序无需管理连接的共享与池化。这消除了驱动层,消除在应用程序与数据库之间管理客户端和集中连接池的需求。应用程序可以通过简单的 HTTP API 调用在 HTTP 端点上运行 SQL 语句。

在为行级安全性配置的数据库架构下,通过 RDS 数据 API 进行安全查询,并强制执行租户隔离。该 API 允许您在无需管理数据库连接的情况下运行 SQL 语句。以下示例 Python 代码传入用户 ID,在上下文中设置它,运行查询,并检索过滤后的数据:

pythonimport boto3

clusterarn = secretarn =

rdsData = boto3client(rdsdata)

dbname = postgres

def gettenantidfromcontext() return 2

tr = rdsDatabegintransaction( resourceArn=clusterarn secretArn=secretarn database=dbname)

rdsDataexecutestatement(resourceArn=clusterarn secretArn=secretarn database=dbname sql=set tenantid = {0}format(gettenantidfromcontext()) transactionId=tr[transactionId])

response = rdsDataexecutestatement(resourceArn=clusterarn secretArn=secretarn database=dbname sql=select tenantname from tenant transactionId=tr[transactionId])

cr = rdsDatacommittransaction( resourceArn=clusterarn secretArn=secretarn transactionId=tr[transactionId])

由于对 executestatement 的调用是独立的,因此使用显式事务以保持会话状态更改。如果不使用事务,则不能保证这些 API 调用会使用相同的连接,且会话状态更改将被清除。在示例代码中,出于简洁考虑,tenantid 属性是硬编码的。在生产应用中,您会从身份验证令牌通常是 JWT 令牌中检索 tenantid。有关此过程的更多详细信息,请参阅使用 AWS 无服务器服务构建多租户 SaaS 解决方案。当运行示例代码时,仅返回上下文中设置的租户的数据:

Admin/environment python3 mainpy[[{stringValue Tenant2}]]

如果更改参数值,则返回不同租户的数据:

pythondef gettenantidfromcontext() return 3

[[{stringValue Tenant3}]]

应用程序可以继续使用 RDS 数据 API 的行级安全性功能来实现多租户数据隔离。因应用请求是简单的无状态 HTTP 请求,因此不需要 JDBC 驱动程序。以下图表展示了多租户应用如何使用 HTTP API 与数据库进行互动,而无需连接池代理层。

在使用 RDS 数据 API 进行 Python 示例时,您可能会希望避免在应用程序中处理显式的事务开始和提交。另一种方式是创建一个函数将 SET 语句与实际查询结合以提取租户数据。使用函数的这种方法允许您一次运行多个语句,并帮助您克服 RDS 数据 API 对于隐式事务处理缺乏多语句支持的问题:

sqlCREATE OR REPLACE FUNCTION gettenantdata(ptenantid integer) RETURNS SETOF text ASfuncBEGIN EXECUTE format(SET tenantid = s ptenantid) RETURN QUERY SELECT tenantname FROM tenantENDfunc LANGUAGE plpgsql

SET ROLE TO appuser

加速器 下载

使用 RDS 数据 API 实施行级安全性 数据库博客

SELECT gettenantdata(2)

经过创建并测试后,下面的 Python 代码利用 RDS 数据 API 调用该函数,并实施行级安全性以实现租户隔离:

pythonimport boto3

clusterarn = secretarn =

rdsData = boto3client(rdsdata)

dbname = postgres

def gettenantidfromcontext() return 2

param1 = {name id value {longValue gettenantidfromcontext()}}paramSet = [param1]

response = rdsDataexecutestatement(resourceArn=clusterarn secretArn=secretarn database=dbname sql=select gettenantdata(idinteger) parameters=paramSet)

print(response[records])

RDS 数据 API 成本考量

RDS 数据 API 按每百万请求计费。每个请求以 32 KB 为单位进行计量。在以下多租户系统的示例中,由于每个租户有不同的访问模式,因此使用 API 时每个租户的成本可能会有所不同。

租户 1 的访问模式如下:

每秒十个请求,大小低于 32 KB = 每小时 36000 个请求 x 730小时 = 2628 百万请求每月。根据撰写时的 useast1 定价每 1 百万请求 035,最多达 10 亿请求= 大约每月 920。

租户 2 的访问模式如下:

每秒六个请求,大小大于 32 KB 小于 64 KB可能租户 2 运行的有很多详细的报告,具有更大的有效载荷= 每小时 21600 个请求 x 730 小时 = 1576 百万请求每月。这将以 3152 百万进行计量,因为每个请求消耗两个 32 KB 的请求。这相当于大约 1103 的租户 2 的使用花费。

由于每个租户的使用成本可能有所不同,因此租户计量和按消耗计费是您的SaaS 控制平面的重要方面。有关完整定价详情,请参见Amazon Aurora 定价。

RDS 数据 API 对同时运行的查询数量没有限制。然而,每个查询会消耗数据库资源。因此,确保实施速率限制控制以保持公正的租户体验十分重要。这些速率限制控制可以在 API 中实现,例如使用Amazon API Gateway,以强制限制在特定时间内某个租户可以发送的请求数量。还可以在数据访问层实施更多的控制,排队请求并优先处理高优先级请求。有关详细信息,请参见使用 API Gateway 在规模上限制分层多租户 REST API。

以下图表展示了利用 API Gateway 实现速率限制的实施示例。它还包括专用的计量微服务,以捕获 RDS 数据 API executestatement 调用并记录到 Amazon DynamoDB 数据库中。这些计量指标可用于监控每个租户的资源消耗,并建立每个租户的成本档案。

另外,您可以将每个对 Execute