加密适用于 PostgreSQL 的亚马逊 RDS 和亚马逊 Aurora PostgreSQL 数据库,停机时间最短

最近,我们的一位客户要求我们帮助他们加密未加密的 适用于 Post greSQL 的 亚马逊关系数据库服务 (Amazon RDS) 。在这篇文章中,我们展示了一种解决方案,该解决方案可以在他们现有的未加密数据库中创建加密数据库,并在对应用程序的干扰最小的情况下进行切换。此解决方案使用 数据库快照 和 PostgreSQL 逻辑 复制。

Amazon RDS 提供两种类型的自动和手动快照。此解决方案使用手动快照。PostgreSQL 逻辑复制使用具有一个或多个订阅者的发布和订阅模式,在发布者节点上订阅一个或多个出版物。适用于 PostgreSQL 的亚马逊 RDS 和 亚马逊 Aurora PostgreSQL 兼容版 支持使用 pglogical 和 pgoutput 等解码插件进行逻辑复制。逻辑复制通常用于将数据从本地迁移到亚马逊 RDS 或亚马逊 Aurora PostgreSQL 兼容版。

作为 Amazon RDS 和 Aurora 安全 最佳实践 ,您必须在静态和传输中加密数据库和快照。静态数据库的加密提供了额外的保护层,防止未经授权访问数据。

将适用于 PostgreSQL 的未加密的 RDS 或亚马逊 Aurora PostgreSQL 数据库转换为加密的

对于加密的数据库实例,存储上的数据、事务日志、备份和快照都是加密的。有两种方法可以完成。一种是使用 Amazon RDS 控制台 ,这是一种简单的方法,但需要一些停机时间。如果您的应用程序对停机时间很敏感,则可以采用第二种方法并使用逻辑复制来最大限度地减少停机时间。

您可以使用相同的解决方案将现有加密亚马逊 RD S for PostgreSQL 或 Amazon Aurora 数据库 的加密密钥从 亚马逊云科技 托管密钥切换到客户管理 的密钥。

解决方案概述

该解决方案分四个高级步骤执行转换:

  1. 在未加密的源数据库上启用本机 PostgreSQL 复制并拍摄手动快照。
  2. 将快照恢复到启用加密的新数据库实例。
  3. 在还原的数据库上执行逻辑复制以捕获变更数据。
  4. 将您的应用程序切换到加密数据库并停用(或删除)未加密的数据库。

先决条件

你可以使用 适用于 PostgreSQL 的 亚马逊 RDS 或 亚马逊 Aurora PostgreSQL 兼容版 来尝试动手操作步骤。 在这篇文章中,我们演示了使用适用于 PostgreSQL 的亚马逊 RDS 的步骤。

在开始之前,您必须完成以下步骤:

  1. 拥有一个有权创建资源 的 亚马逊云科技 账户
  2. 使用未加密的 RDS for PostgreSQL 数据库集群和 PostgreSQL 客户端实用程序来尝试本文中讨论的步骤。您可以使用现有的未加密数据库或 创建新的数据库 。确保未选中 “ 启用加密 ”(参见以下屏幕截图)。

  1. 设置可连接到数据库实例的 亚马逊弹性计算云 (Amazon EC2) 实例。有关更多信息,请参阅 创建和连接到 PostgreSQL 数据库实例

在源数据库上设置发布

在此步骤中,您将设置一个 出版物 ,这是一组从一个表或一组表生成的更改。源数据库被称为 发布者节点。

  1. 要在 Amazon RDS for PostgreSQL 中启用逻辑复制,请修改 自定义参数组 以将 rds.logical_replicat ion 设置为 1 ,并将该自定义组连接到数据库。

此步骤需要重启数据库实例。如果您的数据库实例已经设置了自定义参数组,请修改上述参数并重启该实例。

  1. 运行以下 SQL 语句验证设置:
# Verify the publication
SELECT name, setting FROM pg_settings WHERE name IN ('wal_level','rds.logical_replication');
# You should see:
rds.logical_replication | on
wal_level | logical

现在你可以创建出版物了。您可以选择要捕获副本更改的表。对于此用例,您可以捕获所有表的更改。由于发布与单个数据库相关联,因此您需要为每个数据库创建一个发布。在这篇文章中,我们假设只有一个数据库。

  1. 使用任何 PostgreSQL 客户端应用程序(例如 psql)启动与数据库的客户端会话,然后运行以下命令:
