

# 使用 S3 on Outposts 对象
<a name="S3OutpostsWorkingObjects"></a>

通过使用 Amazon S3 on Outposts，您可以在 AWS Outposts 上创建 S3 桶，并在本地为需要本地数据访问、本地数据处理和数据驻留的应用程序轻松存储和检索对象。S3 on Outposts 提供了一个新的存储类 S3 Outposts (`OUTPOSTS`)；该存储类使用 Amazon S3 API，并且用于在 AWS Outposts 上的多个设备和服务器之间持久冗余地存储数据。您通过 Virtual Private Cloud（VPC）使用接入点和端点连接与 Outposts 桶进行通信。您可以像在 Amazon S3 桶中一样在 Outpost 桶上使用相同的 API 和功能，包括访问策略、加密和标记。您可以通过 AWS 管理控制台、AWS Command Line Interface (AWS CLI)、AWS SDK 或 REST API 使用 S3 on Outposts。

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

对象 ARN 使用以下格式，其中包括 Outpost 归属的 AWS 区域、AWS 账户 ID、Outpost ID、存储桶名称和对象键：

```
arn:aws:s3-outposts:us-west-2:123456789012:​outpost/op-01ac5d28a6a232904/bucket/amzn-s3-demo-bucket1/object/myobject
```

对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

**Topics**
+ [将对象上传到 S3 on Outposts 存储桶](S3OutpostsUploadObjects.md)
+ [使用 适用于 Java 的 AWS SDK 复制 Amazon S3 on Outposts 存储桶中的对象](S3OutpostsCopyObject.md)
+ [从 Amazon S3 on Outposts 存储桶获取对象](S3OutpostsGetObject.md)
+ [列出 Amazon S3 on Outposts 存储桶中的对象](S3OutpostsListObjects.md)
+ [删除 Amazon S3 on Outposts 存储桶中的对象](S3OutpostsDeleteObject.md)
+ [使用 HeadBucket 确定是否存在 S3 on Outposts 存储桶以及您是否具有访问权限。](S3OutpostsHeadBucket.md)
+ [使用适用于 Java 的 SDK 执行和管理分段上传](S3OutpostsMPU.md)
+ [使用适用于 S3 on Outposts 的预签名 URL](S3OutpostsPresignedURL.md)
+ [Amazon S3 on Outposts 与本地 Amazon EMR on Outposts](s3-outposts-emr.md)
+ [授权和身份验证缓存](s3-outposts-auth-cache.md)

# 将对象上传到 S3 on Outposts 存储桶
<a name="S3OutpostsUploadObjects"></a>

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

以下 AWS CLI 和适用于 Java 的 AWS SDK 示例演示如何通过使用访问点将对象上传到 S3 on Outposts 存储桶。

------
#### [ AWS CLI ]

**Example**  
以下示例使用 AWS CLI 将一个名为 `sample-object.xml` 的对象放置到 S3 on Outposts 存储桶 (`s3-outposts:PutObject`)。要使用此命令，请将每个 `user input placeholder` 替换为您自己的信息。有关此命令的更多信息，请参阅《AWS CLI 参考》中的 [put-object](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-object.html)。  

```
aws s3api put-object --bucket arn:aws:s3-outposts:Region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point --key sample-object.xml --body sample-object.xml
```

------
#### [ SDK for Java ]

**Example**  
有关如何使用适用于 Java 的 AWS SDK 将对象上传到 S3 Outposts 存储桶的示例，请参阅《AWS SDK for Java 2.x Code Examples》**中的 [PutObjectOnOutpost.java](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/s3/src/main/java/com/example/s3/outposts/PutObjectOnOutpost.java)。

------

# 使用 适用于 Java 的 AWS SDK 复制 Amazon S3 on Outposts 存储桶中的对象
<a name="S3OutpostsCopyObject"></a>

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

以下示例显示如何使用 适用于 Java 的 AWS SDK 复制 S3 on Outposts 存储桶中的对象。

## 使用适用于 Java 的 AWS SDK
<a name="S3OutpostsCopyObjectJava"></a>

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 将一个对象复制到同一个存储桶中的新对象。要使用此示例，请将 `user input placeholders` 替换为您自己的信息。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CopyObjectRequest;

