

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 将不同账户中的 Amazon Redshift 集群中的数据卸载到 Amazon S3
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3"></a>

*Andrew Kamel，Amazon Web Services*

## Summary
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-summary"></a>

当测试应用程序时，在测试环境中使用生产数据会很有帮助。使用生产数据，您可以更准确地评估正在开发的应用程序。

此模式将从生产环境中的 Amazon Redshift 集群中提取数据，并将这些数据传输到 Amazon Web Services（AWS）上的开发环境中的 Amazon Simple Storage Service（Amazon S3）存储桶中。

此模式将逐步完成 DEV 和 PROD 账户的设置，包括：
+ 所需的资源
+ AWS Identity and Access Management (IAM) 角色
+ 调整与子网、安全组和虚拟私有云（VPC）之间的网络连接，以便支持 Amazon Redshift 连接
+ 一个带有 Python 运行时的示例 AWS Lambda 函数，用于测试架构

要授予对 Amazon Redshift 集群的访问权限，该模式 AWS Secrets Manager 用于存储相关证书。好处是拥有直接连接到 Amazon Redshift 集群所需的全部信息，而无需知道 Amazon Redshift 集群位于何处。此外，您还可以[监控密钥的使用情况](https://docs.aws.amazon.com/secretsmanager/latest/userguide/monitoring.html)。

保存在 Secrets Manager 中的密钥包括 Amazon Redshift 集群的主机、数据库名称、端口和相关的凭证。

有关使用此模式时的安全注意事项的信息，请参阅[最佳实践](#unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-best-practices)部分。

## 先决条件和限制
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-prereqs"></a>

**先决条件**
+ 在 PROD 账户中[运行的 Amazon Redshift 集群](https://docs.aws.amazon.com/redshift/latest/gsg/new-user.html)
+ 在 DEV 账户中[创建的 S3 存储桶](https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html)
+ 在 DEV 账户与 PROD 账户之间建立了 [VPC 对等连接](https://docs.aws.amazon.com/vpc/latest/peering/create-vpc-peering-connection.html)，并相应[调整了路由表](https://docs.aws.amazon.com/vpc/latest/peering/vpc-peering-routing.html)
+ 为两个对等设备@@ [启用了 DNS 主机名和 DNS 解析](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html) VPCs

**限制**
+ 根据您要查询的数据量，Lambda 函数可能会超时。

  如果您的运行时间超过了 Lambda 的最大超时时间（15 分钟），请对您的 Lambda 代码采用一种异步方法。此模式的代码示例使用适用于 Python 的 [psycopg2](https://github.com/psycopg/psycopg2) 库，此库目前不支持异步处理。
+ 有些 AWS 服务 并非全部可用 AWS 区域。有关区域可用性，请参阅[按区域划分的AWS 服务](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/)。有关特定端点，请参阅[服务端点和配额](https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html)页面，然后选择相应服务的链接。

## 架构
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-architecture"></a>

下图显示了包含 DEV 账户和 PROD 账户的目标架构。

![DEV 账户中的 Lambda VPC 和 PROD 账户中的 Amazon Redshift VPC。](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/5c83c617-3a85-4aea-a7a7-930f406d1cef/images/fa4d01df-483d-4454-9711-b391ebbe4629.png)


下图显示了如下工作流：

1. DEV 账户中的 Lambda 函数担任 IAM 角色，访问 PROD 账户中的 Secrets Manager 中的 Amazon Redshift 凭证时，需要使用此角色。

   随后，Lambda 函数将检索 Amazon Redshift 集群密钥。

1. 开发者账户中的 Lambda 函数使用这些信息通过对等连接到 PROD 账户中的 Amazon Redshift 集群。 VPCs

   接下来，Lambda 函数发送一个卸载命令，以便查询 PROD 账户中的 Amazon Redshift 集群。

1. PROD 账户中的 Amazon Redshift 集群担任相关的 IAM 角色，以便访问 DEV 账户中的 S3 存储桶。

   Amazon Redshift 集群将查询的数据卸载到 DEV 账户中的 S3 存储桶。

**查询来自 Amazon Redshift 的数据**

下图显示了用于检索 Amazon Redshift 凭证和连接到 Amazon Redshift 集群的角色。此工作流由 Lambda 函数启动。

![用于在不同的账户中担任角色的三步流程。](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/5c83c617-3a85-4aea-a7a7-930f406d1cef/images/ab25b72c-773c-4d58-9012-4a3755c181ff.png)


下图显示了如下工作流：

1. DEV 账户中的 `CrossAccount-SM-Read-Role` 在 PROD 账户中担任 `SM-Read-Role`。

1. `SM-Read-Role` 角色使用附加的策略，从 Secrets Manager 中检索密钥。

1. 这些凭证用于访问 Amazon Redshift 集群。

**将数据上传到 Amazon S3**

下图显示了用于提取数据并将其上传到 Amazon S3 的跨账户读写过程。此工作流由 Lambda 函数启动。此模式将 [Amazon Redshift 中的 IAM 角色串联在一起](https://docs.aws.amazon.com/redshift/latest/mgmt/authorizing-redshift-service.html#authorizing-redshift-service-chaining-roles)。来自 Amazon Redshift 集群的卸载命令担任 `CrossAccount-S3-Write-Role`，然后担任 `S3-Write-Role`。这一角色串联能够授权 Amazon Redshift 访问 Amazon S3。

![获取凭证、访问 Amazon Redshift 并将数据上传到 Amazon S3 的那些角色。](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/images/pattern-img/5c83c617-3a85-4aea-a7a7-930f406d1cef/images/d2982fc6-1d12-4f9d-9493-a99ce691d693.png)


此工作流包含以下步骤：

1. DEV 账户中的 `CrossAccount-SM-Read-Role` 在 PROD 账户中担任 `SM-Read-Role`。

1. `SM-Read-Role` 从 Secrets Manager 中检索 Amazon Redshift 凭证。

1. Lambda 函数连接到 Amazon Redshift 集群，并发送一个查询。

1. Amazon Redshift 集群担任 `CrossAccount-S3-Write-Role`。

1. 在 DEV 账户中，`CrossAccount-S3-Write-Role` 担任 `S3-Write-Role`。

1. 查询结果将卸载到 DEV 账户中的 S3 存储桶。

## 工具
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-tools"></a>

**AWS 服务**
+ [AWS Key Management Service (AWS KMS)](https://docs.aws.amazon.com/kms/latest/developerguide/overview.html) 帮助您创建和控制加密密钥以帮助保护您的数据。
+ [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 是一项计算服务，可帮助您运行代码，无需预调配或管理服务器。它只在需要时运行您的代码，并自动进行扩展，因此您只需为使用的计算时间付费。
+ [Amazon Redshift](https://docs.aws.amazon.com/redshift/latest/gsg/getting-started.html) 是一项在 Amazon Web Services Cloud 中托管的 PB 级数据仓库服务。
+ [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 可帮助您将代码中的硬编码凭证（包括密码）替换为对 Secrets Manager 进行的 API 调用，以便以编程方式检索此密钥。
+ [Amazon Simple Storage Service（Amazon S3）](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html)是一项基于云的对象存储服务，可帮助您存储、保护和检索任意数量的数据。

**代码存储库 **

此模式的代码可在 GitHub [unload-redshift-to-s3-python](https://github.com/aws-samples/unload-redshift-to-s3-python/) 存储库中找到。

## 最佳实践
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-best-practices"></a>

**安全免责声明**

在实施该解决方案之前，请考虑下面这些重要的安全建议：
+ 请记住，连接开发账户和生产账户可能会导致范围扩大、整体安全状况变差。我们建议只临时部署该解决方案、提取所需的数据部分，然后立即销毁已部署的资源。要销毁资源，您应删除 Lambda 函数、移除为该解决方案创建的任何 IAM 角色和策略，并撤消在多个账户之间授予的任何网络访问权限。
+ 在将任何数据从生产环境复制到开发环境之前，请咨询您的安全和合规团队。通常不应以这种方式复制个人身份信息（PII）、受保护的健康信息（PHI）以及其他机密数据或受监管的数据。只复制公开提供的非机密信息（例如商店前端的公开库存数据）。考虑对数据进行令牌化或匿名化处理，或者生成合成测试数据，而不是尽可能使用生产数据。[AWS 安全原则](https://docs.aws.amazon.com/en_us/wellarchitected/2022-03-31/framework/sec-design.html)之一是限制对数据的访问。换句话说，开发人员不应在生产账户中执行操作。
+ 限制访问开发账户中的 Lambda 函数，因为此函数会从生产环境中的 Amazon Redshift 集群读取数据。
+ 为了避免生产环境中断，请实施以下建议：
  + 使用单独的专用开发账户来执行测试和开发活动。
  + 实施严格的网络访问控制，并将账户之间的流量限制在仅仅必要的水平。
  + 监控和审核对生产环境和数据来源的访问。
  + 对于所有的相关资源和服务，实施最低权限访问控制。
  + 定期审查和轮换证书，例如 AWS Secrets Manager 密钥和 IAM 角色访问密钥。
+ 对于本文中使用的服务，请参阅如下安全文档：
  + [AWS Lambda 安全](https://docs.aws.amazon.com/lambda/latest/dg/lambda-security.html)
  + [Amazon Redshift 安全性](https://docs.aws.amazon.com/redshift/latest/mgmt/iam-redshift-user-mgmt.html)
  + [Amazon S3 安全性](https://docs.aws.amazon.com/AmazonS3/latest/userguide/security.html)
  + [AWS Secrets Manager 安全](https://docs.aws.amazon.com/secretsmanager/latest/userguide/security.html)
  + [IAM 安全最佳实践](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)

访问生产数据和资源时，安全性是重中之重。始终遵循最佳实践、实施最低权限访问控制，并定期审查和更新您的安全措施。

## 操作说明
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-epics"></a>

### 从 Amazon Redshift 查询数据
<a name="query-data-from-amazon-redshift"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 为 Amazon Redshift 集群创建一个密钥。 | 要为 Amazon Redshift 集群创建密钥，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 创建一个用于访问 Secrets Manager 的角色。 | 要创建此角色，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 

### 将数据上载到 Amazon S3
<a name="upload-data-to-s3"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建用于访问 S3 存储桶的角色 | 要创建用于访问 S3 存储桶的角色，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 创建此 Amazon Redshift 角色。 | 要创建 Amazon Redshift 角色，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 

### 部署 Lambda 函数
<a name="deploy-the-lam-function"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 部署 Lambda 函数。 | 要在对等的 VPC 中部署 Lambda 函数，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 

### 测试架构
<a name="test-the-architecture"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 导入所需的资源。 | 要导入所需的资源，请运行以下命令：<pre>import ast<br />import boto3<br />import psycopg2<br />import base64<br />from botocore.exceptions import ClientError</pre> | 应用程序开发人员 | 
| 运行 Lambda 处理程序函数。 | Lambda 函数使用 AWS Security Token Service (AWS STS) 进行跨账户访问和临时凭证管理。该函数使用 AssumeRole API 操作来临时承担 `sm_read_role` IAM 角色的权限。<br />要运行 Lambda 函数，请使用如下示例代码：<pre>def lambda_handler(event, context):<br />    sts_client = boto3.client('sts')<br /><br />    # Secrets Manager Configurations<br />    secret_name = "redshift_creds"<br />    sm_region = "eu-west-1"<br />    sm_read_role = "arn:aws:iam::PROD_ACCOUNT_NUMBER:role/SM-Read-Role"<br /><br />    # S3 Bucket Configurations<br />    s3_bucket_path = "s3://mybucket/"<br />    s3_bucket_region = "eu-west-1"<br />    s3_write_role = "arn:aws:iam::DEV_ACCOUNT_NUMBER:role/S3-Write-Role"<br /><br />    # Redshift Configurations<br />    sql_query = "select * from category"<br />    redshift_db = "dev"<br />    redshift_s3_write_role = "arn:aws:iam::PROD_ACCOUNT_NUMBER:role/CrossAccount-S3-Write-Role"<br /><br />    chained_s3_write_role = "%s,%s" % (redshift_s3_write_role, s3_write_role)<br /><br />    assumed_role_object = sts_client.assume_role(<br />        RoleArn=sm_read_role,<br />        RoleSessionName="CrossAccountRoleAssumption",<br />        ExternalId="YOUR_EXTERNAL_ID",<br />    )<br />    credentials = assumed_role_object['Credentials']<br /><br />    secret_dict = ast.literal_eval(get_secret(credentials, secret_name, sm_region))<br />    execute_query(secret_dict, sql_query, s3_bucket_path, chained_s3_write_role, s3_bucket_region, redshift_db)<br /><br />    return {<br />        'statusCode': 200<br />    }</pre> | 应用程序开发人员 | 
| 获取密钥。 | 要获取 Amazon Redshift 密钥，请使用如下示例代码：<pre>def get_secret(credentials, secret_name, sm_region):<br />    # Create a Secrets Manager client<br />    session = boto3.session.Session()<br />    sm_client = session.client(<br />        service_name='secretsmanager',<br />        aws_access_key_id=credentials['AccessKeyId'],<br />        aws_secret_access_key=credentials['SecretAccessKey'],<br />        aws_session_token=credentials['SessionToken'],<br />        region_name=sm_region<br />    )<br /><br />    try:<br />        get_secret_value_response = sm_client.get_secret_value(<br />            SecretId=secret_name<br />        )<br />    except ClientError as e:<br />        print(e)<br />        raise e<br />    else:<br />        if 'SecretString' in get_secret_value_response:<br />            return get_secret_value_response['SecretString']<br />        else:<br />            return base64.b64decode(get_secret_value_response['SecretBinary'])</pre> | 应用程序开发人员 | 
| 运行卸载命令。 | 要将数据卸载到 S3 存储桶，请使用如下示例代码。<pre>def execute_query(secret_dict, sql_query, s3_bucket_path, chained_s3_write_role, s3_bucket_region, redshift_db):<br />    conn_string = "dbname='%s' port='%s' user='%s' password='%s' host='%s'" \<br />                  % (redshift_db,<br />                     secret_dict["port"],<br />                     secret_dict["username"],<br />                     secret_dict["password"],<br />                     secret_dict["host"])<br /><br />    con = psycopg2.connect(conn_string)<br /><br />    unload_command = "UNLOAD ('{}') TO '{}' IAM_ROLE '{}' DELIMITER '|' REGION '{}';" \<br />        .format(sql_query,<br />                s3_bucket_path + str(datetime.datetime.now()) + ".csv",<br />                chained_s3_write_role,<br />                s3_bucket_region)<br /><br />    # Opening a cursor and run query<br />    cur = con.cursor()<br />    cur.execute(unload_command)<br /><br />    print(cur.fetchone())<br />    cur.close()<br />    con.close()</pre> | 应用程序开发人员 | 

### 清理
<a name="clean-up"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 删除 Lambda 函数。 | 为了避免产生计划外成本，请移除资源以及 DEV 账户与 PROD 账户之间的连接。<br />要移除 Lambda 函数，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 移除 IAM 角色和策略。 | 从 DEV 账户和 PROD 账户中移除 IAM 角色和策略。<br />在 DEV 账户中，执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html)<br />在 PROD 账户中，执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 在 Secrets Manager 中删除密钥。 | 要删除密钥，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 移除 VPC 对等连接和安全组规则。 | 要移除 VPC 对等连接和安全组规则，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 从 S3 存储桶中移除数据。 | 要从 Amazon S3 中移除数据，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 清理 AWS KMS 钥匙。 | 如果您创建了任何用于加密的自定义 AWS KMS 密钥，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 
| 查看并删除 Amazon CloudWatch 日志。 | 要删除日 CloudWatch 志，请执行以下操作：[See the AWS documentation website for more details](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/patterns/unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3.html) | DevOps 工程师 | 

## 相关资源
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-resources"></a>
+ [亚马逊 CloudWatch 文档](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)
+ [IAM 文档](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html)
+ [Lambda 文档](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)
+ [Amazon Redshift 文档](https://docs.aws.amazon.com/redshift/latest/gsg/new-user-serverless.html)
+ [Amazon S3 文档](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html)
+ [AWS Secrets Manager 文档](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)
+ [AWS 安全原则](https://docs.aws.amazon.com/en_us/wellarchitected/2022-03-31/framework/sec-design.html)

## 附加信息
<a name="unload-data-from-amazon-redshift-cross-accounts-to-amazon-s3-additional"></a>

将数据从 Amazon Redshift 卸载到 Amazon S3 之后，您可以使用 Amazon Athena 来分析这些数据。

[Amazon Athena](https://docs.aws.amazon.com/athena/latest/ug/getting-started.html) 是一项大数据查询服务，当您需要访问大量的数据时会非常有用。您无需预调配服务器或数据库，即可使用 Athena。Athena 支持复杂的查询，您可以在不同的对象上运行 Athena。

与大多数一样 AWS 服务，使用 Athena 的主要好处是，它在运行查询时提供了极大的灵活性，而不会增加复杂性。使用 Athena 时，无需更改数据类型，即可在 Amazon S3 中查询不同的数据类型，例如 CSV 和 JSON。您可以查询来自各种来源的数据，包括外部数据 AWS。Athena 降低了复杂性，因为您不必管理服务器。Athena 直接从 Amazon S3 读取数据，而无需在您运行查询之前加载或更改数据。