# This need to be run using SQL client connected to the source DB

CREATE PUBLICATION encryptdb_post FOR ALL TABLES;

# Verify the publication

SELECT * FROM pg_publication;

接下来,创建 复制槽 ,发布者节点在此处保留副本所需的 WAL 日志。订阅者节点从复制槽读取流式更改以更新数据。你可以运行系统函数 pg_replication_logical_replication_slot () 来创建复制槽 。 要进行逻辑解码,你可以使用 PostgreSQL 预先打 包的 pg output 解码插件。

  1. 使用以下代码创建复制槽:
# Run the System function for creating the slot

SELECT * FROM pg_create_logical_replication_slot('encryptdb_post','pgoutput' );

# Verify the publication

SELECT * FROM pg_replication_slots;

备份和恢复以创建加密的数据库

在此步骤中,进行备份并将其恢复到新的数据库实例。新实例将启用加密。请注意,从恢复的角度来看,适用于 PostgreSQL 的亚马逊 RDS 和兼容 Amazon Aurora PostgreSQL 的版本之间存在细微差别。要创建加密的 Aurora 集群,您可以 从启用加密的未加密快 照中 恢复 。对于 Amazon RDS,您需要在恢复之前执行额外的步骤。此步骤涉及从未加密的快照创建加密快照。差异如下图所示。

请注意,此处列出的步骤适用于亚马逊 RDS。下图描述了此阶段执行的步骤。

完成以下步骤:

  1. 使用 Amazon RDS 控制台或通过 亚马逊云科技 命令行接口 (亚马逊云科技 CLI) 使用以下代码创建 RDS 快照:
# Wait for snapshot to be created

aws rds create-db-snapshot \
--db-instance-identifier <<DB Identifier>> \
--db-snapshot-identifier unencrypted-snapshot;

在下一步中,您需要提供用于数据库加密的 亚马逊密钥管理服务 (亚马逊云科技 KMS) 密钥。您使用的 KMS 密钥可以是 亚马逊云科技 托管密钥或 客户管理的密钥 。在这篇文章中,你使用了 亚马逊云科技 托管的默认 RDS 加密密钥(别名 — aws/rds)。

  1. 使用以下代码创建加密快照:
# Get the ARN for default RDS KMS key

aws kms list-aliases --output text \
--query 'Aliases[?AliasName == `alias/aws/rds`].AliasArn'

# Create the encrypted copy of the snapshot

aws rds copy-db-snapshot \
--source-db-snapshot-identifier unencrypted-snapshot \
--target-db-snapshot-identifier encrypted-snapshot \
--kms-key-id <<Paste KMS Key ARN from last command>>

现在,您可以从加密的快照中恢复数据库。确保 启用 PostgreSQL 日志; 在后续步骤中 需要日志序列号 (LSN)。您可以使用 Amazon RDS 控制台或 亚马逊云科技 CLI 执行此步骤,如本文所述。

  1. 使用以下代码恢复数据库。为您的加密数据库指定 VPC、子网组和安全组。为确保在新数据库中设置 rds.logical_replication 参数,请使用与源数据库相同的自定义参数组。
# This will create the encrypted database
# You can use the parameter group used for encrypted database as it already has the replication parameters setup

aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier encrypted-db \
--db-snapshot-identifier encrypted-snapshot \
--db-parameter-group-name <<Paste name of parameter group>> \
--vpc-security-group-ids <<security group>> \
--db-subnet-group-name <<subnet group name>>

在未加密和加密的数据库之间设置复制

在此阶段,您的数据库已更新为快照中可用的最新 LSN。现在,您在还原的数据库实例 上设置 订阅 以接收数据库更改。这将复制创建快照后发生的更改,并将继续传输所有更改。下图描述了此阶段采取的步骤。

首先验证加密数据库上的复制设置:

# Verify the publication

SELECT name, setting FROM pg_settings WHERE name IN ('wal_level','rds.logical_replication');

# You should see:
rds.logical_replication | on
wal_level | logical
  1. 创建 将从加密数据库接收更改的订阅
CREATE SUBSCRIPTION encryptdb_post
CONNECTION 'host=<<Unencrypted DB endpoint>> user=<<User name>> password=<<DB password>> dbname=<<DB name>>
PUBLICATION encryptdb_post
WITH (
       copy_data = false,
       create_slot = false,
       enabled = false,
       synchronous_commit = false,
       connect = true,
       slot_name = 'encryptdb_post'
);

