从 Amazon S3 到 Cloud Storage 的简单迁移

本页面介绍如何完成从 Amazon Simple Storage Service (Amazon S3) 到 Cloud Storage 的简单迁移。在简单迁移中,您可以使用现有的工具和库生成向 Amazon S3 发出的经过身份验证的 REST 请求,从而向 Cloud Storage 发送经过身份验证的请求。

如果您刚接触 Cloud Storage,并且不会直接使用 API,请考虑使用 Google Cloud 控制台来设置和管理转移作业。Google Cloud 控制台为 Cloud Storage 提供了一个图形界面。借助该界面,您只需使用浏览器即可完成众多存储任务,包括将数据从 Amazon S3 迁移到 Cloud Storage。

如果您希望 Cloud Storage 存储 Amazon S3 数据的备份,请考虑使用事件驱动型转移作业,这些转移作业使用 Amazon S3 事件通知自动使 Cloud Storage 存储桶与 Amazon S3 来源保持同步。

在简单迁移情景中从 Amazon S3 迁移到 Cloud Storage

如需向 Cloud Storage 发出请求,您需要完成以下步骤:

  • 设置默认 Google Cloud 项目
  • 获取 HMAC(基于哈希的消息认证码)密钥
  • 在现有工具或库中,进行如下更改:

    • 将请求端点更改为使用 Cloud Storage XML API 请求端点
    • 将 Amazon Web Services (AWS) 访问密钥和密钥替换为相应的 Cloud Storage 访问 ID 和密钥(统称为 Cloud Storage HMAC 密钥)。
    • 请确保您的 x-amz- 标头使用受支持的 Cloud Storage 值。例如,x-amz-storage-class 应使用一个可用的 Cloud Storage 存储类别

      在简单迁移情景中使用 Cloud Storage XML API 时,通过在 Authorization 标头中指定 AWS 签名标识符,您可让 Cloud Storage 了解,您的请求中会出现 x-amz-* 标头和 Amazon S3 ACL XML 语法。Cloud Storage 会处理具有 x-goog-* 等效项的 x-amz-* 标头,如标头表中列出的标头。

完成这些更改后,您就可以开始使用现有工具和库将 HMAC 请求发送到 Cloud Storage。

例如,以下示例演示了如何使用 Amazon S3 SDK 列出 Cloud Storage 存储桶:

Go

如需了解详情,请参阅 Cloud Storage Go API 参考文档

如需向 Cloud Storage 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

