ablog

不器用で落着きのない技術者のメモ

EMRFS で KMS のカスタマー管理 CMK で暗号化する

EMR で KMS のカスタマー管理CMKを利用するには、S3 バケットのデフォルト暗号化で CMK を指定し、S3 と KMS に対する必要な権限を持つロールを EMR にアタッチすればよい。
また、S3 のバケットポリシーで特定の CMK 以外での PUT を禁止すると、「CMK 指定なし」と「許可した CMK 指定する」とアップロードできるが、「許可した CMK 以外を指定する」と失敗する。

検証結果

  • ファイルを作成する。
$ perl -le 'print for 1..10000' > number10000.txt
  • AWS CLIでCMK指定なしでのアップロードは成功する
$ aws s3 cp number10000.txt s3://az-emr-kms-test/
upload: ./number10000.txt to s3://az-emr-kms-test/number10000.txt
  • AWS CLIバケットポリシーで許可されたCMKを指定してのアップロードは成功する。
$ aws s3 cp number10000.txt s3://az-emr-kms-test/number10000.txt --sse aws:kms --sse-kms-key-id 'arn:aws:kms:ap-northeast-1:123456789012:key/c3******-168d-4***-9***-9***********'
upload: ./number10000.txt to s3://az-emr-kms-test/number10000.txt
  • AWS CLIで違うCMKを指定してのアップロードは失敗する。
$ aws s3 cp number10000.txt s3://az-emr-kms-test/number10000.txt --sse aws:kms --sse-kms-key-id 'arn:aws:kms:ap-northeast-1:123456789012:key/2a******-8b8f-4***-9***-0***********'
upload failed: ./number10000.txt to s3://az-emr-kms-test/number10000.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
  • PySpark on EMR で、EMRFS で S3 に書ける(CMK指定なし)。
$ pyspark
Python 2.7.15 (default, Nov 28 2018, 22:38:08)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
19/04/01 07:54:31 WARN Utils: Service 'SparkUI' could not bind on port 4040. Attempting port 4041.
19/04/01 07:54:31 WARN Utils: Service 'SparkUI' could not bind on port 4041. Attempting port 4042.
19/04/01 07:54:31 WARN Utils: Service 'SparkUI' could not bind on port 4042. Attempting port 4043.
19/04/01 07:54:34 WARN Client: Neither spark.yarn.jars nor spark.yarn.archive is set, falling back to uploading libraries under SPARK_HOME.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 2.4.0
      /_/

Using Python version 2.7.15 (default, Nov 28 2018 22:38:08)
SparkSession available as 'spark'.
>>> df = spark.read.csv("s3://az-emr-kms-test/number10000.txt")
>>> df.head(10)
[Row(_c0=u'1'), Row(_c0=u'2'), Row(_c0=u'3'), Row(_c0=u'4'), Row(_c0=u'5'), Row(_c0=u'6'), Row(_c0=u'7'), Row(_c0=u'8'), Row(_c0=u'9'), Row(_c0=u'10')]
>>> df.write.mode('overwrite').parquet("s3://az-emr-kms-test/number10000.parquet")
>>> exit
  • Sparkから書いたファイルを確認する。
$ aws s3 ls --recursive s3://az-emr-kms-test/
2019-04-01 07:34:49      48894 num1
2019-04-01 05:39:51  888888898 number.txt
2019-04-01 07:55:47          0 number10000.parquet/_SUCCESS
2019-04-01 07:55:47      43888 number10000.parquet/part-00000-4c91ddce-b347-4239-85ec-0eba160c6c15-c000.snappy.parquet
2019-04-01 07:53:21      48894 number10000.txt

準備

  • EMRクラスタを作成する。
  • IAMポリシー「KMSUserPolicy1」を作成して、ロール「EMR_EC2_DefaultRole」にアタッチする
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey",
                "kms:ListAliases"
            ],
            "Resource": "*"
        }
    ]
}
  • S3バケットポリシーで指定したCMK以外での暗号化を禁止する。
{
    "Version": "2012-10-17",
    "Id": "S3KeyPolicy",
    "Statement": [
        {
            "Sid": "Force KMS Key",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::az-emr-kms-test/*",
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:ap-northeast-1:123456789012:key/c3******-168d-4***-9***-9***********"
                }
            }
        }
    ]
}