默认情况下,订阅将被禁用;您可以在稍后的步骤中将其启用。

  1. 从 PostgreSQL 日志中获取 LSN

你可以通过在亚马逊 RDS 控制台、亚马逊 CloudWatch 控制台或 亚马逊云科技 CLI 中打开 PostgreSQL 日志来获取 L S N 。恢复实例后,导航到 亚马逊云科技 控制台并转到日志和事件选项卡。向下滚动到最新的日志文件。打开日志文件并查找 “: LOG:记录长度无效”。以下示例片段显示了如何查找 LSN。

# OR search the pattern in CloudWatch logs

# Double check the name of the database in the log-group-name below

aws logs filter-log-events \
--log-group-name /aws/rds/instance/encrypted-db/postgresql \
--filter-pattern 'invalid record length'

现在,你可以使用 PostgreSQL 系统管理函数 pg_replication_origin_advances 来推进复制 槽的当前确认位置。

  1. 使用 psql 等 PostgreSQL 客户端连接到加密的数据库,然后运行以下命令:
# First get the replication origin.
# You will use the attribute roname in the next statement

SELECT * FROM pg_replication_origin;

# Advance the slot

SELECT pg_replication_origin_advance(<<Replace with roname>>', '<<Replace with LSN>>’);

# E.g.,

SELECT pg_replication_origin_advance ('pg_2457', '0/20000110’);
  1. 启用复制:
ALTER SUBSCRIPTION encryptdb_post ENABLE;
  1. 要验证复制是否正常,请使用 SQL 客户端确保更改显示在加密的数据库中:
SELECT slot_name, confirmed_flush_lsn AS flushed, pg_current_wal_lsn(), (pg_current_wal_lsn() - confirmed_flush_lsn) AS lsn_distance FROM pg_catalog.pg_replication_slots WHERE slot_type = 'logical';

你应该看到 lsn_distance = 0。


slot_name      | flushed    | pg_current_wal_lsn | lsn_distance

---------------+------------+--------------------+--------------

encryptdb_post | 1/18000358 | 1/18000358         | 0

请记住,完全同步的持续时间将取决于创建快照和启用复制之间所做的数据更改量。

当新的加密数据库与旧的未加密数据库同步时,您就可以进行直接转换了。

将应用程序切换到加密的数据库

此时,您可以使用以下指南将应用程序重新指向加密数据库。

  1. 断开应用程序与数据库的连接并 停止未加密的数据库, 以防止意外写入。
  2. 配置您的应用程序以连接到加密的数据库实例
  3. 重新启动并验证应用程序的功能
  4. 将未加密的实例保留一段时间,然后再将其删除。

清理

为避免将来产生费用,请删除您创建的资源。

  1. 移除出版物
DROP PUBLICATION encryptdb_post;
  1. 移除复制槽:
DROP SUBSCRIPTION encryptdb_post;
  1. 禁用 PostgreSQL 日志和向 CloudWatch 发布日志(可选)。
  2. 删除 CloudWatch 群组:
# Double check the name of the database in the log-group-name below

aws logs delete-log-group --log-group-name /aws/rds/instance/encrypted-db/postgresql
  1. 如果您不再需要未加密的数据库,请将其删除。

结论

在这篇文章中,我们展示了如何在停机时间最短的情况下将未加密的 RDS for PostgreSQL 数据库转换为加密的数据库。该过程包括使用加密快照恢复到加密的数据库实例,然后在未加密和加密的数据库实例之间使用 CDC 的本机复制。这种方法的好处是,对于特别大的数据库,此活动所花费的总时间更短。在加密的数据库赶上未加密数据库的更改后,您可以在最短的停机时间内将应用程序切换到加密的数据库。

如果您有问题、评论或反馈,请将其留在评论部分。


作者简介

Santosh Bhupathi 是一位驻费城的高级数据库专家解决方案架构师。他专注于关系数据库和非 SQL 数据库,为客户提供指导和技术支持,帮助他们设计、部署和优化 亚马逊云科技 上的数据库工作负载。

Rajeev Sakhuja 是一位居住在纽约市的解决方案架构师。他喜欢与客户合作,使用 亚马逊云科技 服务解决复杂的业务问题。在业余时间,他喜欢徒步旅行,并创建有关应用程序架构和新兴技术的视频课程;在Udemy上看看他。


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