public class CopyObject {
    public static void main(String[] args) {
        String accessPointArn = "*** access point ARN ***";
        String sourceKey = "*** Source object key ***";
        String destinationKey = "*** Destination object key ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            // Copy the object into a new object in the same bucket.
            CopyObjectRequest copyObjectRequest = new CopyObjectRequest(accessPointArn, sourceKey, accessPointArn, destinationKey);
            s3Client.copyObject(copyObjectRequest);
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

# 从 Amazon S3 on Outposts 存储桶获取对象
<a name="S3OutpostsGetObject"></a>

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

下面的示例演示如何使用 AWS Command Line Interface (AWS CLI) 和适用于 Java 的 AWS SDK 下载（获取）对象。

## 使用 AWS CLI
<a name="S3OutpostsGetObjectCLI"></a>

以下示例使用 AWS CLI 从 S3 on Outposts 存储桶 (`s3-outposts:GetObject`) 获取一个名为 `sample-object.xml` 的对象。要使用此命令，请将每个 `user input placeholder` 替换为您自己的信息。有关此命令的更多信息，请参阅《AWS CLI 参考》中的 *get-object*。

```
aws s3api get-object --bucket arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point --key testkey sample-object.xml
```

## 使用适用于 Java 的 AWS SDK
<a name="S3OutpostsGetObjectJava"></a>

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 获取对象。要使用此示例，请将每个 `user input placeholder` 替换为您自己的信息。有关更多信息，请参阅 *Amazon Simple Storage Service API 参考*中的 [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html)。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
import com.amazonaws.services.s3.model.S3Object;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class GetObject {
    public static void main(String[] args) throws IOException {
        String accessPointArn = "*** access point ARN ***";
        String key = "*** Object key ***";

        S3Object fullObject = null, objectPortion = null, headerOverrideObject = null;
        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            // Get an object and print its contents.
            System.out.println("Downloading an object");
            fullObject = s3Client.getObject(new GetObjectRequest(accessPointArn, key));
            System.out.println("Content-Type: " + fullObject.getObjectMetadata().getContentType());
            System.out.println("Content: ");
            displayTextInputStream(fullObject.getObjectContent());

            // Get a range of bytes from an object and print the bytes.
            GetObjectRequest rangeObjectRequest = new GetObjectRequest(accessPointArn, key)
                    .withRange(0, 9);
            objectPortion = s3Client.getObject(rangeObjectRequest);
            System.out.println("Printing bytes retrieved.");
            displayTextInputStream(objectPortion.getObjectContent());

            // Get an entire object, overriding the specified response headers, and print the object's content.
            ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides()
                    .withCacheControl("No-cache")
                    .withContentDisposition("attachment; filename=example.txt");
            GetObjectRequest getObjectRequestHeaderOverride = new GetObjectRequest(accessPointArn, key)
                    .withResponseHeaders(headerOverrides);
            headerOverrideObject = s3Client.getObject(getObjectRequestHeaderOverride);
            displayTextInputStream(headerOverrideObject.getObjectContent());
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        } finally {
            // To ensure that the network connection doesn't remain open, close any open input streams.
            if (fullObject != null) {
                fullObject.close();
            }
            if (objectPortion != null) {
                objectPortion.close();
            }
            if (headerOverrideObject != null) {
                headerOverrideObject.close();
            }
        }
    }

    private static void displayTextInputStream(InputStream input) throws IOException {
        // Read the text input stream one line at a time and display each line.
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        String line = null;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        System.out.println();
    }
}
```

# 列出 Amazon S3 on Outposts 存储桶中的对象
<a name="S3OutpostsListObjects"></a>

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

**注意**  
对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

以下示例显示如何使用 AWS CLI 和适用于 Java 的 AWS SDK 列出 S3 on Outposts 存储桶中的对象。

## 使用 AWS CLI
<a name="S3OutpostsListObjectsCLI"></a>

以下示例使用 AWS CLI 列出 S3 on Outposts 存储桶 (`s3-outposts:ListObjectsV2`) 中的对象。要使用此命令，请将每个 `user input placeholder` 替换为您自己的信息。有关此命令的更多信息，请参阅《AWS CLI 参考》中的 [list-objects-v2](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/list-objects-v2.html)。

```
aws s3api list-objects-v2 --bucket arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point
```

**注意**  
通过 AWS SDK 将此操作与 Amazon S3 on Outposts 结合使用时，您可以通过以下表单使用 Outposts 访问点 ARN 代替存储桶的名称：`arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-Outposts-Access-Point`。有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

## 使用适用于 Java 的 AWS SDK
<a name="S3OutpostsListObjectsJava"></a>

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 列出桶中的对象。要使用此示例，请将每个 `user input placeholder` 替换为您自己的信息。

**重要**  
此示例使用 [ListObjectsV2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html)，这是 `ListObjects` API 操作的最新版本。我们建议您使用此修订后的 API 操作进行应用程序开发。为了实现向后兼容，Amazon S3 继续支持此 API 操作的先前版本。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ListObjectsV2Request;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.S3ObjectSummary;

public class ListObjectsV2 {

    public static void main(String[] args) {
        String accessPointArn = "*** access point ARN ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            System.out.println("Listing objects");

            // maxKeys is set to 2 to demonstrate the use of
            // ListObjectsV2Result.getNextContinuationToken()
            ListObjectsV2Request req = new ListObjectsV2Request().withBucketName(accessPointArn).withMaxKeys(2);
            ListObjectsV2Result result;

            do {
                result = s3Client.listObjectsV2(req);

                for (S3ObjectSummary objectSummary : result.getObjectSummaries()) {
                    System.out.printf(" - %s (size: %d)\n", objectSummary.getKey(), objectSummary.getSize());
                }
                // If there are more than maxKeys keys in the bucket, get a continuation token
                // and list the next objects.
                String token = result.getNextContinuationToken();
                System.out.println("Next Continuation Token: " + token);
                req.setContinuationToken(token);
            } while (result.isTruncated());
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

# 删除 Amazon S3 on Outposts 存储桶中的对象
<a name="S3OutpostsDeleteObject"></a>

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

以下示例显示如何使用 AWS Command Line Interface (AWS CLI) 和适用于 Java 的 AWS SDK 从 S3 on Outposts 存储桶删除单个或多个对象。

## 使用 AWS CLI
<a name="S3OutpostsDeleteObjectsCLI"></a>

以下示例显示如何从 S3 on Outposts 存储桶删除单个或多个对象。







------
#### [ delete-object ]

以下示例使用 AWS CLI 从 S3 on Outposts 存储桶 (`s3-outposts:DeleteObject`) 删除一个名为 `sample-object.xml` 的对象。要使用此命令，请将每个 `user input placeholder` 替换为您自己的信息。有关此命令的更多信息，请参阅《AWS CLI 参考》中的 [delete-object](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/delete-object.html)。

```
aws s3api delete-object --bucket arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point --key sample-object.xml
```

------
#### [ delete-objects ]

以下示例使用 AWS CLI 从 S3 on Outposts 存储桶 (`s3-outposts:DeleteObject`) 删除名为 `sample-object.xml` 和 `test1.text` 的两个对象。要使用此命令，请将每个 `user input placeholder` 替换为您自己的信息。有关此命令的更多信息，请参阅《AWS CLI 参考》中的 *delete-objects*。

```
aws s3api delete-objects --bucket arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point --delete file://delete.json

delete.json
{
  "Objects": [
    {
      "Key": "test1.txt"
    },
    {
      "Key": "sample-object.xml"
    }
  ],
  "Quiet": false
}
```

------

## 使用适用于 Java 的 AWS SDK
<a name="S3OutpostsDeleteObjectsJava"></a>

以下示例显示如何从 S3 on Outposts 存储桶删除单个或多个对象。

------
#### [ DeleteObject ]

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 删除存储桶中的对象。要使用此示例，请指定 Outpost 的访问点 ARN 和要删除的对象的密钥名称。有关更多信息，请参阅 *Amazon Simple Storage Service API 参考*中的 [DeleteObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.DeleteObjectRequest;

public class DeleteObject {
    public static void main(String[] args) {
        String accessPointArn = "*** access point ARN ***";
        String keyName = "*** key name ****";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            s3Client.deleteObject(new DeleteObjectRequest(accessPointArn, keyName));
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

------
#### [ DeleteObjects ]

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 向存储桶上传对象，然后删除对象。要使用此示例，请指定 Outpost 的访问点 ARN。有关更多信息，请参阅《Amazon Simple Storage Service API 参考》中的 [DeleteObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html)。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion;
import com.amazonaws.services.s3.model.DeleteObjectsResult;

import java.util.ArrayList;

public class DeleteObjects {

    public static void main(String[] args) {
       String accessPointArn = "arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point";
        

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            // Upload three sample objects.
            ArrayList<KeyVersion> keys = new ArrayList<KeyVersion>();
            for (int i = 0; i < 3; i++) {
                String keyName = "delete object example " + i;
                s3Client.putObject(accessPointArn, keyName, "Object number " + i + " to be deleted.");
                keys.add(new KeyVersion(keyName));
            }
            System.out.println(keys.size() + " objects successfully created.");

            // Delete the sample objects.
            DeleteObjectsRequest multiObjectDeleteRequest = new DeleteObjectsRequest(accessPointArn)
                    .withKeys(keys)
                    .withQuiet(false);

            // Verify that the objects were deleted successfully.
            DeleteObjectsResult delObjRes = s3Client.deleteObjects(multiObjectDeleteRequest);
            int successfulDeletes = delObjRes.getDeletedObjects().size();
            System.out.println(successfulDeletes + " objects successfully deleted.");
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

------

# 使用 HeadBucket 确定是否存在 S3 on Outposts 存储桶以及您是否具有访问权限。
<a name="S3OutpostsHeadBucket"></a>

对象是 Amazon S3 on Outposts 中存储的基础实体。每个对象都储存在一个存储桶中。您必须使用访问点才能访问 Outpost 存储桶中的任何对象。当您为对象操作指定桶时，可以使用访问点 Amazon 资源名称（ARN）或访问点别名。有关访问点别名的更多信息，请参阅[为您的 S3 on Outposts 桶访问点使用桶式别名](s3-outposts-access-points-alias.md)。

以下示例显示了 S3 on Outposts 访问点的 ARN 格式，其中包括 Outpost 所属区域的 AWS 区域 代码、AWS 账户 ID、Outpost ID 和访问点名称：

```
arn:aws:s3-outposts:region:account-id:outpost/outpost-id/accesspoint/accesspoint-name
```

有关 S3 on Outposts ARN 的更多信息，请参阅[S3 on Outposts 的资源 ARN](S3OutpostsIAM.md#S3OutpostsARN)。

**注意**  
对于 Amazon S3 on Outposts，对象数据始终存储在 Outpost 上。当 AWS 安装 Outpost 机架时，您的数据将保留在 Outpost 的本地，以满足数据驻留要求。您的对象永远不会离开您的 Outpost，也不在 AWS 区域 中。由于 AWS 管理控制台 托管在区域内，您无法使用控制台上传或管理 Outpost 中的对象。但是，您可以使用 REST API、AWS Command Line Interface (AWS CLI) 和 AWS SDK 通过访问点上传和管理对象。

以下 AWS Command Line Interface (AWS CLI) 和 适用于 Java 的 AWS SDK 示例显示如何使用 HeadBucket API 操作确定 Amazon S3 on Outposts 存储桶是否存在以及您是否有权访问该存储桶。有关更多信息，请参阅《Amazon Simple Storage Service API 参考》中的 [HeadBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html)。

## 使用 AWS CLI
<a name="S3OutpostsHeadBucketCLI"></a>

以下 S3 on Outposts AWS CLI 示例显示如何使用 `head-bucket` 命令确定存储桶是否存在以及您是否有权访问该存储桶。要使用此命令，请将每个 `user input placeholder` 替换为您自己的信息。有关此命令的更多信息，请参阅《AWS CLI 参考》中的 [head-bucket](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/head-bucket.html)。

```
aws s3api head-bucket --bucket arn:aws:s3-outposts:region:123456789012:outpost/op-01ac5d28a6a232904/accesspoint/example-outposts-access-point
```

## 使用适用于 Java 的 AWS SDK
<a name="S3OutpostsHeadBucketJava"></a>

以下 S3 on Outposts 示例显示如何确定存储桶是否存在以及您是否有权访问该存储桶。要使用此示例，请指定 Outpost 的访问点 ARN。有关更多信息，请参阅《Amazon Simple Storage Service API 参考》中的 [HeadBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html)。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.HeadBucketRequest;

public class HeadBucket {
    public static void main(String[] args) {
        String accessPointArn = "*** access point ARN ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            s3Client.headBucket(new HeadBucketRequest(accessPointArn));
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

# 使用适用于 Java 的 SDK 执行和管理分段上传
<a name="S3OutpostsMPU"></a>

使用 Amazon S3 on Outposts，您可以在 AWS Outposts 资源上创建 S3 存储桶，并在本地为需要本地数据访问、本地数据处理和数据驻留的应用程序存储和检索对象。您可以通过 AWS 管理控制台、AWS Command Line Interface (AWS CLI)、AWS SDK 或 REST API 使用 S3 on Outposts。有关更多信息，请参阅 [什么是 Amazon S3 on Outposts？](S3onOutposts.md) 

以下示例显示如何结合使用 S3 on Outposts 和 适用于 Java 的 AWS SDK 来执行和管理分段上传。

**Topics**
+ [在 S3 on Outposts 存储桶中执行对象的分段上传](#S3OutpostsInitiateMultipartUploadJava)
+ [通过分段上传，在 S3 on Outposts 存储桶中复制大型对象](#S3OutpostsCopyPartJava)
+ [在 S3 on Outposts 存储桶中列出对象的分段](#S3OutpostsListPartsJava)
+ [检索 S3 on Outposts 存储桶中正在进行的分段上传的列表](#S3OutpostsListMultipartUploadsJava)

## 在 S3 on Outposts 存储桶中执行对象的分段上传
<a name="S3OutpostsInitiateMultipartUploadJava"></a>

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 启动、上传和完成对象到存储桶的分段上传。要使用此示例，请将每个 `user input placeholder` 替换为您自己的信息。有关更多信息，请参阅《Amazon Simple Storage Service 用户指南》**中的[使用分段上传操作上传对象](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpu-upload-object.html)。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import java.util.ArrayList;
import java.util.List;

public class MultipartUploadCopy {
    public static void main(String[] args) {
        String accessPointArn = "*** Source access point ARN ***";
        String sourceObjectKey = "*** Source object key ***";
        String destObjectKey = "*** Target object key ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            // Initiate the multipart upload.
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(accessPointArn, destObjectKey);
            InitiateMultipartUploadResult initResult = s3Client.initiateMultipartUpload(initRequest);

            // Get the object size to track the end of the copy operation.
            GetObjectMetadataRequest metadataRequest = new GetObjectMetadataRequest(accessPointArn, sourceObjectKey);
            ObjectMetadata metadataResult = s3Client.getObjectMetadata(metadataRequest);
            long objectSize = metadataResult.getContentLength();

            // Copy the object using 5 MB parts.
            long partSize = 5 * 1024 * 1024;
            long bytePosition = 0;
            int partNum = 1;
            List<CopyPartResult> copyResponses = new ArrayList<CopyPartResult>();
            while (bytePosition < objectSize) {
                // The last part might be smaller than partSize, so check to make sure
                // that lastByte isn't beyond the end of the object.
                long lastByte = Math.min(bytePosition + partSize - 1, objectSize - 1);

                // Copy this part.
                CopyPartRequest copyRequest = new CopyPartRequest()
                        .withSourceBucketName(accessPointArn)
                        .withSourceKey(sourceObjectKey)
                        .withDestinationBucketName(accessPointArn)
                        .withDestinationKey(destObjectKey)
                        .withUploadId(initResult.getUploadId())
                        .withFirstByte(bytePosition)
                        .withLastByte(lastByte)
                        .withPartNumber(partNum++);
                copyResponses.add(s3Client.copyPart(copyRequest));
                bytePosition += partSize;
            }

            // Complete the upload request to concatenate all uploaded parts and make the copied object available.
            CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(
                    accessPointArn,
                    destObjectKey,
                    initResult.getUploadId(),
                    getETags(copyResponses));
            s3Client.completeMultipartUpload(completeRequest);
            System.out.println("Multipart copy complete.");
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process 
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client  
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }

    // This is a helper function to construct a list of ETags.
    private static List<PartETag> getETags(List<CopyPartResult> responses) {
        List<PartETag> etags = new ArrayList<PartETag>();
        for (CopyPartResult response : responses) {
            etags.add(new PartETag(response.getPartNumber(), response.getETag()));
        }
        return etags;
    }
```

## 通过分段上传，在 S3 on Outposts 存储桶中复制大型对象
<a name="S3OutpostsCopyPartJava"></a>

下面的 S3 on Outposts 示例使用适用于 Java 的 SDK 复制存储桶中的对象。要使用此示例，请将每个 `user input placeholder` 替换为您自己的信息。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import java.util.ArrayList;
import java.util.List;

public class MultipartUploadCopy {
    public static void main(String[] args) {
        String accessPointArn = "*** Source access point ARN ***";
        String sourceObjectKey = "*** Source object key ***";
        String destObjectKey = "*** Target object key ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            // Initiate the multipart upload.
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(accessPointArn, destObjectKey);
            InitiateMultipartUploadResult initResult = s3Client.initiateMultipartUpload(initRequest);

            // Get the object size to track the end of the copy operation.
            GetObjectMetadataRequest metadataRequest = new GetObjectMetadataRequest(accessPointArn, sourceObjectKey);
            ObjectMetadata metadataResult = s3Client.getObjectMetadata(metadataRequest);
            long objectSize = metadataResult.getContentLength();

            // Copy the object using 5 MB parts.
            long partSize = 5 * 1024 * 1024;
            long bytePosition = 0;
            int partNum = 1;
            List<CopyPartResult> copyResponses = new ArrayList<CopyPartResult>();
            while (bytePosition < objectSize) {
                // The last part might be smaller than partSize, so check to make sure
                // that lastByte isn't beyond the end of the object.
                long lastByte = Math.min(bytePosition + partSize - 1, objectSize - 1);

                // Copy this part.
                CopyPartRequest copyRequest = new CopyPartRequest()
                        .withSourceBucketName(accessPointArn)
                        .withSourceKey(sourceObjectKey)
                        .withDestinationBucketName(accessPointArn)
                        .withDestinationKey(destObjectKey)
                        .withUploadId(initResult.getUploadId())
                        .withFirstByte(bytePosition)
                        .withLastByte(lastByte)
                        .withPartNumber(partNum++);
                copyResponses.add(s3Client.copyPart(copyRequest));
                bytePosition += partSize;
            }

            // Complete the upload request to concatenate all uploaded parts and make the copied object available.
            CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(
                    accessPointArn,
                    destObjectKey,
                    initResult.getUploadId(),
                    getETags(copyResponses));
            s3Client.completeMultipartUpload(completeRequest);
            System.out.println("Multipart copy complete.");
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process 
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client  
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }

