

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

# Amazon S3 客户端加密
<a name="emr-emrfs-encryption-cse"></a>

对于 Amazon S3 客户端加密，Amazon S3 加密和解密过程在您的 EMR 集群上的 EMRFS 客户端中进行。在对象上载到 Amazon S3 之前对其进行加密，并在下载后对其进行解密。您指定的提供程序会提供客户端使用的加密密钥。客户端可以使用 AWS KMS 提供的密钥（CSE-KMS）或提供客户端根密钥（CSE-C）的自定义 Java 类。CSE-KMS 和 CSE-C 之间的加密细节略有不同，具体取决于指定的提供程序以及正在解密或加密对象的元数据。有关这些区别的更多信息，请参阅*《Amazon Simple Storage Service 用户指南》*中的[使用客户端加密保护数据](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingClientSideEncryption.html)。

**注意**  
Amazon S3 CSE 仅确保与 Amazon S3 交换的 EMRFS 数据已加密；不确保集群实例卷上的所有数据都已加密。此外，由于 Hue 不使用 EMRFS，因此 Hue S3 文件浏览器写入 Amazon S3 的对象没有加密。

**要在 Amazon S3 中为 EMRFS 数据指定 CSE-KMS，请使用 AWS CLI**
+ 键入以下命令并替换为要*MyKMSKeyID*使用的 KMS 密钥的密钥 ID 或 ARN：

  ```
  aws emr create-cluster --release-label emr-4.7.2 or earlier
  --emrfs Encryption=ClientSide,ProviderType=KMS,KMSKeyId=MyKMSKeyId
  ```

## 创建自定义密钥提供程序
<a name="emr-emrfs-create-cse-key"></a>

根据您在创建自定义密钥提供程序时使用的加密类型，应用程序还必须实现不同的 EncryptionMaterialsProvider 接口。这两个接口在适用于 Java 的 AWS SDK 版本 1.11.0 及更高版本中都可用。
+ 要实现亚马逊 S3 加密，请使用 [com.amazonaws.services.s3.model。 EncryptionMaterialsProvider 接口](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/EncryptionMaterialsProvider.html)。
+ 要实现本地磁盘加密，请使用 [com.amazonaws.services.elasticmapreduce.spi.security。 EncryptionMaterialsProvider 接口](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/elasticmapreduce/spi/security/EncryptionMaterialsProvider.html)。

您可以使用任何策略为实施提供加密材料。例如，您可以选择提供静态加密材料，也可以选择与更复杂的密钥管理系统集成。

如果您使用的是 Amazon S3 加密，则必须**AES/GCM/NoPadding**对自定义加密材料使用加密算法。

如果您使用的是本地磁盘加密，则用于自定义加密材料的加密算法因 EMR 发行版而异。对于亚马逊 EMR 7.0.0 及更低版本，您必须使用。**AES/GCM/NoPadding**对于 Amazon EMR 7.1.0 及更高版本，您必须使用 **AES**。

该 EncryptionMaterialsProvider 类通过加密上下文获取加密材料。Amazon EMR 在运行时填充加密上下文信息，以帮助调用者确定要返回的正确加密材料。

