介绍
订单数据库目前接受整个应用 VPC 的连接,应用还使用数据库管理员身份。你将缩小网络访问范围,创建能读取和添加订单但不能删除订单的专用应用用户。
请先完成数据库连接和 SQL 实验。本独立环境提供 PostgreSQL 主数据库、三笔示例订单和应用。你将测试两种访问边界,并在最后删除练习数据库。
认证考试关联
本实验为以下考试主题提供入门实践。
- Cloud Practitioner (CLF-C02) · 任务 3.5:理解安全组作为网络访问边界的作用。
- Solutions Architect – Associate (SAA-C03) · 任务 1.3:应用最小权限原则并限制应用数据访问。
限制 PostgreSQL 的网络来源
本步骤将广泛的 VPC 入站访问替换为来自准备好的应用安全组的访问。
安全组控制哪些网络连接可以到达数据库,但不决定已认证数据库用户能执行哪些 SQL 操作。下一步会处理这个独立的权限边界。
加载准备好的设置:
cd /home/labex/project
source database.env
检查数据库安全组及提供的两个规则文件:
aws ec2 \
describe-security-groups \
--group-ids "$DB_SECURITY_GROUP_ID" \
--query 'SecurityGroups[].{Group:GroupName,Ingress:IpPermissions}'
cat broad-rule.json
cat application-rule.json
现有规则允许 10.70.0.0/16 访问 TCP 端口 5432,因此该 VPC 中的其他客户端也能尝试连接数据库。替代规则使用 UserIdGroupPairs 引用应用安全组。安全组引用允许来自关联该来源组的资源的流量,并不会复制来源组的规则。
移除宽泛规则,添加应用规则:
aws ec2 \
revoke-security-group-ingress \
--group-id "$DB_SECURITY_GROUP_ID" \
--ip-permissions file://broad-rule.json
aws ec2 \
authorize-security-group-ingress \
--group-id "$DB_SECURITY_GROUP_ID" \
--ip-permissions file://application-rule.json
测试来自应用来源的新连接:
psql \
"service=orders-db" \
--command 'SELECT count(*) FROM orders;'
应看到 3。然后测试提供的不属于应用组的客户端:
psql \
"service=orders-db-external" \
--command 'SELECT count(*) FROM orders;'
外部客户端应连接失败。它的数据库密码有效,但网络来源未被允许。准备好的连接名称用于选择这两种来源。实验访问规则不会改变你的 Terminal 或 AWS View 管理连接。
AWS View 应显示应用组作为数据库的 PostgreSQL 来源,而不是宽泛的 VPC CIDR。
为应用创建数据库用户
本步骤允许应用读取和插入订单,但不给予管理或删除权限。
PostgreSQL 角色可以拥有权限。带有 LOGIN 的角色可以作为数据库用户认证。数据库角色与 AWS IAM 身份分开:IAM 授权管理 RDS 资源,而这些 SQL 授权控制 PostgreSQL 内部操作。

概念图:网络访问、登录和 SQL 权限是不同的边界。
使用提供的私密应用密码文件创建 orders_app。--set 定义 psql 变量,:'app_password' 将值安全引用为 SQL 字符串:
psql \
"service=orders-db" \
--set=ON_ERROR_STOP=1 \
--set=app_password="$(cat app-password.txt)" <<'SQL'
CREATE ROLE orders_app LOGIN PASSWORD :'app_password';
GRANT CONNECT ON DATABASE orders TO orders_app;
GRANT USAGE ON SCHEMA public TO orders_app;
GRANT SELECT, INSERT ON orders TO orders_app;
SQL
CONNECT 允许数据库连接。USAGE 允许访问 schema,即包含表的命名空间。SELECT 和 INSERT 仅允许应用所需的订单操作。你没有授予 DELETE、UPDATE、CREATEDB、CREATEROLE 或超级用户权限。
将私密密码值传递给 psql,测试应用角色:
PGPASSWORD="$(cat app-password.txt)" psql \
"service=orders-db-app" \
--command 'SELECT current_user, count(*) FROM orders;'
应看到用户 orders_app 和 3 笔订单。
尝试删除不存在的订单 ID。即使权限意外过宽,该语句也不会删除真实订单:
PGPASSWORD="$(cat app-password.txt)" psql \
"service=orders-db-app" \
--command 'DELETE FROM orders WHERE order_id = -1;'
应看到 permission denied for table orders。这个失败发生在网络连接和数据库登录成功之后,因此它证明的边界不同于之前外部客户端连接失败的边界。
在应用中使用受限身份
本步骤配置应用使用该角色,并证明正常订单操作仍然可用。
修改数据库身份和密码文件引用,保持两个端点字段不变:
jq \
'.user = "orders_app" | .password_file = "app-password.txt"' \
app-config.json > app-config.new
mv app-config.new app-config.json
读取当前订单列表:
curl \
--silent \
--show-error \
--fail \
http://127.0.0.1:8080/application/orders | jq
应看到三笔原始订单和 user: orders_app。
通过应用的 HTTP 端点添加一笔订单。Content-Type 告知应用请求正文为 JSON:
curl \
--silent \
--show-error \
--fail \
--request POST \
--header 'Content-Type: application/json' \
--data '{"order_id":104,"customer":"Kai","total":"5.00"}' \
http://127.0.0.1:8080/application/orders
应看到 saved: true 和订单 ID 104。再次读取列表:
curl \
--silent \
--show-error \
--fail \
http://127.0.0.1:8080/application/orders | jq
应看到四笔订单,包括 Kai 金额为 5.00 的订单。AWS View 应显示同样的已存储数据和应用的受限身份。缩小权限后,应用所需行为仍然正常。

删除练习数据库
本步骤删除本实验的数据库,包括示例订单和 SQL 用户。
aws rds \
delete-db-instance \
--db-instance-identifier orders-db \
--skip-final-snapshot \
--query 'DBInstance.DBInstanceIdentifier'
aws rds \
wait db-instance-deleted \
--db-instance-identifier orders-db
aws rds \
describe-db-instances \
--query 'DBInstances[].DBInstanceIdentifier'
应看到 []。数据库引擎及角色均已删除,应用的旧端点不再连接。保留提供的网络和已收紧的数据库安全组。清理时无需重新开放数据库访问。
总结
你将 PostgreSQL 连接限制为应用来源,并为应用分配了独立的受限数据库角色。外部客户端无法连接,应用角色无法删除订单,但正常读取和插入仍然可用。随后你删除了练习数据库,并保留收紧后的网络访问规则。
下一项实验将通过把手动 RDS 快照恢复到新数据库来找回丢失的订单。