import (
	"context"
	"fmt"
	"io"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

func listGCSBuckets(w io.Writer, googleAccessKeyID string, googleAccessKeySecret string) error {
	// googleAccessKeyID := "Your Google Access Key ID"
	// googleAccessKeySecret := "Your Google Access Key Secret"

	// Create a new client and do the following:
	// 1. Change the endpoint URL to use the Google Cloud Storage XML API endpoint.
	// 2. Use Cloud Storage HMAC Credentials.
	sess := session.Must(session.NewSession(&aws.Config{
		Region:      aws.String("auto"),
		Endpoint:    aws.String("https://storage.googleapis.com"),
		Credentials: credentials.NewStaticCredentials(googleAccessKeyID, googleAccessKeySecret, ""),
	}))

	client := s3.New(sess)
	ctx := context.Background()

	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()
	result, err := client.ListBucketsWithContext(ctx, &s3.ListBucketsInput{})
	if err != nil {
		return fmt.Errorf("ListBucketsWithContext: %w", err)
	}

	fmt.Fprintf(w, "Buckets:")
	for _, b := range result.Buckets {
		fmt.Fprintf(w, "%s\n", aws.StringValue(b.Name))
	}

	return nil
}

Java

如需了解详情,请参阅 Cloud Storage Java API 参考文档

如需向 Cloud Storage 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.Bucket;
import java.util.List;

public class ListGcsBuckets {
  public static void listGcsBuckets(String googleAccessKeyId, String googleAccessKeySecret) {

    // String googleAccessKeyId = "your-google-access-key-id";
    // String googleAccessKeySecret = "your-google-access-key-secret";

    // Create a BasicAWSCredentials using Cloud Storage HMAC credentials.
    BasicAWSCredentials googleCreds =
        new BasicAWSCredentials(googleAccessKeyId, googleAccessKeySecret);

    // Create a new client and do the following:
    // 1. Change the endpoint URL to use the Google Cloud Storage XML API endpoint.
    // 2. Use Cloud Storage HMAC Credentials.
    AmazonS3 interopClient =
        AmazonS3ClientBuilder.standard()
            .withEndpointConfiguration(
                new AwsClientBuilder.EndpointConfiguration(
                    "https://storage.googleapis.com", "auto"))
            .withCredentials(new AWSStaticCredentialsProvider(googleCreds))
            .build();

    // Call GCS to list current buckets
    List<Bucket> buckets = interopClient.listBuckets();

    // Print bucket names
    System.out.println("Buckets:");
    for (Bucket bucket : buckets) {
      System.out.println(bucket.getName());
    }

    // Explicitly clean up client resources.
    interopClient.shutdown();
  }

Python

如需了解详情,请参阅 Cloud Storage Python API 参考文档

如需向 Cloud Storage 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

import boto3  # type: ignore


def list_gcs_buckets(
    google_access_key_id: str, google_access_key_secret: str
) -> List[str]:
    """Lists all Cloud Storage buckets using AWS SDK for Python (boto3)
    Positional arguments:
        google_access_key_id: hash-based message authentication code (HMAC) access ID
        google_access_key_secret: HMAC access secret

    Returned value is a list of strings, one for each bucket name.

    To use this sample:
    1. Create a Cloud Storage HMAC key: https://cloud.google.com/storage/docs/authentication/managing-hmackeys#create
    2. Change endpoint_url to a Google Cloud Storage XML API endpoint.

    To learn more about HMAC: https://cloud.google.com/storage/docs/authentication/hmackeys#overview
    """
    client = boto3.client(
        "s3",
        region_name="auto",
        endpoint_url="https://storage.googleapis.com",
        aws_access_key_id=google_access_key_id,
        aws_secret_access_key=google_access_key_secret,
    )

    # Call GCS to list current buckets
    response = client.list_buckets()

    # Return list of bucket names
    results = []
    for bucket in response["Buckets"]:
        results.append(bucket["Name"])
        print(bucket["Name"])  # Can remove if not needed after development
    return results

设置默认项目

如需在简单迁移情景中使用 Cloud Storage,建议您设置一个默认项目,Cloud Storage 会使用该项目执行某些操作,例如 GET 服务或 PUT 存储桶。如果您未设置默认项目,则必须在特定请求中指定项目标头

要设置默认项目,请执行以下操作:

  1. 在 Google Cloud 控制台中打开 Cloud Storage 设置页面
  2. 选择互操作标签页。
  3. 点击位于“互操作访问的默认项目”部分中的PROJECT-ID 设置为默认项目

    如果该项目已经是默认项目,您将会看到 PROJECT-ID 是用于互操作访问的默认项目

该项目现在是您的默认项目。您可以随时更改默认项目,方法是选择其他项目并按照上述步骤进行操作。

或者,指定项目标头

您还可以在需要您指定项目的各个请求中使用 x-amz-project-id 标头,以取代设置默认项目或作为其补充。

  • 即使已有默认项目,使用 x-amz-project-id 的请求也会使用标头中指定的项目。

x-amz-project-id 标头在以下情况下很有用:

  • 您正在处理多个项目。
  • 您的请求由与其他项目关联的服务账号发出,因为服务账号会将其父项目用作默认项目。

请注意,Amazon S3 没有项目,因此根据您使用的工具或客户端库,可能无法指定 x-amz-project-id 标头。在这种情况下,您应该设置默认项目

使用 HMAC 密钥

如需在简单迁移情景中使用 Cloud Storage XML API,请使用 Cloud Storage 基于哈希的消息认证码 (HMAC) 密钥作为凭据。通常,您应该创建与服务账号关联的 HMAC 密钥;但您也可以选择使用与用户账号关联的 HMAC 密钥。

在简单迁移情景中进行身份验证

使用 Authorization 标头

如果您要在简单迁移情景中进行需要身份验证的操作,请在操作中添加一个 Authorization 请求标头(与向 Amazon S3 发出请求时一样)。Amazon S3 请求的 Authorization 标头语法如下:

Authorization: AWS4-HMAC-SHA256 Credential=AWS-ACCESS-KEY/CREDENTIAL_SCOPE, SignedHeaders=SIGNED_HEADERS, Signature=SIGNATURE

在简单迁移情景中,您只需更改标头以使用 Cloud Storage HMAC 访问 ID,并确保您附加的 Signature 是使用 Cloud Storage HMAC 密钥计算得出的:

Authorization: ALGORITHM Credential=GOOG-ACCESS-ID/CREDENTIAL_SCOPE, SignedHeaders=SIGNED_HEADERS, Signature=SIGNATURE

Authorization 标头包含以下几个部分:

  • ALGORITHM:您使用的签名算法和版本。如果使用 AWS4-HMAC-SHA256,则表示您使用 HMAC V4 签名,并打算发送 x-amz-* 标头。您也可以使用 GOOG4-HMAC-SHA256,这表示您使用 HMAC V4 签名,并打算发送 x-goog-* 标头。

  • GOOG-ACCESS-ID:访问 ID 标识发出请求并对请求签名的实体。在简单迁移中,请将您用于访问 Amazon S3 的 Amazon Web Service (AWS) 访问密钥 ID 替换为您的 Cloud Storage HMAC 访问 ID。您的 Cloud Storage HMAC 访问 ID 应以 GOOG 开头。

  • CREDENTIAL_SCOPE:凭据范围,如签名中所定义。在简单迁移中,如果您使用 AWS4-HMAC-SHA256 作为 ALGORITHM 值,则无需更改凭据范围。

  • SIGNED_HEADERS:以英文分号分隔的标头名称列表,其中包含对此请求进行签名所必需标头的名称。所有标头应使用小写,并按字符代码排序。

    Amazon S3 样式签名标头字符串示例如下所示:

    content-type;host;x-amz-date

    在简单迁移中,您无需对签名标头字符串进行任何更改。

  • SIGNATURE:允许对请求进行身份验证的签名。在简单迁移中,将 AWS 访问密钥信息替换为等效的 Cloud Storage HMAC 密钥信息。

身份验证请求示例

以下示例会将名为 /europe/france/paris.jpg 的对象上传到名为 my-travel-maps 的存储桶,应用预定义 ACL public-read,并为审核者定义自定义元数据标头。以下是对 Amazon S3 中的存储桶发出的请求:

PUT europe/france/paris.jpg HTTP/1.1
Host: my-travel-maps.s3.amazonaws.com
Date: Mon, 11 Mar 2019 23:46:19 GMT
Content-Length: 888814
Content-Type: image/jpg
x-amz-acl: public-read
x-amz-date:20190311T192918Z
x-amz-meta-reviewer: joe,jane
Authorization: AWS4-HMAC-SHA256 Credential=AWS-ACCESS-KEY/20190311/us-east-1/s3/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-acl;x-amz-date;x-amz-meta-reviewer, Signature=SIGNATURE

以下是针对 Cloud Storage 中的存储桶的请求:

PUT europe/france/paris.jpg HTTP/1.1
Host: my-travel-maps.storage.googleapis.com
Date: Mon, 11 Mar 2019 23:46:19 GMT
Content-Length: 888814
Content-Type: image/jpg
x-amz-acl: public-read
x-amz-date:20190311T192918Z
x-amz-meta-reviewer: joe,jane
Authorization: AWS4-HMAC-SHA256 Credential=GOOG-ACCESS-ID/20190311/us-east-1/s3/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-acl;x-amz-date;x-amz-meta-reviewer, Signature=SIGNATURE

以下是为此请求创建的相应规范化请求:

PUT
/europe/france/paris.jpg

content-length:888814
content-type:image/jpg
host:my-travel-maps.storage.googleapis.com
x-amz-acl:public-read
x-amz-date:20190311T192918Z
x-amz-meta-reviewer:joe,jane

content-length,content-type,host,x-amz-acl,x-amz-date,x-amz-meta-reviewer
82e3da8b3f35989512e8d428add7eca73ab0e5f36586e66fbad8e1051343cbd2

以下是为此请求创建的要签名的相应字符串:

AWS4-HMAC-SHA256
20190311T192918Z
20190311/us-east-1/s3/aws4_request
73918a5ff373d7a03e406fbf9ea35675396b06fca2af76c27a5c451fa783ef65

此请求未提供 Content-MD5 标头,因此消息中显示了空字符串(第二行)。

简单迁移情景中的访问权限控制

为了支持简单迁移,Cloud Storage 允许使用 Amazon S3 生成的 ACL。在简单迁移情景中,您将使用 AWS 作为签名标识符,让 Cloud Storage 了解将会收到采用 Amazon S3 ACL XML 语法的 ACL 语法请求。您应确保自己使用的 Amazon S3 ACL 会映射到 Cloud Storage ACL 模型。例如,如果您的工具和库使用 Amazon S3 的 ACL 语法授予存储桶 WRITE 权限,那么它们还必须授予存储桶 READ 权限,因为 Cloud Storage 采用同心权限(即授予其中一种权限时,也会同时授予其他权限)。使用 Cloud Storage 语法授予 WRITE 权限时,您无需同时指定 WRITEREAD 权限。

在以下情景中,Cloud Storage 支持 Amazon S3 ACL 语法:

  • 向 Cloud Storage 发出检索 ACL 的请求(例如 GET Object 或 GET Bucket 请求)时,Cloud Storage 会返回 Amazon S3 ACL 语法请求。
  • 向 Cloud Storage 发出应用 ACL 的请求(例如 PUT Object 或 PUT Bucket 请求)时,Cloud Storage 应会收到 Amazon S3 ACL 语法请求。

简单迁移情景中的 Authorization 标头将使用 AWS 作为签名标识符,但会搭配使用您的 Google 访问 ID。

Authorization: AWS4-HMAC-SHA256 Credential=GOOG-ACCESS-ID/CREDENTIAL_SCOPE, SignedHeaders=SIGNED_HEADERS, Signature=SIGNATURE

以下示例显示了对 Cloud Storage 发出的 GET 请求,该请求要求返回对象的 ACL。

GET europe/france/paris.jpg?acl HTTP/1.1
Host: my-travel-maps.storage.googleapis.com
Date: Thu, 21 Feb 2019 23:50:10 GMT
Content-Type: application/xml
X-Amz-Date: 20190221T235010Z
Authorization: AWS4-HMAC-SHA256 Credential=GOOGMC5PDPA5JLZYQMHQHRAX/20190221/region/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=29088b1d6dfeb2549f6ff67bc3744abb7e45475f0ad60400485805415bbfc534

该请求的响应包含使用 Amazon S3 ACL 语法的 ACL。

<?xml version='1.0' encoding='UTF-8'?>
<AccessControlPolicy>
    <Owner>
        <ID>00b4903a972faa8bcce9382686e9129676f1cd6e5def1f5663affc2ba4652490
        </ID>
        <DisplayName>OwnerName</DisplayName>
    </Owner>
    <AccessControlList>
        <Grant>
            <Grantee xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
                xsi:type='CanonicalUser'>
                <ID>00b4903a972faa8bcce9382686e9129676f1cd6e5def1f5663affc2ba4652490</ID>
                <DisplayName>UserName</DisplayName>
            </Grantee>
            <Permission>FULL_CONTROL</Permission>
        </Grant>
    </AccessControlList>
</AccessControlPolicy>

以下示例显示了对 Cloud Storage 发出的 PUT 请求,该请求要求设置对象的 ACL。该示例显示了使用 Amazon S3 ACL 语法的请求正文。

PUT europe/france/paris.jpg?acl HTTP/1.1
Host: my-travel-maps.storage.googleapis.com
Date: Thu, 21 Feb 2019 23:50:10 GMT
Content-Type: application/xml
Content-Length: 337
X-Amz-Date: 20190221T235010Z
Authorization: AWS4-HMAC-SHA256 Credential=GOOGMC5PDPA5JLZYQMHQHRAX/20190221/region/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=29088b1d6dfeb2549f6ff67bc3744abb7e45475f0ad60400485805415bbfc534

<?xml version='1.0' encoding='utf-8'?>
<AccessControlPolicy>
  <AccessControlList>
    <Grant>
      <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="AmazonCustomerByEmail">
        <EmailAddress>jane@gmail.com</EmailAddress>
      </Grantee>
      <Permission>FULL_CONTROL</Permission>
    </Grant>
  </AccessControlList>
</AccessControlPolicy>

最后,在简单迁移情景中,您还可以在 Authorization 标头中使用 GOOG1 签名标识符。在这种情况下,您必须使用 Cloud Storage ACL 语法,并确保所有 x-amz-* 标头都已更改为 x-goog-*。虽然上述做法可行,但我们建议您选择完整迁移,以便充分利用 Cloud Storage 的全部优势。

针对 XML API 与 Amazon S3 兼容性的支持服务

有关 XML API 互操作性的讨论,请参阅 Stack Overflow(使用 google-cloud-storage 标记)。

后续步骤