**Example 示例：通过 EMRFS 使用自定义密钥提供程序对 Amazon S3 进行加密**  
当 Amazon EMR 从EncryptionMaterialsProvider 类中提取加密材料以执行加密时，EMRFS 可以选择在材料描述参数中填充两个字段：对象的 Amazon S3 URI 和 JobFlowId 集群的 URI，该类可以选择性地使用这两个字段来有选择地返回加密材料。EncryptionMaterialsProvider   
例如，提供程序可能会为不同的 Amazon S3 URI 前缀返回不同的密钥。它是最终与 Amazon S3 对象一起存储的返回加密材料的描述，而不是 EMRFS 生成并传递给提供程序的 materialsDescription 值。解密 Amazon S3 对象时，加密材料描述会传递给该EncryptionMaterialsProvider 类，这样它就可以有选择地返回匹配的密钥来解密该对象。  
下面提供了一个 EncryptionMaterialsProvider 参考实现。另一个自定义提供程序可从中获得 GitHub。[EMRFSRSAEncryptionMaterialsProvider](https://github.com/awslabs/emr-sample-apps/tree/master/emrfs-plugins/EMRFSRSAEncryptionMaterialsProvider)  

```
import com.amazonaws.services.s3.model.EncryptionMaterials;
import com.amazonaws.services.s3.model.EncryptionMaterialsProvider;
import com.amazonaws.services.s3.model.KMSEncryptionMaterials;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.conf.Configuration;

import java.util.Map;

/**
 * Provides KMSEncryptionMaterials according to Configuration
 */
public class MyEncryptionMaterialsProviders implements EncryptionMaterialsProvider, Configurable{
  private Configuration conf;
  private String kmsKeyId;
  private EncryptionMaterials encryptionMaterials;

  private void init() {
    this.kmsKeyId = conf.get("my.kms.key.id");
    this.encryptionMaterials = new KMSEncryptionMaterials(kmsKeyId);
  }

  @Override
  public void setConf(Configuration conf) {
    this.conf = conf;
    init();
  }

  @Override
  public Configuration getConf() {
    return this.conf;
  }

  @Override
  public void refresh() {

  }

  @Override
  public EncryptionMaterials getEncryptionMaterials(Map<String, String> materialsDescription) {
    return this.encryptionMaterials;
  }

  @Override
  public EncryptionMaterials getEncryptionMaterials() {
    return this.encryptionMaterials;
  }
}
```

## 使用指定定制材料提供商 AWS CLI
<a name="emr-emrfs-encryption-cse-custom-cli"></a>

要使用 AWS CLI，请将 `Encryption`、`ProviderType`、`CustomProviderClass` 和 `CustomProviderLocation` 参数传递给 `emrfs` 选项。

```
aws emr create-cluster --instance-type m5.xlarge --release-label emr-4.7.2 or earlier --emrfs Encryption=ClientSide,ProviderType=Custom,CustomProviderLocation=s3://amzn-s3-demo-bucket/myfolder/provider.jar,CustomProviderClass=classname
```

将 `Encryption` 设置为 `ClientSide` 会启用客户端加密，`CustomProviderClass` 是您的 `EncryptionMaterialsProvider` 对象的名称，而 `CustomProviderLocation` 是本地或 Amazon S3 位置，Amazon EMR 从此位置将 `CustomProviderClass` 复制到集群中的每个节点并放置在类路径中。

## 使用 SDK 指定自定义材料提供程序
<a name="emr-emrfs-encryption-cse-custom-sdk"></a>

要使用 SDK，您可以将属性 `fs.s3.cse.encryptionMaterialsProvider.uri` 设置为将存储在 Amazon S3 中的自定义 `EncryptionMaterialsProvider` 类下载到集群中的每个节点。您在 `emrfs-site.xml` 文件中配置此设置，同时启用 CSE 并提供自定义提供程序的正确位置。

例如，在 适用于 Java 的 AWS SDK 使用中 RunJobFlowRequest，您的代码可能如下所示：

```
<snip>
		Map<String,String> emrfsProperties = new HashMap<String,String>();
	    	emrfsProperties.put("fs.s3.cse.encryptionMaterialsProvider.uri","s3://amzn-s3-demo-bucket/MyCustomEncryptionMaterialsProvider.jar");
	    	emrfsProperties.put("fs.s3.cse.enabled","true");
	    	emrfsProperties.put("fs.s3.consistent","true");
		    emrfsProperties.put("fs.s3.cse.encryptionMaterialsProvider","full.class.name.of.EncryptionMaterialsProvider");

		Configuration myEmrfsConfig = new Configuration()
	    	.withClassification("emrfs-site")
	    	.withProperties(emrfsProperties);

		RunJobFlowRequest request = new RunJobFlowRequest()
			.withName("Custom EncryptionMaterialsProvider")
			.withReleaseLabel("emr-7.12.0")
			.withApplications(myApp)
			.withConfigurations(myEmrfsConfig)
			.withServiceRole("EMR_DefaultRole_V2")
			.withJobFlowRole("EMR_EC2_DefaultRole")
			.withLogUri("s3://myLogUri/")
			.withInstances(new JobFlowInstancesConfig()
				.withEc2KeyName("myEc2Key")
				.withInstanceCount(2)
				.withKeepJobFlowAliveWhenNoSteps(true)
				.withMasterInstanceType("m5.xlarge")
				.withSlaveInstanceType("m5.xlarge")
			);						
					
		RunJobFlowResult result = emr.runJobFlow(request);
</snip>
```

## 带参数的自定义 EncryptionMaterialsProvider
<a name="emr-emrfs-encryption-custommaterials"></a>

您可能需要将参数直接传递给提供程序。要执行此操作，您可以将 `emrfs-site` 配置分类与定义为属性的自定义参数结合使用。下面显示了一个示例配置，该示例配置将另存为 `myConfig.json` 文件：

```
[
    {
      "Classification": "emrfs-site",
      "Properties": {
        "myProvider.arg1":"value1",
	    "myProvider.arg2":"value2"
      }
    }
 ]
```

使用中的`create-cluster`命令 AWS CLI，您可以使用`--configurations`选项来指定文件，如下所示：

```
aws emr create-cluster --release-label emr-7.12.0 --instance-type m5.xlarge --instance-count 2 --configurations file://myConfig.json --emrfs Encryption=ClientSide,CustomProviderLocation=s3://amzn-s3-demo-bucket/myfolder/myprovider.jar,CustomProviderClass=classname
```

## 配置 EMRFS S3EC V2 支持
<a name="emr-emrfs-encryption-cse-s3v2"></a>

S3 Java SDK 版本（1.11.837 及更高版本）支持带有各种安全增强功能的加密客户端版本 2（S3EC V2）。有关更多信息，请参阅 S3 博客文章 [Updates to the Amazon S3 encryption client](https://aws.amazon.com/blogs/developer/updates-to-the-amazon-s3-encryption-client/)。另请参阅《 适用于 Java 的 AWS SDK 开发人员指南》[中的 Amazon S3 加密客户端迁移](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/s3-encryption-migration.html)。

为保持向后兼容性，加密客户端 V1 在 SDK 中仍可用。默认情况下，启用 CSE 后，EMRFS 将使用 S3EC V1 加密和解密 S3 对象。

在发行版早于 emr-5.31.0（emr-5.30.1 及更早版本、emr-6.1.0 及更早版本）的 EMR 集群上，使用 S3EC V2 加密的 S3 对象无法通过 EMRFS 来解密。

**Example 将 EMRFS 配置为使用 S3EC V2**  
要将 EMRFS 配置为使用 S3EC V2，请添加以下配置：  

```
{
  "Classification": "emrfs-site",
  "Properties": {
    "fs.s3.cse.encryptionV2.enabled": "true"
  }
}
```

## Amazon S3 客户端加密的 `emrfs-site.xml` 属性
<a name="emr-emrfs-cse-config"></a>


| 属性  | 默认 值 | 说明  | 
| --- | --- | --- | 
| fs.s3.cse.enabled | false |  设置为 **true** 时，使用客户端加密对 Amazon S3 中存储的 EMRFS 对象进行加密。  | 
| fs.s3.cse.encryptionV2.enabled | false |  设置为 `true` 时，EMRFS 使用 S3 加密客户端版本 2 来加密和解密 S3 上的对象。在 EMR 版本 5.31.0 及更高版本中提供。  | 
| fs.s3.cse.encryptionMaterialsProvider.uri | N/A | 在使用自定义加密材料时适用。带 EncryptionMaterialsProvider 的 JAR 所在的 Amazon S3 URI。如果您提供此 URI，Amazon EMR 将此 JAR 自动下载到集群中的所有节点。 | 
| fs.s3.cse.encryptionMaterialsProvider | N/A |  用于客户端加密的 `EncryptionMaterialsProvider` 类路径。在使用 CSE-KMS 时，请指定 `com.amazon.ws.emr.hadoop.fs.cse.KMSEncryptionMaterialsProvider`。  | 
| fs.s3.cse.materialsDescription.enabled | false |  如果设置为`true`，则使用加密对象的 Amazon S3 URI 填充加密对象的 MaterialsDescription 和。 JobFlowId在使用自定义加密材料时设置为 `true`。  | 
| fs.s3.cse.kms.keyId | N/A |  在使用 CSE-KMS 时适用。用于加密的 KMS 密钥的值 KeyId、ARN 或别名。  | 
| fs.s3.cse.cryptoStorageMode | ObjectMetadata  |  Amazon S3 存储模式。默认情况下，加密信息的描述存储在对象元数据中。也可以将描述存储在指令文件中。有效值为 ObjectMetadata 和InstructionFile。有关更多信息，请参阅使用[适用于 Java 的 AWS SDK 和 Amazon S3 进行客户端数据加密](https://aws.amazon.com/articles/client-side-data-encryption-with-the-aws-sdk-for-java-and-amazon-s3/)。  | 