

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

# 使用 EMRFS 属性指定 Amazon S3 加密
<a name="emr-emrfs-encryption"></a>

**重要**  
从 Amazon EMR 发行版 4.8.0 开始，您可以使用安全配置以更轻松的方式应用安全设置，并获得更多选项。建议您使用安全配置。有关更多信息，请参阅[配置数据加密](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-create-security-configuration.html#emr-security-configuration-encryption)。此部分中所述的控制台说明适用于 4.8.0 之前的版本。如果您使用在 AWS CLI 集群配置和后续版本的安全配置中配置 Amazon S3 加密，则安全配置将覆盖集群配置。

创建集群时，您可以使用控制台或通过或 EMR SDK 使用`emrfs-site`分类属性为 Amazon S3 中的 EMRFS 数据指定服务器端加密 (SSE) 或客户端加密 (CSE)。 AWS CLI Amazon S3 SSE 和 CSE 是互斥的；您可以任选其一，但不能同时选择两者。

有关 AWS CLI 说明，请参阅下面与您的加密类型对应的部分。

**要指定 EMRFS 加密选项，请使用 AWS 管理控制台**

1. 导航到 Amazon EMR 新控制台，然后从侧面导航栏中选择**切换到旧控制台**。有关切换到旧控制台后预期情况的更多信息，请参阅 [Using the old console](https://docs.aws.amazon.com/emr/latest/ManagementGuide/whats-new-in-console.html#console-opt-in)。

1. 依次选择 **Create cluster (创建集群)**、**Go to advanced options (转到高级选项)**。

1. 选择 **Release (版本)** 4.7.2 或更早版本。

1. 为 **Software and Steps (软件和步骤)** 选择适用于您的应用程序的其它选项，然后选择 **Next (下一步)**。

1. 在 **Hardware (硬件)** 和 **General Cluster Settings (常规集群设置)** 窗格中选择适用于您的应用程序的设置。

1. 在 **Security (安全)** 窗格上的 **Authentication and encryption (身份验证和加密)** 下，选择要使用的 **S3 Encryption (with EMRFS)** 选项。
**注意**  
在使用 Amazon EMR 发行版 4.4 或更早版本时，**S3 server-side encryption with KMS Key Management (利用 KMS Key Management 进行 S3 服务器端加密)**（SSE-KMS）不可用。
   + 如果您选择一个使用 **AWS Key Management** 的选项，请选择一个 **AWS KMS Key ID**。有关更多信息，请参阅[用 AWS KMS keys 于 EMRFS 加密](#emr-emrfs-awskms)。
   + 如果您选择 **S3 client-side encryption with custom materials provider (利用自定义材料提供程序进行 S3 客户端加密)**，请提供 **Class name (类名称)** 和 **JAR location (AR 位置)**。有关更多信息，请参阅[Amazon S3 客户端加密](emr-emrfs-encryption-cse.md)。

1. 选择适用于您的应用程序的其它选项，然后选择 **Create Cluster (创建集群)**。

## 用 AWS KMS keys 于 EMRFS 加密
<a name="emr-emrfs-awskms"></a>

 AWS KMS 加密密钥必须与您的 Amazon EMR 集群实例和与 EMRFS 一起使用的 Amazon S3 存储桶所在的区域创建。如果指定的密钥没有位于用于配置集群的账户中，则必须使用它的 ARN 指定密钥。

Amazon EC2 实例配置文件的角色必须具有使用您指定的 KMS 密钥的权限。Amazon EMR 中实例配置文件的默认角色是 `EMR_EC2_DefaultRole`。如果您对实例配置文件使用不同的角色，或者对 Amazon S3 的 EMRFS 请求使用 IAM 角色，请确保根据需要将每个角色添加为密钥用户。这会为该角色授予使用该 KMS 密钥的权限。有关更多信息，请参阅*《AWS Key Management Service 开发人员指南》*和[为向 Amazon S3 发出的 EMRFS 请求配置 IAM 角色](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-emrfs-iam-roles.html)中的[使用密钥策略](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-users)。

您可以使用将您的实例配置文件或 EC2 实例配置文件 AWS 管理控制台 添加到指定 KMS 密钥的密钥用户列表中，也可以使用 AWS CLI 或 AWS 软件开发工具包来附加相应的密钥策略。

请注意 Amazon EMR 仅支持[对称 KMS 密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#symmetric-cmks)。不能使用[非对称 KMS 密钥](https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html#asymmetric-cmks)加密 Amazon EMR 集群中的静态数据。要获取确定 KMS 密钥是对称还是非对称的帮助，请参阅[识别对称密钥和非对称密钥](https://docs.aws.amazon.com/kms/latest/developerguide/find-symm-asymm.html)。

以下步骤介绍了如何使用 AWS 管理控制台将 Amazon EMR 实例配置文件 `EMR_EC2_DefaultRole` 作为*密钥用户*添加。它假定您已创建一个 KMS 密钥。要创建新的 KMS 密钥，请参阅*《AWS Key Management Service 开发人员指南》*中的[创建密钥](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html)。

**将 Amazon EMR 的 EC2 实例配置文件添加到加密密钥用户列表中**

1. 登录 AWS 管理控制台 并在 [https://console.aws.amazon.com/km](https://console.aws.amazon.com/kms) s 处打开 AWS Key Management Service (AWS KMS) 控制台。

1. 要更改 AWS 区域，请使用页面右上角的区域选择器。

1. 选择要修改的 KMS 密钥的别名。

1. 在密钥详细信息页面的 **Key Users (密钥用户)** 下，选择 **Add (添加)**。

1. 在 **Add key users (添加密钥用户)** 对话框中，选择适当的角色。默认角色的名称为 `EMR_EC2_DefaultRole`。

1. 选择**添加**。

## Amazon S3 服务器端加密
<a name="emr-emrfs-encryption-sse"></a>

默认情况下，所有 Amazon S3 存储桶都配置了加密，所有上传到 S3 存储桶的新对象都会自动静态加密，Amazon S3 在向磁盘写入数据时会在对象级别对数据进行加密，并在访问数据时对其进行解密。有关 SSE 的更多信息，请参阅*《Amazon Simple Storage Service 用户指南》*中的[使用服务器端加密保护数据](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html)。

在 Amazon EMR 中指定 SSE 时，可以在两个不同的密钥管理系统之间进行选择：
+ **SSE-S3**：Amazon S3 为您管理密钥。
+ **SSE-KMS** — 您可以使用 AWS KMS key 来设置适用于 Amazon EMR 的策略。有关 Amazon EMR 密钥要求的更多信息，请参阅[AWS KMS keys 用于](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-encryption-enable.html#emr-awskms-keys)加密。

客户提供密钥的 SSE（SSE-C）不能用于 Amazon EMR。

**要创建启用了 SSE-S3 的集群，请使用 AWS CLI**
+ 键入以下命令：

  ```
  aws emr create-cluster --release-label emr-4.7.2 or earlier \
  --instance-count 3 --instance-type m5.xlarge --emrfs Encryption=ServerSide
  ```

你也可以通过设置 fs.s3 来启用 SSE-S3。 enableServerSide属性中的`emrfs-site`加密属性为 true。请参阅下面的 SSE-KMS 示例并忽略密钥 ID 的属性。

**要创建启用了 SSE-KMS 的集群，请使用 AWS CLI**
**注意**  
SSE-KMS 仅在 Amazon EMR 发行版 4.5.0 及更高版本中可用。
+ 键入以下 AWS CLI 命令创建带有 SSE-KMS 的集群，其中*keyID*是 AWS KMS key，例如：*a4567b8-9900-12ab-1234-123a45678901*

  ```
  aws emr create-cluster --release-label emr-4.7.2 or earlier --instance-count 3 \
  --instance-type m5.xlarge --use-default-roles \
  --emrfs Encryption=ServerSide,Args=[fs.s3.serverSideEncryption.kms.keyId=keyId]
  ```

  **或者**

  使用`emrfs-site`分类键入以下 AWS CLI 命令，并提供包含内容的配置 JSON 文件，如下例`myConfig.json`所示：

  ```
  aws emr create-cluster --release-label emr-4.7.2 or earlier --instance-count 3 --instance-type m5.xlarge --applications Name=Hadoop --configurations file://myConfig.json --use-default-roles
  ```

  **myConfig.json** 的示例内容：

  ```
  [
    {
      "Classification":"emrfs-site",
      "Properties": {
         "fs.s3.enableServerSideEncryption": "true",
         "fs.s3.serverSideEncryption.kms.keyId":"a4567b8-9900-12ab-1234-123a45678901"
      }
    }
  ]
  ```

### SSE-S3 和 SSE-KMS 的配置属性
<a name="emr-emrfs-encryption-site-sse-properties"></a>

可使用 `emrfs-site` 配置分类来配置这些属性。SSE-KMS 仅在 Amazon EMR 发行版 4.5.0 及更高版本中可用。


| 属性  | 默认 值 | 说明  | 
| --- | --- | --- | 
| fs.s3.enableServerSideEncryption | false |  设置为 **true** 时，使用服务器端加密对 Amazon S3 中存储的对象进行加密。如果未指定密钥，则使用 SSE-S3。  | 
| fs.s3.serverSideEncryption.kms.keyId | n/a |  指定密 AWS KMS 钥 ID 或 ARN。如果未指定密钥，则使用 SSE-KMS。  | 

# 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/)。  | 