    // This is a helper function to construct a list of ETags.
    private static List<PartETag> getETags(List<CopyPartResult> responses) {
        List<PartETag> etags = new ArrayList<PartETag>();
        for (CopyPartResult response : responses) {
            etags.add(new PartETag(response.getPartNumber(), response.getETag()));
        }
        return etags;
    }
}
```

## 在 S3 on Outposts 存储桶中列出对象的分段
<a name="S3OutpostsListPartsJava"></a>

以下 S3 on Outposts 示例使用适用于 Java 的 SDK 列出存储桶中对象的分段。要使用此示例，请将每个 `user input placeholder` 替换为您自己的信息。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import java.util.List;

public class ListParts {
    public static void main(String[] args) {
        String accessPointArn = "*** access point ARN ***";
        String keyName = "*** Key name ***";
        String uploadId = "*** Upload ID ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            ListPartsRequest listPartsRequest = new ListPartsRequest(accessPointArn, keyName, uploadId);
            PartListing partListing = s3Client.listParts(listPartsRequest);
            List<PartSummary> partSummaries = partListing.getParts();

            System.out.println(partSummaries.size() + " multipart upload parts");
            for (PartSummary p : partSummaries) {
                System.out.println("Upload part: Part number = \"" + p.getPartNumber() + "\", ETag = " + p.getETag());
            }

        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

## 检索 S3 on Outposts 存储桶中正在进行的分段上传的列表
<a name="S3OutpostsListMultipartUploadsJava"></a>

以下 S3 on Outposts 示例说明如何使用适用于 Java 的 SDK 从 Outposts 存储桶检索正在进行的分段上传的列表。要使用此示例，请将每个 `user input placeholder` 替换为您自己的信息。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ListMultipartUploadsRequest;
import com.amazonaws.services.s3.model.MultipartUpload;
import com.amazonaws.services.s3.model.MultipartUploadListing;

import java.util.List;

public class ListMultipartUploads {
    public static void main(String[] args) {
                String accessPointArn = "*** access point ARN ***";

        try {
            // This code expects that you have AWS credentials set up per:
            // https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .enableUseArnRegion()
                    .build();

            // Retrieve a list of all in-progress multipart uploads.
            ListMultipartUploadsRequest allMultipartUploadsRequest = new ListMultipartUploadsRequest(accessPointArn);
            MultipartUploadListing multipartUploadListing = s3Client.listMultipartUploads(allMultipartUploadsRequest);
            List<MultipartUpload> uploads = multipartUploadListing.getMultipartUploads();

            // Display information about all in-progress multipart uploads.
            System.out.println(uploads.size() + " multipart upload(s) in progress.");
            for (MultipartUpload u : uploads) {
                System.out.println("Upload in progress: Key = \"" + u.getKey() + "\", id = " + u.getUploadId());
            }
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

# 使用适用于 S3 on Outposts 的预签名 URL
<a name="S3OutpostsPresignedURL"></a>

要授予对 Outpost 本地存储对象的限时访问权限而不更新存储桶策略，您可以使用预签名 URL。借助预签名 URL，作为存储桶的所有者，您可以与您虚拟私有云（VPC）中的个人共享对象，或者向其授予上传或删除对象的权限。

使用 AWS SDK 或 AWS Command Line Interface（AWS CLI）创建预签名 URL 时，您会将该 URL 与某个特定的操作关联。您还可以通过选择自定义到期时间来授予对预签名 URL 的限时访问权限，自定义到期时间最短可为 1 秒，最长可为 7 天。共享预签名 URL 时，VPC 中的个人可以执行嵌入在 URL 中的操作，如同他们就是原始签名用户。URL 在到达其到期时间时将会过期，不再有效。

## 限制预签名 URL 功能
<a name="S3OutpostsPresignedUrlUploadObjectLimitCapabilities"></a>

预签名 URL 的功能受创建它的用户的权限所限制。预签名 URL 实质上是一种不记名令牌，向持有相关 URL 的人授予了访问权限。因此，我们建议您适当地保护它们。

**AWS 签名版本 4（SigV4）**  
使用 AWS 签名版本 4（SigV4）对预签名 URL 请求进行身份认证时要强制执行特定的行为，您可以在存储桶策略和访问点策略中使用条件键。例如，您可以创建一个使用 `s3-outposts:signatureAge` 条件的存储桶策略，以在相关签名的存在时间超过 10 分钟时，拒绝对 `example-outpost-bucket` 存储桶中对象的任何 Amazon S3 on Outposts 预签名 URL 请求。要使用此示例，请将 *`user input placeholders`* 替换为您自己的信息。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "Deny a presigned URL request if the signature is more than 10 minutes old",
            "Effect": "Deny",
            "Principal": {"AWS":"444455556666"},
            "Action": "s3-outposts:*",
            "Resource": "arn:aws:s3-outposts:us-east-1:111122223333:outpost/op-01ac5d28a6a232904/bucket/example-outpost-bucket/object/*",
            "Condition": {
                "NumericGreaterThan": {"s3-outposts:signatureAge": 600000},
                "StringEquals": {"s3-outposts:authType": "REST-QUERY-STRING"}
            }
        }
    ]
}
```

------

有关在使用签名版本 4 对预签名 URL 请求进行身份认证时，可用于强制执行特定行为的条件键和其他示例策略的列表，请参阅 [AWS 签名版本 4（SigV4）身份认证特定的策略键](s3-outposts-bucket-policy-s3-sigv4-conditions.md)。

**网络路径限制**  
如果要将预签名 URL 的使用和所有 S3 on Outposts 访问限定为特定的网络路径，您可以编写要求使用特定网络路径的策略。要对发起调用的 IAM 主体设置限制，您可以使用基于身份的 AWS Identity and Access Management（IAM）策略（例如用户、组或角色策略）。要对 S3 on Outposts 资源设置限制，您可以使用基于资源的策略（例如，存储桶和访问点策略）。

对 IAM 主体实施网络路径限制后，要求拥有这些凭证的用户从指定的网络发出请求。对存储桶或接入点实施限制后，要求对该资源的所有请求都必须来自指定的网络。这些限制也适用于预签名 URL 以外的场景。

您使用的 IAM 全局条件取决于端点的类型。如果您使用适用于 S3 on Outposts 的公有端点，请使用 `aws:SourceIp`。如果您使用适用于 S3 on Outposts 的 VPC 端点，请使用 `aws:SourceVpc` 或 `aws:SourceVpce`。

以下 IAM policy 语句要求主体仅从指定的网络范围访问。AWS使用此策略语句时，所有访问都必须来自该范围。这包括有人使用适用于 S3 on Outposts 的预签名 URL 的情况。要使用此示例，请将 *`user input placeholders`* 替换为您自己的信息。

```
{
    "Sid": "NetworkRestrictionForIAMPrincipal",
    "Effect": "Deny",
    "Action": "*",
    "Resource": "*",
    "Condition": {
        "NotIpAddressIfExists": {"aws:SourceIp": "IP-address-range"},
        "BoolIfExists": {"aws:ViaAWSService": "false"}
    }
}
```

有关使用 `aws:SourceIP` AWS 全局条件键将对 S3 on Outposts 存储桶的访问限定为特定网络范围的示例存储桶策略，请参阅[使用 S3 on Outposts 设置 IAM](S3OutpostsIAM.md)。

## 谁可以创建预签名 URL
<a name="S3Outpostswho-presigned-url"></a>

具有有效安全凭证的任何人都可以创建预签名 URL。但要使 VPC 中的用户成功地访问对象，必须由拥有执行预签名 URL 所基于的操作权限的人创建该预签名 URL。

您可以使用下面的凭证创建预签名 URL：
+ **IAM 实例配置文件** – 有效期最长 6 小时。
+ **AWS Security Token Service** – 使用永久凭证（例如，AWS 账户 根用户或 IAM 用户的凭证）签名时，有效期最长 36 小时。
+ **IAM 用户** – 使用 AWS 签名版本 4 时，有效期最长 7 天。

  要创建有效期最长 7 天的预签名 URL，请首先为所使用的开发工具包委托 IAM 用户凭证（访问密钥和秘密密钥）。然后使用 AWS 签名版本 4 生成预签名 URL。

**注意**  
如果您已使用临时令牌创建了预签名 URL，则此 URL 将在令牌过期时过期，即使您使用更晚的到期时间创建了该 URL。
由于预签名 URL 将向持有该 URL 的任何人授予访问 S3 on Outposts 存储桶的权限，我们建议您妥善保护它们。有关保护预签名 URL 的更多信息，请参阅 [限制预签名 URL 功能](#S3OutpostsPresignedUrlUploadObjectLimitCapabilities)。

## S3 on Outposts 何时检查预签名 URL 的到期日期和时间？
<a name="S3Outpostspresigned-url-when-checked"></a>

在发出 HTTP 请求时，S3 on Outposts 会检查签名 URL 的到期日期和时间。例如，如果客户端刚好在到期时间之前开始下载某个大型文件，即使在下载过程中超过到期时间，下载也会继续进行。但如果连接断开，在客户端试图在超过到期时间后重新开始下载，则下载将会失败。

有关使用预签名 URL 共享或上传对象的更多信息，请参阅以下主题。

**Topics**
+ [限制预签名 URL 功能](#S3OutpostsPresignedUrlUploadObjectLimitCapabilities)
+ [谁可以创建预签名 URL](#S3Outpostswho-presigned-url)
+ [S3 on Outposts 何时检查预签名 URL 的到期日期和时间？](#S3Outpostspresigned-url-when-checked)
+ [使用预签名 URL 共享对象](S3OutpostsShareObjectPresignedURL.md)
+ [生成预签名 URL 以将对象上传到 S3 on Outposts 存储桶](S3OutpostsPresignedUrlUploadObject.md)

# 使用预签名 URL 共享对象
<a name="S3OutpostsShareObjectPresignedURL"></a>

要授予对 Outpost 本地存储对象的限时访问权限而不更新存储桶策略，您可以使用预签名 URL。借助预签名 URL，作为存储桶的所有者，您可以与您虚拟私有云（VPC）中的个人共享对象，或者向其授予上传或删除对象的权限。

使用 AWS SDK 或 AWS Command Line Interface（AWS CLI）创建预签名 URL 时，您会将该 URL 与某个特定的操作关联。您还可以通过选择自定义到期时间来授予对预签名 URL 的限时访问权限，自定义到期时间最短可为 1 秒，最长可为 7 天。共享预签名 URL 时，VPC 中的个人可以执行嵌入在 URL 中的操作，如同他们就是原始签名用户。URL 在到达其到期时间时将会过期，不再有效。



创建预签名 URL 时，必须提供您的安全凭证，然后指定以下内容：
+ 该 Amazon S3 on Outposts 存储桶的一个访问点 Amazon 资源名称（ARN）
+ 一个对象键
+ 一个 HTTP方法（`GET` 用于下载对象）
+ 一个到期日期和时间

预签名 URL 仅在指定的有效期内有效。也就是说，您必须在到期日期和时间到达之前启动该 URL 允许的操作。在到期日期和时间到达之前，您可以多次使用预签名 URL。如果您已使用临时令牌创建了预签名 URL，则此 URL 将在令牌过期时过期，即使您使用更晚的到期时间创建了该 URL。

虚拟私有云（VPC）中有权访问预签名 URL 的用户可以访问对象。例如，如果您在桶中具有一段视频，并且桶和对象均为私有，您可以通过生成预签名的 URL 来与其他用户共享视频。由于预签名 URL 将向持有该 URL 的任何人授予访问 S3 on Outposts 存储桶的权限，我们建议您妥善保护这些 URL。有关保护预签名 URL 的更多详细信息，请参阅 [限制预签名 URL 功能](S3OutpostsPresignedURL.md#S3OutpostsPresignedUrlUploadObjectLimitCapabilities)。

具有有效安全凭证的任何人都可以创建预签名 URL。但必须由拥有执行预签名 URL 所基于的操作权限的人创建该预签名 URL。有关更多信息，请参阅 [谁可以创建预签名 URL](S3OutpostsPresignedURL.md#S3Outpostswho-presigned-url)。

您可以使用 AWS SDK 和 AWS CLI 生成预签名 URL 以共享 S3 on Outposts 存储桶中的对象。有关更多信息，请参阅以下示例。

## 使用 AWS SDK
<a name="S3OutpostsShareObjectPreSignedURLSDK"></a>

您可以使用 AWS SDK 生成可以提供给其他人的预签名 URL，以便他们可以检索对象。

**注意**  
使用 AWS SDK 生成预签名 URL 时，预签名 URL 的最长到期时间为创建之时起 7 天。

------
#### [ Java ]

**Example**  
以下示例将生成一个预签名 URL，您可以将其提供给其他人，以便他们可以检索 S3 on Outposts 存储桶的对象。有关更多信息，请参阅 [使用适用于 S3 on Outposts 的预签名 URL](S3OutpostsPresignedURL.md)。要使用此示例，请将 *`user input placeholders`* 替换为您自己的信息。  

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.HttpMethod;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;

import java.io.IOException;
import java.net.URL;
import java.time.Instant;

public class GeneratePresignedURL {

    public static void main(String[] args) throws IOException {
        Regions clientRegion = Regions.DEFAULT_REGION;
        String accessPointArn = "*** access point ARN ***";
        String objectKey = "*** object key ***";

        try {
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .withRegion(clientRegion)
                    .withCredentials(new ProfileCredentialsProvider())
                    .build();

            // Set the presigned URL to expire after one hour.
            java.util.Date expiration = new java.util.Date();
            long expTimeMillis = Instant.now().toEpochMilli();
            expTimeMillis += 1000 * 60 * 60;
            expiration.setTime(expTimeMillis);

            // Generate the presigned URL.
            System.out.println("Generating pre-signed URL.");
            GeneratePresignedUrlRequest generatePresignedUrlRequest =
                    new GeneratePresignedUrlRequest(accessPointArn, objectKey)
                            .withMethod(HttpMethod.GET)
                            .withExpiration(expiration);
            URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);

            System.out.println("Pre-Signed URL: " + url.toString());
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process 
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

------
#### [ .NET ]

**Example**  
以下示例将生成一个预签名 URL，您可以将其提供给其他人，以便他们可以检索 S3 on Outposts 存储桶的对象。有关更多信息，请参阅 [使用适用于 S3 on Outposts 的预签名 URL](S3OutpostsPresignedURL.md)。要使用此示例，请将 *`user input placeholders`* 替换为您自己的信息。  

```
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using System;

namespace Amazon.DocSamples.S3
{
    class GenPresignedURLTest
    {
        private const string accessPointArn = "*** access point ARN ***"; 
        private const string objectKey = "*** object key ***";
        // Specify how long the presigned URL lasts, in hours.
        private const double timeoutDuration = 12;
        // Specify your bucket Region (an example Region is shown).
        private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
        private static IAmazonS3 s3Client;

        public static void Main()
        {
            s3Client = new AmazonS3Client(bucketRegion);
            string urlString = GeneratePreSignedURL(timeoutDuration);
        }
        static string GeneratePreSignedURL(double duration)
        {
            string urlString = "";
            try
            {
                GetPreSignedUrlRequest request1 = new GetPreSignedUrlRequest
                {
                    BucketName = accessPointArn,
                    Key = objectKey,
                    Expires = DateTime.UtcNow.AddHours(duration)
                };
                urlString = s3Client.GetPreSignedURL(request1);
            }
            catch (AmazonS3Exception e)
            {
                Console.WriteLine("Error encountered on server. Message:'{0}' when writing an object", e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
            }
            return urlString;
        }
    }
}
```

------
#### [ Python ]

使用适用于 Python (Boto3) 的 SDK 生成预签名 URL 以共享对象。例如，使用 Boto3 客户端和 `generate_presigned_url` 函数生成一个允许您 `GET` 对象的预签名 URL。

```
import boto3
    url = boto3.client('s3').generate_presigned_url(
    ClientMethod='get_object', 
    Params={'Bucket': 'ACCESS_POINT_ARN', 'Key': 'OBJECT_KEY'},
    ExpiresIn=3600)
```

有关使用适用于 Python 的 SDK（Boto3）生成预签名 URL 的更多信息，请参阅《AWS SDK for Python (Boto) API 参考》**中的 [Python](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.generate_presigned_url)。

------

## 使用 AWS CLI
<a name="S3OutpostsShareObjectPresignedCLI"></a>

以下示例 AWS CLI 命令将为一个 S3 on Outposts 存储桶生成一个预签名 URL。要使用此示例，请将 *`user input placeholders`* 替换为您自己的信息。

**注意**  
使用 AWS CLI 生成预签名 URL 时，预签名 URL 的最长到期时间为创建之时起 7 天。

```
aws s3 presign s3://arn:aws:s3-outposts:us-east-1:111122223333:outpost/op-01ac5d28a6a232904/accesspoint/example-outpost-access-point/mydoc.txt --expires-in 604800
```

有关更多信息，请参阅《AWS CLI 命令参考》中的 [presign](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/presign.html)。

# 生成预签名 URL 以将对象上传到 S3 on Outposts 存储桶
<a name="S3OutpostsPresignedUrlUploadObject"></a>

要授予对 Outpost 本地存储对象的限时访问权限而不更新存储桶策略，您可以使用预签名 URL。借助预签名 URL，作为存储桶的所有者，您可以与您虚拟私有云（VPC）中的个人共享对象，或者向其授予上传或删除对象的权限。

使用 AWS SDK 或 AWS Command Line Interface（AWS CLI）创建预签名 URL 时，您会将该 URL 与某个特定的操作关联。您还可以通过选择自定义到期时间来授予对预签名 URL 的限时访问权限，自定义到期时间最短可为 1 秒，最长可为 7 天。共享预签名 URL 时，VPC 中的个人可以执行嵌入在 URL 中的操作，如同他们就是原始签名用户。URL 在到达其到期时间时将会过期，不再有效。

创建预签名 URL 时，必须提供您的安全凭证，然后指定以下内容：
+ 该 Amazon S3 on Outposts 存储桶的一个访问点 Amazon 资源名称（ARN）
+ 一个对象键
+ 一个 HTP 方法（`PUT` 用于上传对象）
+ 一个到期日期和时间

预签名 URL 仅在指定的有效期内有效。也就是说，您必须在到期日期和时间到达之前启动该 URL 允许的操作。在到期日期和时间到达之前，您可以多次使用预签名 URL。如果您已使用临时令牌创建预签名 URL，则此 URL 将在令牌过期时过期，即使创建的 URL 的到期时间更晚也是如此。

如果预签名 URL 允许的操作由多个步骤构成（例如分段上传），则必须在到期时间前启动所有步骤。如果 S3 on Outposts 尝试使用某个已过期的 URL 启动某个步骤，您将会遇到错误。

虚拟私有云（VPC）中有权访问预签名 URL 的用户可上传对象。例如，VPC 中有权访问预签名 URL 的用户可以将对象上传到您的存储桶。由于预签名 URL 将向 VPC 中有权访问预签名 URL 的任何用户授予访问 S3 on Outposts 存储桶的权限，我们建议您妥善保护这些 URL。有关保护预签名 URL 的更多详细信息，请参阅 [限制预签名 URL 功能](S3OutpostsPresignedURL.md#S3OutpostsPresignedUrlUploadObjectLimitCapabilities)。

具有有效安全凭证的任何人都可以创建预签名 URL。但必须由拥有执行预签名 URL 所基于的操作权限的人创建该预签名 URL。有关更多信息，请参阅 [谁可以创建预签名 URL](S3OutpostsPresignedURL.md#S3Outpostswho-presigned-url)。

## 使用 AWS SDK 为 S3 on Outposts 对象操作生成预签名 URL
<a name="s3-outposts-presigned-urls-upload-examples"></a>

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
此示例演示了如何生成一个预签名 URL，以便在限定时间内用于将对象上传到某个 S3 on Outposts 存储桶。有关更多信息，请参阅 [使用适用于 S3 on Outposts 的预签名 URL](S3OutpostsPresignedURL.md)。  

```
    public static void signBucket(S3Presigner presigner, String outpostAccessPointArn, String keyName) {

        try {
            PutObjectRequest objectRequest = PutObjectRequest.builder()
                    .bucket(accessPointArn)
                    .key(keyName)
                    .contentType("text/plain")
                    .build();

            PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
                    .signatureDuration(Duration.ofMinutes(10))
                    .putObjectRequest(objectRequest)
                    .build();

            PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest);


            String myURL = presignedRequest.url().toString();
            System.out.println("Presigned URL to upload a file to: " +myURL);
            System.out.println("Which HTTP method must be used when uploading a file: " +
                    presignedRequest.httpRequest().method());

            // Upload content to the S3 on Outposts bucket by using this URL.
            URL url = presignedRequest.url();

            // Create the connection and use it to upload the new object by using the presigned URL.
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type","text/plain");
            connection.setRequestMethod("PUT");
            OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
            out.write("This text was uploaded as an object by using a presigned URL.");
            out.close();

            connection.getResponseCode();
            System.out.println("HTTP response code is " + connection.getResponseCode());

        } catch (S3Exception e) {
            e.getStackTrace();
        } catch (IOException e) {
            e.getStackTrace();
        }
    }
```

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
此示例演示了如何生成可在限定时间内执行某个 S3 on Outposts 操作的预签名 URL。有关更多信息，请参阅 [使用适用于 S3 on Outposts 的预签名 URL](S3OutpostsPresignedURL.md)。要使用该 URL 发出请求，请使用 `Requests` 程序包。  

```
import argparse
import logging
import boto3
from botocore.exceptions import ClientError
import requests

logger = logging.getLogger(__name__)


def generate_presigned_url(s3_client, client_method, method_parameters, expires_in):
    """
    Generate a presigned S3 on Outposts URL that can be used to perform an action.

    :param s3_client: A Boto3 Amazon S3 client.
    :param client_method: The name of the client method that the URL performs.
    :param method_parameters: The parameters of the specified client method.
    :param expires_in: The number of seconds that the presigned URL is valid for.
    :return: The presigned URL.
    """
    try:
        url = s3_client.generate_presigned_url(
            ClientMethod=client_method,
            Params=method_parameters,
            ExpiresIn=expires_in
        )
        logger.info("Got presigned URL: %s", url)
    except ClientError:
        logger.exception(
            "Couldn't get a presigned URL for client method '%s'.", client_method)
        raise
    return url


def usage_demo():
    logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')

    print('-'*88)
    print("Welcome to the Amazon S3 on Outposts presigned URL demo.")
    print('-'*88)

    parser = argparse.ArgumentParser()
    parser.add_argument('accessPointArn', help="The name of the S3 on Outposts access point ARN.")
    parser.add_argument(
        'key', help="For a GET operation, the key of the object in S3 on Outposts. For a "
                    "PUT operation, the name of a file to upload.")
    parser.add_argument(
        'action', choices=('get', 'put'), help="The action to perform.")
    args = parser.parse_args()

    s3_client = boto3.client('s3')
    client_action = 'get_object' if args.action == 'get' else 'put_object'
    url = generate_presigned_url(
        s3_client, client_action, {'Bucket': args.accessPointArn, 'Key': args.key}, 1000)

    print("Using the Requests package to send a request to the URL.")
    response = None
    if args.action == 'get':
        response = requests.get(url)
    elif args.action == 'put':
        print("Putting data to the URL.")
        try:
            with open(args.key, 'r') as object_file:
                object_text = object_file.read()
            response = requests.put(url, data=object_text)
        except FileNotFoundError:
            print(f"Couldn't find {args.key}. For a PUT operation, the key must be the "
                  f"name of a file that exists on your computer.")

    if response is not None:
        print("Got response:")
        print(f"Status: {response.status_code}")
        print(response.text)

    print('-'*88)


if __name__ == '__main__':
    usage_demo()
```

------

# Amazon S3 on Outposts 与本地 Amazon EMR on Outposts
<a name="s3-outposts-emr"></a>

Amazon EMR 是一个托管式集群平台，可简化在 AWS 上运行大数据框架（如 Apache Hadoop 和 Apache Spark）以处理和分析海量数据的操作。通过使用这些框架和相关的开源项目，您可以处理用于分析目的的数据和业务情报工作负载。Amazon EMR 还可以协助您转换大量数据并将数据移入/移出其它 AWS 数据存储和数据库，并支持 Amazon S3 on Outposts。有关更多信息，请参阅《Amazon EMR 管理指南》**中的 [Amazon EMR on Outposts](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-outposts.html)。

对于 Amazon S3 on Outposts，Amazon EMR 在版本 7.0.0 中开始支持 Apache Hadoop S3A 连接器。早期版本的 Amazon EMR 不支持本地 S3 on Outposts，也不支持 EMR 文件系统（EMRFS）。

**受支持的应用程序**  
Amazon EMR 与 Amazon S3 on Outposts 结合使用可支持以下应用程序：
+ Hadoop
+ Spark
+ Hue
+ Hive
+ Sqoop
+ Pig
+ Hudi
+ Flink

有关更多信息，请参阅[《Amazon EMR 版本指南》](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-release-components.html)。

## 创建和配置 Amazon S3 on Outposts 桶
<a name="create-outposts-bucket"></a>

Amazon EMR 将 适用于 Java 的 AWS SDK 与 Amazon S3 on Outposts 结合使用来存储输入数据和输出数据。您的 Amazon EMR 日志文件存储在您选择的区域 Amazon S3 位置，而不是本地存储在 Outpost 上。有关更多信息，请参阅《Amazon EMR 管理指南》**中的 [Amazon EMR 日志](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-manage-view-web-log-files.html)。

为了符合 Amazon S3 和 DNS 的要求，S3 on Outposts 桶具有命名限制和局限性。有关更多信息，请参阅 [创建 S3 on Outposts 存储桶](S3OutpostsCreateBucket.md)。

在 Amazon EMR 版本 7.0.0 及更高版本中，您可以将 Amazon EMR 与 S3 on Outposts 和 S3A 文件系统结合使用。

**先决条件**  
**S3 on Outposts 权限** – 当您创建 Amazon EMR 实例配置文件时，您的角色必须包含 S3 on Outposts 的 AWS Identity and Access Management（IAM）命名空间。S3 on Outposts 具有自己的命名空间 `s3-outposts*`。有关使用此命名空间的示例策略，请参阅[使用 S3 on Outposts 设置 IAM](S3OutpostsIAM.md)。

**S3A 连接器** – 要将您的 EMR 集群配置为访问 Amazon S3 on Outposts 桶中的数据，您必须使用 Apache Hadoop S3A 连接器。要使用该连接器，请确保所有 S3 URI 都使用 `s3a` 方案。如果不是这样，您可以配置用于 EMR 集群的文件系统实现，以便 S3 URI 可以与 S3A 连接器结合使用。

要将文件系统实现配置为与 S3A 连接器结合使用，请为 EMR 集群使用 `fs.file_scheme.impl` 和 `fs.AbstractFileSystem.file_scheme.impl` 配置属性，其中 `file_scheme` 对应于您拥有的 S3 URI 类型。要使用以下示例，请将 *`user input placeholders`* 替换为您自己的信息。例如，要更改使用 `s3` 方案的 S3 URI 的文件系统实现，请指定以下集群配置属性：

```
1. [
2.   {
3. "Classification": "core-site",
4.     "Properties": {
5.     "fs.s3.impl": "org.apache.hadoop.fs.s3a.S3AFileSystem",
6.     "fs.AbstractFileSystem.s3.impl": "org.apache.hadoop.fs.s3a.S3A"
7.     }
8.   }
9. ]
```

要使用 S3A，请将 `fs.file_scheme.impl` 配置属性设置为 `org.apache.hadoop.fs.s3a.S3AFileSystem`，并将 `fs.AbstractFileSystem.file_scheme.impl` 属性设置为 `org.apache.hadoop.fs.s3a.S3A`。

例如，如果您要访问路径 `s3a://bucket/...`，请将 `fs.s3a.impl` 属性设置为 `org.apache.hadoop.fs.s3a.S3AFileSystem`，然后将 `fs.AbstractFileSystem.s3a.impl` 属性设置为 `org.apache.hadoop.fs.s3a.S3A`。

## 开始将 Amazon EMR 与 Amazon S3 on Outposts 结合使用
<a name="getting-started-outposts"></a>

以下主题介绍了如何开始将 Amazon EMR 与 Amazon S3 on Outposts 结合使用。

**Topics**
+ [创建权限策略](#create-permission-policy)
+ [创建和配置集群](#configure-cluster)
+ [配置概述](#configurations-overview)
+ [注意事项](#considerations)

### 创建权限策略
<a name="create-permission-policy"></a>

在创建使用 Amazon S3 on Outposts 的 EMR 集群之前，您必须创建一个 IAM policy 以附加到该集群的 Amazon EC2 实例配置文件。该策略必须具有访问 S3 on Outposts 接入点 Amazon 资源名称（ARN）的权限。有关为 S3 on Outposts 创建 IAM policy 的更多信息，请参阅[使用 S3 on Outposts 设置 IAM](S3OutpostsIAM.md)。

以下示例策略显示如何授予所需的权限。创建策略后，将策略附加到您用于创建 EMR 集群的实例配置文件角色，如 [创建和配置集群](#configure-cluster) 部分所述。要使用此示例，请将 *`user input placeholders`* 替换为您自己的信息。

```
 1. {
 2. "Version":"2012-10-17",		 	 	  
 3.   "Statement": [
 4.         {
 5.   "Effect": "Allow",
 6.             "Resource": "arn:aws:s3-outposts:us-west-2:111122223333:outpost/op-01ac5d28a6a232904/accesspoint/access-point-name,
 7.             "Action": [
 8.                 "s3-outposts:*"
 9.             ]
10.         }
11.     ]
12.     
13.  }
```

### 创建和配置集群
<a name="configure-cluster"></a>

要创建在 S3 on Outposts 中运行 Spark 的集群，请在控制台中完成以下步骤。

**创建在 S3 on Outposts 中运行 Spark 的集群**

1. 通过 [https://console.aws.amazon.com/elasticmapreduce/](https://console.aws.amazon.com/elasticmapreduce/) 打开 Amazon EMR 控制台。

1. 在左侧导航窗格中，选择**集群**。

1. 选择**创建集群**。

   

1. 对于 **Amazon EMR 版本**，请选择 **emr-7.0.0** 或更高版本。

1. 对于应用程序捆绑包，请选择 **Spark 交互式**。然后，选择要包含在集群中的任何其它受支持的应用程序。

1. 要启用 Amazon S3 on Outposts，请输入您的配置设置。

**示例配置设置**  
要使用以下示例配置设置，请将 `user input placeholders` 替换为您自己的信息。

   ```
    1. [
    2.  {
    3.    "Classification": "core-site",
    4.    "Properties": {
    5.      "fs.s3a.bucket.DOC-EXAMPLE-BUCKET.accesspoint.arn": "arn:aws:s3-outposts:us-west-2:111122223333:outpost/op-01ac5d28a6a232904/accesspoint/access-point-name"
    6.      "fs.s3a.committer.name": "magic", 
    7.      "fs.s3a.select.enabled": "false"
    8.     }
    9.   },
   10.   {
   11.     "Classification": "hadoop-env",
   12.     "Configurations": [
   13.       {
   14.         "Classification": "export",
   15.         "Properties": {
   16.           "JAVA_HOME": "/usr/lib/jvm/java-11-amazon-corretto.x86_64" 
   17.           }
   18.        }
   19.      ],
   20.      "Properties": {}
   21.    },
   22.    {
   23.      "Classification": "spark-env",
   24.      "Configurations": [
   25.        {
   26.          "Classification": "export",
   27.          "Properties": {
   28.            "JAVA_HOME": "/usr/lib/jvm/java-11-amazon-corretto.x86_64"
   29.          }
   30.        }
   31.       ],
   32.       "Properties": {}
   33.      },
   34.      {
   35.       "Classification": "spark-defaults",
   36.       "Properties": {
   37.         "spark.executorEnv.JAVA_HOME": "/usr/lib/jvm/java-11-amazon-corretto.x86_64",
   38.         "spark.sql.sources.fastS3PartitionDiscovery.enabled": "false"
   39.       }
   40.      }
   41.   ]
   ```

1. 在**联网**部分中，选择您的 AWS Outposts 机架上的虚拟私有云（VPC）和子网。有关 Amazon EMR on Outposts 的更多信息，请参阅《Amazon EMR 管理指南》**中的 [AWS Outposts 上的 EMR 集群](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-outposts.html)。

1. 在 **Amazon EMR 的 EC2 实例配置文件**部分，选择附加了[您之前创建的权限策略](#create-permission-policy)的 IAM 角色。

1. 配置剩余的集群设置，然后选择**创建集群**。

### 配置概述
<a name="configurations-overview"></a>

下表描述了 S3A 配置，以及在设置将 S3 on Outposts 与 Amazon EMR 结合使用的集群时要为这些配置的参数指定的值。


| 参数 | 默认值 | S3 on Outposts 的必需值 | 说明 | 
| --- | --- | --- | --- | 
|  `fs.s3a.aws.credentials.provider`  |  如果未指定，S3A 将在区域桶中查找具有 Outposts 桶名称的 S3。  |  S3 on Outposts 桶的接入点 ARN  |  Amazon S3 on Outposts 支持将纯 Virtual Private Cloud (VPC) 接入点作为访问 Outposts 存储桶的唯一方式。  | 
|  `fs.s3a.committer.name`  | file |  `magic`  |  Magic 提交程序是 S3 on Outposts 唯一支持的提交程序。  | 
|  `fs.s3a.select.enabled`  |  `TRUE`  |  `FALSE`  | Outposts 上不支持 S3 Select。 | 
|  `JAVA_HOME`  |  `/usr/lib/jvm/java-8`  |  `/usr/lib/jvm/java-11-amazon-corretto.x86_64`  |  S3A 上的 S3 on Outposts 需要 Java 版本 11。  | 

下表描述了 Spark 配置，以及在设置将 S3 on Outposts 与 Amazon EMR 结合使用的集群时要为这些配置的参数指定的值。


| 参数 | 默认值 | S3 on Outposts 的必需值 | 说明 | 
| --- | --- | --- | --- | 
|  `spark.sql.sources.fastS3PartitionDiscovery.enabled`  |  `TRUE`  |  `FALSE`  |  S3 on Outposts 不支持快速分区。  | 
|  `spark.executorEnv.JAVA_HOME`  |  `/usr/lib/jvm/java-8`  |  `/usr/lib/jvm/java-11-amazon-corretto.x86_64`  |  S3A 上的 S3 on Outposts 需要 Java 版本 11。  | 

### 注意事项
<a name="considerations"></a>

当您将 Amazon EMR 与 S3 on Outposts 桶集成时，请考虑以下几点：
+ Amazon EMR 版本 7.0.0 及更高版本支持 Amazon S3 on Outposts。
+ 将 S3 on Outposts 与 Amazon EMR 结合使用时需要 S3A 连接器。只有 S3A 具有与 S3 on Outposts 桶交互所需的功能。有关 S3A 连接器设置的信息，请参阅[先决条件](#s3a-outposts-prerequisites)。
+ Amazon S3 on Outposts 对于 Amazon EMR 仅支持采用 Amazon S3 托管式密钥的服务器端加密（SSE-S3）。有关更多信息，请参阅 [S3 on Outposts 中的数据加密](s3-outposts-data-encryption.md)。
+ Amazon S3 on Outposts 不支持使用 S3A FileOutputCommitter 进行写入。在 S3 on Outposts 桶上使用 S3A FileOutputCommitter 进行写入会导致以下错误：InvalidStorageClass：您指定的存储类无效。
+ Amazon EMR Serverless 或 Amazon EMR on EKS 不支持 Amazon S3 on Outposts。
+ Amazon EMR 日志存储在您选择的区域 Amazon S3 位置，而不是本地存储在 S3 on Outposts 桶中。

# 授权和身份验证缓存
<a name="s3-outposts-auth-cache"></a>

S3 on Outposts 可在 Outposts 机架上安全地在本地缓存身份验证和授权数据。该缓存会针对每个请求，删除到父 AWS 区域的往返行程。这能够消除网络往返带来的可变性。借助 S3 on Outposts 中的身份验证和授权缓存功能，您可以获得与 Outposts 和AWS 区域 之间的连接延迟无关的一致延迟。

当您发出 S3 on Outposts API 请求时，身份验证和授权数据会被安全地缓存。然后，缓存的数据可用于对后续 S3 对象 API 请求进行身份验证。在使用签名版本 4A（SigV4A）对请求进行签名时，S3 on Outposts 仅缓存身份验证和授权数据。缓存本地存储在 S3 on Outposts 服务中的 Outposts 上。当您发出 S3 API 请求时，它会异步刷新。缓存已加密，Outposts 上不会存储任何纯文本加密密钥。

当 Outpost 连接到 AWS 区域时，缓存的有效期最长为 10 分钟。当您发出 S3 on Outposts API 请求时，它会异步刷新，以确保使用最新策略。如果 Outpost 与 AWS 区域断开连接，则缓存的有效期最长为 12 小时。

## 配置授权和身份验证缓存
<a name="config-auth-cache"></a>

S3 on Outposts 会针对使用 Sigv4a 算法进行签名的请求，自动缓存身份验证和授权数据。有关更多信息，请参阅《AWS Identity and Access Management 用户指南》**中的[对 AWS API 请求进行签名](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html)。在最新版本的 AWS SDK 中提供了 SigV4A 算法。您可以通过依赖 [AWS 公共运行时（CRT）库](https://docs.aws.amazon.com/sdkref/latest/guide/common-runtime.html)来获取它。

您需要使用最新版本的 AWS SDK 并安装最新版本的 CRT。例如，您可以通过运行 `pip install awscrt` 使用 Boto3 来获取最新版本的 CRT。

S3 on Outposts 不会针对使用 SigV4 算法进行签名的请求，缓存身份验证和授权数据。

## 验证 SigV4A 签名
<a name="validate-SigV4A"></a>

您可以使用 AWS CloudTrail 来验证是否已使用 SigV4A 对请求进行了签名。有关为 S3 on Outposts 设置 CloudTrail 的更多信息，请参阅[使用 AWS CloudTrail 日志监控 S3 on Outposts](S3OutpostsCloudtrail.md)。

配置 CloudTrail 后，您可以在 CloudTrail 日志的 `SignatureVersion` 字段中验证是否已对请求进行了签名。使用 SigV4A 进行了签名的请求的 `SignatureVersion` 将设置为 `AWS4-ECDSA-P256-SHA256`。使用 SigV4 进行了签名的请求的 `SignatureVersion` 将设置为 `AWS4-HMAC-SHA256`。