Amazon Web Services ブログ

Amazon EMR を保護するベストプラクティス

どの業界でも、組織が機能する上で中心となるのは、データです。お客様とデータ戦略について話し合うとき、データの取り込み、保存、処理、分析、配布、最終的なデータを安全性について語ります。

Amazon EMR は、膨大な量のデータを処理するために使用するマネージド型 Hadoop フレームワークです。お客様が Amazon EMR を選ぶ理由の 1 つは、そのセキュリティ機能です。例えば、金融サービスなどの規制された業界や医療分野の FINRA のようなお客様は、データ戦略の一環として Amazon EMR を選びます。ペイメントカード業界データセキュリティ基準(PCI)や 医療保険の携行と責任に関する法律(HIPAA)など、エンティティからの厳しい規制要件に準拠するためのものです。

この記事では、Amazon EMR セキュリティの原則についていくつか説明します。また、Amazon EMR で使用できる機能についての説明は、ビジネスのセキュリティとコンプライアンスの目標を達成するのに役立ちます。使用している共通のセキュリティベストプラクティスについて取り上げます。また、開始するためのサンプル構成もいくつか示しています。詳しい情報については、「EMR管理ガイド」「セキュリティ」を参照してください。

暗号化、暗号化、暗号化

当社の CTO である Werner Vogelsは、「誰も見ていないかのように踊り、みんなと同じように暗号化しなさい。」というのが持論です。 暗号化を使用して、休止中および移動中のデータを適切に保護することは、Well-Architected のセキュリティ柱において主要なコンポーネントです。Amazon EMR のセキュリティ構成(「EMR ドキュメント」を参照)により、データを簡単に暗号化できます。セキュリティ構成は、暗号化や他のセキュリティ構成用のテンプレートのようなもので、起動すると、どのクラスタにも適用できます。

休止中の暗号化

EMR クラスターでは、休止中のデータを暗号化する複数のオプションがあります。EMR は、デフォルトで EMR ファイルシステム(EMRFS)を使用して、Amazon S3 とデータの読み書きを行います。Amazon S3 でデータを暗号化するには、次のオプションのいずれかを指定します。

  • SSE-S3:Amazon S3 が暗号キーを管理します
  • SSE-KMS:AWS Key Management Service(AWS KMS)のカスタマーマスターキー(CMK)を使用して、Amazon S3 のデータサーバー側を暗号化します。必ず、Amazon EMR によるアクセスを許可するポリシーを使用してください。
  • CSE-KMS/CSE-C:Amazon S3 の暗号化と復号化は、Amazon EMR クラスターのクライアント側で行われます。AWS KMS(CSE-KMS)が提供するキーを使用するか、マスターキー(CSE-C)を提供するカスタム Java クラスを使用できます。

Amazon EMR では、Amazon S3 の暗号化タイプを簡単に設定できます。リストから選択するだけで十分です。

選択するオプションは、特定のワークロード要件に応じて異なります。SSE-S3 では、キーの管理が Amazon によって完全に処理されます。これは最も簡単なオプションです。SSE-KMS または CSE-KMS を使用すると、暗号化キーをより完全に制御でき、暗号化に独自のキーマテリアルを提供できます。暗号化はバケット内のオブジェクトに適用されます。クラスターで実行されているアプリケーションを変更する、または暗号化を認識する必要はありません。

さらに制御するために、CSE-C でカスタムキープロバイダを使用できます。詳しくは、「EMR ドキュメント」の「Amazon S3 クライアント側暗号化」を参照してください。

ローカルディスクの暗号化には、お互いを補完する 2 つの方法があります。具体的な暗号化ターゲットで説明してみます。

  • ローカルディスク暗号化を使用してルートボリュームを暗号化するには、Amazon EMR 用のカスタム Amazon Machine Image (AMI) を作成し、Amazon EBS ボリューム暗号化を指定します。この記事で、後ほどカスタム AMI の詳細を取り上げます。
  • ローカルディスクの暗号化を使用してストレージボリュームを暗号化するには、Amazon EMR セキュリティ構成(「EMR ドキュメント」を参照)を使用します。セキュリティ構成では、オープンソースの HDFS 暗号化と LUKS 暗号化を組み合わせて使用します。この機能を使用するには、AWS KMS キーの Amazon リソースネーム (ARN) を指定するか、暗号化アーティファクトをカスタム Java クラスに提供します。

EMR と S3 で KMS を使用する方法について詳しくは、「EMR ドキュメント」で 「Amazon EMR で AWS KMS の使用方法」を参照してください。

暗号化戦略の一環として AWS KMS を使用している場合、ユースケースでサポートされているリクエスト率については、「EMR ドキュメント」の「AWS KMS の制限」を参照してください。

移動中の暗号化

Amazon EMR のセキュリティ構成では、Transport Layer Security (TLS)(「EMR ドキュメント」を参照)を使用して、移動中のデータを暗号化する方法を選択できます。次のいずれかを実行できます。

  • PEM 証明書を手動で作成し、ファイルに圧縮し、Amazon S3 から参照します。
  • Java で証明書カスタムプロバイダを実行し、JAR への S3 パスを指定します。

さまざまなビッグデータテクノロジでこれらの証明書を使用する方法については、「EMR を使用した移動中のデータの暗号化」を確認してください。

EMR マネジメントコンソールでセキュリティ構成を作成するときに表示される内容は次のとおりです。

コードでの暗号化の表現

また、AWS CLI、Boto3、AWS CloudFormation を使用して暗号化を指定することもできます。ここでは、S3 暗号化に SSE-S3、ローカルディスク暗号化に KMS を使用する Boto3 の例を示します。

import boto3
client = boto3.client('emr')
response = client.create_security_configuration(
    Name='MySecurityConfig'
    SecurityConfiguration='''{
        "EncryptionConfiguration": {
            "EnableInTransitEncryption" : true,
            "EnableAtRestEncryption" : true,
            "AtRestEncryptionConfiguration" : {
                "S3EncryptionConfiguration" : {
                    "EncryptionMode" : "SSE-S3"
                },
                "LocalDiskEncryptionConfiguration" : {
                    "EncryptionKeyProviderType" : "AwsKms",
                    "AwsKmsKey" : "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
                }
            }
            "InTransitEncryptionConfiguration" : {
                "TLSCertificateConfiguration" : {
                    "CertificateProviderType" : "PEM",
                    "S3Object" : "s3://MyConfigStore/artifacts/MyCerts.zip"
                }
            }
        }
    }'''
)

そして AWS CloudFormation と同様のスニペットです。

Resources:
    MySecurityConfig:
        Type: AWS::EMR::SecurityConfiguration
        Properties:
            Name: MySecurityConfig
            SecurityConfiguration:
                EncryptionConfiguration:
                    EnableInTransitEncryption: true
                    EnableAtRestEncryption: true
                    AtRestEncryptionConfiguration:
                        S3EncryptionConfiguration:
                            EncryptionMode: SSE-S3
                        LocalDiskEncryptionConfiguration:
                            EncryptionKeyProviderType: AwsKms
                            AwsKmsKey: arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012
                    InTransitEncryptionConfiguration:
                        TLSCertificateConfiguration:
                            CertificateProviderType: PEM
                            S3Object: arn:aws:s3:::MyConfigStore/artifacts/MyCerts.zip

Amazon EMR でのセキュリティ構成については、AWS ビッグデータブログの記事「セキュアな Amazon EMR の暗号化」を参照してください。

認証と承認

AuthN と AuthZ とも呼ばれる認証と承認は、データへのアクセスを制御するときに考える必要がある 2 つの重要なコンポーネントです。 認証はエンティティの検証で、承認はエンティティが要求しているデータまたはリソースに実際にアクセスできるかどうかを確認することです。つまり、認証は、ユーザーが本当にユーザー自身が言う通りの人なのかを確認するものです。承認は、ユーザーが実際に求めているものにアクセスできるかどうかを確認します。Alice が実際に Alice だと認証された場合でも、Alice が Bob の銀行口座を確認するための認証、またはアクセス権を持っているとは限りません。

Amazon EMR での認証

マサチューセッツ工科大学(MIT)によって作成されたネットワーク認証プロトコルである Kerberos は、強力な認証を提供するためにシークレットキー暗号作成法を使用します。暗号化されていない、公開された形式のネットワーク経由で送信されるパスワードやその他の資格情報など、機密情報を入手することを避ける場合に役立ちます。

Kerberos を使用すると、一連のサービス(別名、領域)と認証が必要なユーザー(別名、プリンシパル)を維持できます。原則を認証する方法を提供します。また、Kerberos 設定を他の領域と統合することもできます。例えば、Microsoft Active Directory ドメインからユーザーを認証して、クロス領域のトラストをセットアップすることができます。このような設定では、認証されたユーザーをシームレスに認証して EMR クラスターにアクセスできます。

Amazon EMR は、オープンソースの Hadoop ベースアプリケーションをクラスターにインストールします。つまり、これらの製品で Kerberos を使用する既存のセキュリティ機能を使用できます。例えば、YARN の Kerberos 認証を有効にして、Apache Spark などの YARN で実行されているアプリケーションに対して、ユーザーレベルの認証を与えることができます。

EMR クラスターで Kerberos を構成することができます(別名、Kerberizing)。これにより、クラスターユーザーの認証を得る手段が提供されます。 Amazon EMR で Kerberos を構成する前に、EMR ドキュメントの「Kerberos 認証を使用する」を参照して、Kerberos の概念に精通しておくことをお勧めします。

次の例は、CloudFormation による Kerberizing を示しています。

"SecurityConfiguration": {
      "Type": "AWS::EMR::SecurityConfiguration",
      "Properties": {
        "SecurityConfiguration": {
          "AuthenticationConfiguration": {
            "KerberosConfiguration": {
              "ClusterDedicatedKdcConfiguration": {
                "CrossRealmTrustConfiguration": {
                  "Realm": {
                    "Ref": "KerberosADdomain"
                  },
                  "KdcServer": {
                    "Ref": "DomainDNSName"
                  },
                  "Domain": {
                    "Ref": "DomainDNSName"
                  },
                  "AdminServer": {
                    "Ref": "DomainDNSName"
                  }
                },
                "TicketLifetimeInHours": 24
              },
              "Provider": "ClusterDedicatedKdc"
            }
          }
        }
      }
    }
...

Amazon EMR での承認

Amazon EMR では、AWS Identity and Access Managementt (IAM) を使用して、クラスターへのアクセスを管理します。IAM を使用して、Amazon EMR やその他の AWS リソースで実行できるアクションを制御するユーザーやグループなど、プリンシパルのポリシーを作成できます。

通常、Amazon EC2 インスタンスプロファイルサービスロールとロール、2 つのロールは、Amazon EMR の各クラスターに関連しています。EC2 インスタンスのコンテキストで実行されないリソースやその他のサービスレベルのタスクプロビジョニングに関連するアクションについては、サービスロールまたは EMR ロールを使用します。インスタンスプロファイルのロールは、クラスターの EC2 インスタンスによって使用されます。このロールに関連付けられているポリシーは、クラスターインスタンスで実行されるプロセスに適用されます。これらのロールおよびその他の詳細については、「EMR ドキュメント」の「AWS のサービスに対する Amazon EMR 権限の IAMロールの構成」を参照してください。

IAM を使用して、これらのロールに関連するクラスターへ許可されたアクセスを制御する方法と、許可されていないアクセスを制御する方法を理解することが重要です。IAM は、他の AWS のサービスで実行される API レベルのアクションを制御します。IAM は、S3 のオブジェクトへのアクセス制御、クラスター変更に対する保護、AWS KMS のキーへのアクセス制限などに役立ちます。

これには重要な意味があります。デフォルトでは、クラスターで実行中のすべてのプロセスは、クラスターに関連付けられた IAMロールのアクセス権限を継承します。対照的に、IAM はクラスターのアクティビティを制御しません。各 EC2 インスタンスで実行されているプロセスを適切に保護するには、他の手段を使用する必要があります。

これらの特性のため、以前は特定の Amazon EMR 承認チャレンジに直面していました。デフォルトでは、このチャレンジはクラスターの EC2 インスタンスプロファイルロールにアタッチされた IAMロールが、Amazon S3 でアクセスできるデータを決定する方法を理解するものでした。S3 へのデータアクセスはクラスターレベルでのみ、きめ細かい有効手段となります。その結果、潜在的に異なるレベルのデータへのアクセスを持つ複数のユーザーが同じクラスターに接触することが難しくなりました。

Amazon EMR バージョン 5.10.0 以降では、EMRFS のきめ細かい承認が導入されました。このきめ細かい承認により、EMRFS が Amazon S3 にアクセスしているときに、ユーザーまたはグループレベルで想定する IAMロールを指定することができます。この承認により、マルチテナント型 EMR クラスターで Amazon S3 のきめ細かいアクセス制御が可能になります。また、クロスアカウントの Amazon S3 でデータにアクセスすることも容易になります。

EMRFS 承認機能は、特に HiveServer2 を使用したアクセスに適用されます。ユーザーが任意のコード(Jupyter、Zeppelin、SSH、spark-shell など)を実行できる Spark または他のアプリケーションを使用している場合、ユーザーは EMRFS がマップしたロールをバイパスできます。

セキュリティ構成と IAMロールを適切に構成する方法については、「EMR ドキュメント」の「Amazon S3 への EMRFS リクエストの IAMロールの構成」を参照してください。

Kerberos 認証と EMRFS 承認の両方を備えたマルチテナント環境のセットアップに関する詳細ガイドについては、AWS ビッグデータブログの次の記事を参照してください。「Kerberos、Microsoft Active Directory インテグレーションおよび EMRFS の IAMロールを使用したマルチテナントの Amazon EMR クラスターの構築」

ネットワーク

セキュリティとプライバシーを考えて設計するときは、ネットワークトポロジーも重要です。Amazon EMR クラスターをプライベートサブネットに配置し、NAT を使用してアウトバウンドのインターネットアクセスのみを実行することをお勧めします。

セキュリティグループは、個々のインスタンスからインバウンドアクセスとアウトバウンドアクセスを制御します。Amazon EMR では、Amazon EMR マネージド型セキュリティグループ独自のセキュリティグループの両方を使用して、インスタンスへのネットワークアクセスを制御できます。セキュリティグループに最小特権のプリンシパルを適用することで、アクセスが必要なアプリケーションまたは個人のみに EMR クラスターをロックダウンできます。

詳細については、「EMR ドキュメント」の「Amazon EMR マネージド型セキュリティグループの操作」を参照してください。

次の例は、boto3 を持つセキュリティグループを示しています。

import boto3
from botocore.exceptions import ClientError

ec2 = boto3.client('ec2')

response = ec2.describe_vpcs()
vpc_id = response.get('Vpcs', [{}])[0].get('VpcId', '')

try:
    response = ec2.create_security_group(GroupName='SECURITY_GROUP_NAME',
                                         Description='Allow 80',
                                         VpcId=vpc_id)
    security_group_id = response['GroupId']

    data = ec2.authorize_security_group_ingress(
        GroupId=security_group_id,
        IpPermissions=[
            {'IpProtocol': 'tcp',
             'FromPort': 22,
             'ToPort': 22,
             'IpRanges': [{'CidrIp': '0.0.0.0/0'}]}
        ])
except ClientError as e:
    print(e)

次の例は、CloudFormation を持つセキュリティグループを示しています。

InstanceSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Allow 80
    VpcId:
      Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
      FromPort: '80'
      ToPort: '80'
      CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: tcp
      FromPort: '80'
      ToPort: '80'
      CidrIp: 0.0.0.0/0
 ...

最小限の IAM ポリシー

デフォルトでは、EMR に関連付けられた IAM ポリシーは一般に許可され、EMR を他の AWS のサービスと簡単に統合することができます。EMR を保護するときのベストプラクティスは、EMR が機能するために必要な最小限の権限から始め、必要に応じて権限を追加することです。

以下は、EMR のベーシック操作に最低限必要とされる 3 つのポリシーです。スポット料金や Autoscaling に関連するアクションを削除することで、これらのポリシーをさらに最小限に抑えることができます。わかりやすくするために、ポリシーには注釈が付いています。使用前に注釈を削除してください。

最小限の EMR サービスロールポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": [
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:CancelSpotInstanceRequests",
                "ec2:CreateNetworkInterface",
                "ec2:CreateSecurityGroup",
                "ec2:CreateTags",
                "ec2:DeleteNetworkInterface", // プライベートサブネットでクラスターを起動する場合にのみ必要です。
                "ec2:DeleteTags",
                "ec2:DeleteSecurityGroup", // プライベートサブネットに対して、Amazon マネージド型セキュリティグループを使用している場合にのみ必要です。カスタムセキュリティグループを使用している場合は、このアクションを省略できます。
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeDhcpOptions",
                "ec2:DescribeImages",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:DescribeKeyPairs",
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribePrefixLists",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSpotInstanceRequests",
                "ec2:DescribeSpotPriceHistory",
                "ec2:DescribeSubnets",
                "ec2:DescribeTags",
                "ec2:DescribeVpcAttribute",
                "ec2:DescribeVpcEndpoints",
                "ec2:DescribeVpcEndpointServices",
                "ec2:DescribeVpcs",
                "ec2:DetachNetworkInterface",
                "ec2:ModifyImageAttribute",
                "ec2:ModifyInstanceAttribute",
                "ec2:RequestSpotInstances",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:RunInstances",
                "ec2:TerminateInstances",
                "ec2:DeleteVolume",
                "ec2:DescribeVolumeStatus",
                "ec2:DescribeVolumes",
                "ec2:DetachVolume",
                "iam:GetRole",
                "iam:GetRolePolicy",
                "iam:ListInstanceProfiles",
                "iam:ListRolePolicies",
                "s3:CreateBucket",
                "sdb:BatchPutAttributes",
                "sdb:Select",
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:DeleteAlarms",
                "application-autoscaling:RegisterScalableTarget",
                "application-autoscaling:DeregisterScalableTarget",
                "application-autoscaling:PutScalingPolicy",
                "application-autoscaling:DeleteScalingPolicy",
                "application-autoscaling:Describe*"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:s3:::examplebucket/*","arn:aws:s3:::examplebucket2/*"], // ここでは、クラスターログ、ブートストラップのアクションスクリプト、カスタム JAR ファイル、EMR 手順の入力パスと出力パスを保存するバケットのリストを指定できます
            "Action": [
                "s3:GetBucketLocation",
                "s3:GetBucketCORS",
                "s3:GetObjectVersionForReplication",
                "s3:GetObject",
                "s3:GetBucketTagging",
                "s3:GetObjectVersion",
                "s3:GetObjectTagging",
                "s3:ListMultipartUploadParts",
                "s3:ListBucketByTags",
                "s3:ListBucket",
                "s3:ListObjects",
                "s3:ListBucketMultipartUploads"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": "arn:aws:sqs:*:123456789012:AWS-ElasticMapReduce-*", // EMR は名前の先頭にリテラル文字列 AWS-ElasticMapReduce- が付いた SQS キューに対してのみアクション(キューの作成、メッセージの受信、キューの削除など)を実行できます。
            "Action": [
                "sqs:CreateQueue",
                "sqs:DeleteQueue",
                "sqs:DeleteMessage",
                "sqs:DeleteMessageBatch",
                "sqs:GetQueueAttributes",
                "sqs:GetQueueUrl",
                "sqs:PurgeQueue",
                "sqs:ReceiveMessage"
            ]
        },
        {
            "Effect": "Allow", 
            "Action": "iam:CreateServiceLinkedRole",  // EMR には、EC2 スポットインスタンスを起動する、このサービスに関連付けられたロールを作成する権限が必要です
            "Resource": "arn:aws:iam::*:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot*",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "spot.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole", // 必要最低限の権限を持つカスタム EC2 インスタンスプロファイル(次のように定義されています)を渡します
            "Resource": [
                "arn:aws:iam::*:role/Custom_EMR_EC2_role",
                "arn:aws:iam::*:role/EMR_AutoScaling_DefaultRole"
            ]
        }
    ]
}

EC2(インスタンスプロファイル)ポリシーで最小限の EMR ロール

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": [
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:CancelSpotInstanceRequests",
                "ec2:CreateNetworkInterface",
                "ec2:CreateSecurityGroup",
                "ec2:CreateTags",
                "ec2:DeleteNetworkInterface", // プライベートサブネットでクラスターを起動する場合にのみ必要です。
                "ec2:DeleteTags",
                "ec2:DeleteSecurityGroup", // プライベートサブネットに対して、Amazon マネージド型セキュリティグループを使用している場合にのみ必要です。カスタムセキュリティグループを使用している場合は、このアクションを省略できます。
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeDhcpOptions",
                "ec2:DescribeImages",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:DescribeKeyPairs",
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribePrefixLists",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSpotInstanceRequests",
                "ec2:DescribeSpotPriceHistory",
                "ec2:DescribeSubnets",
                "ec2:DescribeTags",
                "ec2:DescribeVpcAttribute",
                "ec2:DescribeVpcEndpoints",
                "ec2:DescribeVpcEndpointServices",
                "ec2:DescribeVpcs",
                "ec2:DetachNetworkInterface",
                "ec2:ModifyImageAttribute",
                "ec2:ModifyInstanceAttribute",
                "ec2:RequestSpotInstances",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:RunInstances",
                "ec2:TerminateInstances",
                "ec2:DeleteVolume",
                "ec2:DescribeVolumeStatus",
                "ec2:DescribeVolumes",
                "ec2:DetachVolume",
                "iam:GetRole",
                "iam:GetRolePolicy",
                "iam:ListInstanceProfiles",
                "iam:ListRolePolicies",
                "s3:CreateBucket",
                "sdb:BatchPutAttributes",
                "sdb:Select",
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:DeleteAlarms",
                "application-autoscaling:RegisterScalableTarget",
                "application-autoscaling:DeregisterScalableTarget",
                "application-autoscaling:PutScalingPolicy",
                "application-autoscaling:DeleteScalingPolicy",
                "application-autoscaling:Describe*"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:s3:::examplebucket/*","arn:aws:s3:::examplebucket2/*"], // ここでは、クラスターログ、ブートストラップのアクションスクリプト、カスタム JAR ファイル、EMR 手順の入力パスと出力パスを保存するバケットのリストを指定できます
            "Action": [
                "s3:GetBucketLocation",
                "s3:GetBucketCORS",
                "s3:GetObjectVersionForReplication",
                "s3:GetObject",
                "s3:GetBucketTagging",
                "s3:GetObjectVersion",
                "s3:GetObjectTagging",
                "s3:ListMultipartUploadParts",
                "s3:ListBucketByTags",
                "s3:ListBucket",
                "s3:ListObjects",
                "s3:ListBucketMultipartUploads"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": "arn:aws:sqs:*:123456789012:AWS-ElasticMapReduce-*", // EMR は名前の先頭にリテラル文字列 AWS-ElasticMapReduce- が付いた SQS キューに対してのみアクション(キューの作成、メッセージの受信、キューの削除など)を実行できます。
            "Action": [
                "sqs:CreateQueue",
                "sqs:DeleteQueue",
                "sqs:DeleteMessage",
                "sqs:DeleteMessageBatch",
                "sqs:GetQueueAttributes",
                "sqs:GetQueueUrl",
                "sqs:PurgeQueue",
                "sqs:ReceiveMessage"
            ]
        },
        {
            "Effect": "Allow", 
            "Action": "iam:CreateServiceLinkedRole",  // EMR には、EC2 スポットインスタンスを起動する、このサービスに関連付けられたロールを作成する権限が必要です
            "Resource": "arn:aws:iam::*:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot*",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "spot.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole", // 必要最低限の権限を持つカスタム EC2 インスタンスプロファイル(次のように定義されています)を渡します
            "Resource": [
                "arn:aws:iam::*:role/Custom_EMR_EC2_role",
                "arn:aws:iam::*:role/EMR_AutoScaling_DefaultRole"
            ]
        }
    ]
}

EC2(インスタンスプロファイル)ポリシーで最小限の EMR ロール

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": [
                "ec2:Describe*",
                "elasticmapreduce:Describe*",
                "elasticmapreduce:ListBootstrapActions",
                "elasticmapreduce:ListClusters",
                "elasticmapreduce:ListInstanceGroups",
                "elasticmapreduce:ListInstances",
                "elasticmapreduce:ListSteps"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": [    // ここでは、クラスターのノードで実行されているアプリケーション(Spark、Hive など)がアクセスするバケットのリストを指定できます
                "arn:aws:s3:::examplebucket1/*",
                "arn:aws:s3:::examplebucket1*",
                "arn:aws:s3:::examplebucket2/*",
                "arn:aws:s3:::examplebucket2*"
            ],
            "Action": [
                "s3:GetBucketLocation",
                "s3:GetBucketCORS",
                "s3:GetObjectVersionForReplication",
                "s3:GetObject",
                "s3:GetBucketTagging",
                "s3:GetObjectVersion",
                "s3:GetObjectTagging",
                "s3:ListMultipartUploadParts",
                "s3:ListBucketByTags",
                "s3:ListBucket",
                "s3:ListObjects",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject",
                "s3:PutObjectTagging",
                "s3:HeadBucket",
                "s3:DeleteObject"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": "arn:aws:sqs:*:123456789012:AWS-ElasticMapReduce-*", // EMR は名前の先頭にリテラル文字列 AWS-ElasticMapReduce- が付いた SQS キューに対してのみアクション(キューの作成、メッセージの受信、キューの削除など)を実行できます。
            "Action": [
                "sqs:CreateQueue",
                "sqs:DeleteQueue",
                "sqs:DeleteMessage",
                "sqs:DeleteMessageBatch",
                "sqs:GetQueueAttributes",
                "sqs:GetQueueUrl",
                "sqs:PurgeQueue",
                "sqs:ReceiveMessage"
            ]
        }
    ]
}

EMR クラスターを起動するユーザーの最小限のロールポリシー

// このポリシーは、EMR クラスターを起動する IAM ユーザーにアタッチすることができます。EMR クラスターを起動、モニタ、終了する最小限のアクセスをユーザーに提供します

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": [
                        "elasticmapreduce.amazonaws.com",
                        "elasticmapreduce.amazonaws.com.cn"
                    ]
                }
            }
        },
        {
            "Sid": "Statement2",
            "Effect": "Allow",
            "Action": [
                "iam:GetPolicyVersion",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:DescribeInstances",
                "ec2:RequestSpotInstances",
                "ec2:DeleteTags",
                "ec2:DescribeSpotInstanceRequests",
                "ec2:ModifyImageAttribute",
                "cloudwatch:GetMetricData",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:ListMetrics",
                "ec2:DescribeVpcAttribute",
                "ec2:DescribeSpotPriceHistory",
                "ec2:DescribeAvailabilityZones",
                "ec2:CreateRoute",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:CreateSecurityGroup",
                "ec2:DescribeAccountAttributes",
                "ec2:ModifyInstanceAttribute",
                "ec2:DescribeKeyPairs",
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeRouteTables",
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:TerminateInstances", //このアクションは、次と同様の方法でスコープを指定できます。 "elasticmapreduce:TerminateJobFlows"
                "iam:GetPolicy",
                "ec2:CreateTags",
                "ec2:DeleteRoute",
                "iam:ListRoles",
                "ec2:RunInstances",
                "ec2:DescribeSecurityGroups",
                "ec2:CancelSpotInstanceRequests",
                "ec2:CreateVpcEndpoint",
                "ec2:DescribeVpcs",
                "ec2:DescribeSubnets",
                "elasticmapreduce:*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Statement3",
            "Effect": "Allow",
            "Action": [
                "elasticmapreduce:TerminateJobFlows"
            ],
            "Resource":"*",
            "Condition": {
                "StringEquals": {
                  "elasticmapreduce:ResourceTag/custom_key": "custom_value"  // ここでは、カスタムタグのキー値ペアを指定して、この IAM ユーザーがユーザーによって適切にタグ付けされたクラスターのみを削除できるようにします
                }
              }
        },
        {
            "Sid": "Statement4",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": [
                "arn:aws:iam::*:role/Custom_EMR_Role",
                "arn:aws:iam::*:role/Custom_EMR_EC2_role",
                "arn:aws:iam::*:role/EMR_AutoScaling_DefaultRole"
            ]
        }
    ]
}

ブートストラップアクション

ブートストラップアクションは、通常、クラスターの実行前にセットアップ用のカスタムコードを実行するために使用されます。それらを使用して、Bash、Perl、Python、Ruby、C++、Java など、クラスターにすでにインストールされている言語でソフトウェアをインストールしたり、インスタンスを構成したりすることができます。

ブートストラップアクションの使用方法については、「EMR ドキュメント」の「ブートストラップアクションを作成して、追加ソフトウェアをインストールする」を参照してください。

このブログの記事では、クラスターを強化し、必要なセキュリティパッケージを適用し、サードパーティのモニタリングソリューションをセットアップするためのブートストラップアクションについて説明します。

ブートストラップアクションは、いつクラスターのライフサイクルで実行されますか?

ブートストラップアクションは、インスタンスのプロビジョニング後およびアプリケーションのインストール前に、各クラスターのインスタンスで実行されます。このアプローチは、ブートストラップアクションを使用して、EMR によってプロビジョニングされるアプリケーションのセキュリティ構成を変更する場合に意味があります。このような場合は、Presto のインストールに応じてブートストラップアクションを使用し、スクリプトを特定のトリガーで待機させることができます。

# Presto がインストールされる前に、行う作業がこの行の前で実行されます
while [ ! -f /var/run/presto/presto-presto-server.pid ]
do
  sleep 1
done

# スクリプトの実行を続けます

前述のスニペットをバックグラウンドプロセスで実行して、プロビジョニングプロセスをブロックしないようにしてください。そうでない場合は、タイムアウトで失敗します。

クラスターのライフサイクルについては、「EMR ドキュメント」の「クラスターのライフサイクルの理解」を参照してください。

カスタム AMI と CIS コントロールを適用して AMI を強化

カスタム Amazon Machine Image (AMI) は、EMR クラスターの強化および保護に役立つ別のアプローチを提供します。Amazon EMR は、Amazon Linux AMI を使用して、クラスターを作成および起動するときに Amazon EC2 インスタンスを初期化します。AMI には、Amazon Linux オペレーティングシステム、その他のソフトウェア、および各インスタンスがクラスターアプリケーションをホストするために必要な構成が含まれています。

カスタム AMI を指定すると、次のユースケースに役立ちます。

  • クラスターで EC2 インスタンスの EBS ルートデバイスボリューム(ブートボリューム)を暗号化します。セキュリティ構成ではできません。セキュリティ構成は、ストレージボリュームの暗号化に役立ちます。詳細については、「EMR ドキュメント」の「暗号化された Amazon EBS ルートデバイスボリュームを使用したカスタム AMI の作成」を参照してください。
  • ブートストラップアクションを使用する代わりに、アプリケーションを予めインストールして他のカスタマイズを実行すると、クラスターの開始時間が短縮され、起動ワークフローが合理化されます。詳細と例については、「EMR ドキュメント」の「事前に構成されたインスタンスからのカスタム Amazon Linux AMI の作成」を参照してください。
  • ブートストラップアクションよりも高度なクラスターおよびノード構成を実行することができます。

ブートストラップアクションの代わりにカスタム AMI を使用することで、インスタンスをプロビジョニングするときに、ブートストラップアクションのスクリプトを実行せずに、使用している画像に予め強化された手順を組み込むことができます。二つのうちどちらかを選ぶ必要はありません。変更する可能性の低いクラスターの共通セキュリティ特性で、カスタム AMI を作成できます。ブートストラップアクションを使用して、クラスター固有の最新構成とスクリプトを引き出すことができます。

多くのお客様が取るアプローチの 1 つは、Center for Internet Security の ウェブサイトにある EMR クラスターを強化するために、Center for Internet Security (CIS) ベンチマークを適用することです。これらのベンチマークをクラスターに適用するときは、各コントロールに対して必要性と機能テストを要件ごとに検証することが重要です。

次の例は、CloudFormation でカスタム AMI を使用する方法を示しています。

Resources:
  cluster:
    Type: 'AWS::EMR::Cluster'
    Properties:
      CustomAmiId: "ami-7fb3bc69"
      Instances:
        MasterInstanceGroup:
...

次の例は、boto3 でカスタム AMI を使用する方法を示しています。

response = client.run_job_flow(
    Name='string',
    LogUri='string',
    AdditionalInfo='string',
    CustomAmiId='ami-7fb3bc69',
...

監査

多くのお客様にとって重要な要件であるコンピューティング環境を監査する機能が必要な場合があります。EMR 内でこの要件をサポートできるさまざまな方法があります。

  • EMR 5.14.0 以降、S3 の Amazon EMR コネクタである EMRFS は、S3 の EMRFS でデータにアクセス済みのクエリを実行したユーザーの監査をサポートします。この機能はデフォルトで有効になっており、ユーザーやグループの情報を CloudTrail などの監査ログに渡します。包括的なリクエストの追跡を提供します。
  • 存在する場合は、EMR でアプリケーション固有の監査を構成して実行できます。例えば、この AWS ビッグデータブログの記事は、Presto でカスタムイベントリスナーを構成して、監査ログ、デバッグ、およびパフォーマンス分析を有効にする方法を説明しています。「監査と Performance Insights のための Amazon EMR のカスタムログ Presto クエリイベント。
  • Apache Ranger などのツールを使用して、監査と承認の層を別に実行することができます。詳細については、この AWS ビッグデータブログの記事を参照してください。「Amazon EMR の Apache Ranger を使用した承認と監査の実行」
  • ユーザー、ロール、または AWS のサービスによって実行されたアクションの記録を提供する AWS CloudTrail サービスは、Amazon EMR と統合されています。CloudTrail は、イベントで Amazon EMR のすべての API 呼び出しを取得します。取得した呼び出しには、Amazon EMR コンソールからの呼び出しと Amazon EMR API 操作へのコード呼び出しが含まれます。トレイルを作成すると、Amazon EMR のイベントを含む Amazon S3 バケットへの CloudTrail イベントの継続的な配信が可能になります。
  • また、S3 のアクセスログを使用して、EMR がアクセスする S3 オブジェクトを監査することもできます。AWS CloudTrail は、AWS API 呼び出しのログのみを提供します。したがって、ユーザーが S3 にデータを読み書きするジョブを実行すると、EMR によってアクセスされた S3 データは CloudTrail に表示されません。S3 のアクセスログを使用することで、EMR を含むどこからでも、S3 のデータに対するアクセスを包括的にモニタリングおよび監査できます。
  • EMR クラスターを完全に制御するため、サードパーティのエージェントまたはツールをいつでもインストールできます。ブートストラップアクションまたはカスタム AMI を使用して、監査要件をサポートする場合に役立ちます。

セキュリティ構成の検証

もちろん、構成が正常に動作していることを検証する必要があります。次に、構成を検証するために実行できる手順をいくつか示します。

EMR の S3 サーバー側暗号化(SSE)

ここでは、特定のケースを検証する必要があります。S3 オブジェクトが EMRFS を使用してアップロードされ、EMRFS 構成でサーバー側の暗号化(SSE)が有効になっている場合、暗号化されていることを示すメタデータがあることを確認します。例えば、オブジェクトが S3 キーを使用して暗号化されている場合、S3 オブジェクトで getSSEAlgorithm を呼び出すと AES256 が返されます。オブジェクトが KMS キーを使用して暗号化されている場合は、aws:kms を返します。

また、EMRFS を使用してファイルをダウンロードされる場合、元のファイルとダウンロードされたファイルの内容が一致することを確認してください。

検証するには、次の手順を実行します。

  1. 「EMR ドキュメント」の「SSH を使用したマスターノードへの接続」の説明に従って、Secure Shell (SSH) を使用してマスターノードに接続します。
  2. EMRFS を使用して S3 にオブジェクトをアップロードします。
    • hadoop fs -put <local path> <s3 bucket path>
  3. アップロードされたオブジェクトのメタデータを直接チェックします。
    • aws s3api head-object --bucket <s3 bucket path> --key file
  4. EMRFS を使用して S3 からファイルをダウンロードします。
    • hadoop fs -get <s3 bucket path> <local path>
  5. 元のファイルとダウンロードしたファイルに diff を使用し、それらが同じであることを確認します。

EMR の S3 クライアント側暗号化(CSE)

サーバー側の暗号化を検証する場合と同様に、別のポイントを確認する必要があります。EMRFS を使用してオブジェクトがアップロードされ、EMRFS 構成でクライアント側の暗号化が有効になっている場合は、S3 オブジェクトのコンテンツを暗号化する必要があります。正しいキーを持っていないクライアントは、確認することができません。Amazon S3 クライアントを使用してオブジェクトを取得した場合、オブジェクトの内容は、アップロードされた元のオブジェクトの内容と同じではいけません。

また、EMRFS を使用してファイルをダウンロードすると、ダウンロードしたファイルの内容が元のファイルの内容と一致することも確認する必要があります。

検証するには、次の手順を実行します。

  1. 「SSH を使用したマスターノードへの接続」の説明に従って、SSH を使用してマスターノードに接続します。
  2. EMRFS を使用して S3 にオブジェクトをアップロードします。
    • hadoop fs -put <local path> <s3 bucket path>
  3. AWS CLI を使用して S3 からオブジェクトをダウンロードします。
    • aws s3 mv <s3 bucket path> <local path>
    • このファイルは元のファイルと一致してはいけません。
  4. EMRFS を使用して S3 からオブジェクトをダウンロードします。
    • hadoop fs -get <s3 bucket path> <local path>
    • このファイルは元のファイルと一致する必要があります。

ローカルディスクの暗号化

また、ローカルディスクの暗号化が有効になっている場合、クラスターのブロックデバイスがすべて crypto_LUKS タイプであることを確認する必要があります。LUKS パーティション以外のパーティションがある場合、次のコマンドはリターンコード 1 で終了します。

! blkid | grep -v crypto_LUKS

さらに、ローカルディスクの暗号化では、構成で定義された種類のキーが使用されていることを検証する必要があります。

暗号化されたローカルディスクのパスフレーズを復号化するために KMS を使用してみましょう。復号化された場合は、それを使って LUKS パーティションを開きます。復号化されない場合は、それをカスタムキーと想定します。

これを行うには、次のコマンドを実行します。

  1. base64 -d /var/setup-devices/.encrypted-diskKey > (local path for encrypted passphrase)
  2. aws kms decrypt --ciphertext-blob fileb://(local path for encrypted passphrase) --query Plaintext > (local path for decrypted passphrase)
    • この手順が失敗した場合、そのキーは KMS からのものではありません
  3. sudo cryptsetup luksOpen --test-passphrase --key-slot 0 /dev/xvdb1 < (local path for decrypted passphrase) | cut -d '"' -f 2

AWS CloudFormation のまとめ

以下の AWS CloudFormation テンプレートを用意しました。このテンプレートは、この記事で説明するパターンとプラクティスに沿った EMR クラスターをより簡単に展開できるようにします。次のテンプレートは、次の特性を持つ EMR クラスターをスピンアップします。

  • S3 とローカルディスクの両方で有効化された休止中の暗号化
  • 指定した証明書バンドルを使用して有効化された移動中の暗号化
  • カスタム AMI セクションで説明した概念を組み込めるカスタム AMI CloudFormation パラメータ
  • Kerberos 対応
  • きめ細かな S3 承認
---
Description: EMR クラスターを作成する CloudFormation テンプレートのサンプル
Parameters:
  KeyName:
    Description: インスタンスへの SSH を有効にする既存の EC2 キーペアの名前
    Type: AWS::EC2::KeyPair::KeyName
  Subnet:
    Description: EMR クラスターを作成するサブネット ID
    Type: AWS::EC2::Subnet::Id
Resources:
  EMRInstanceProfile:
    Properties:
      Roles:
      - Ref: EMRJobFlowRole
    Type: AWS::IAM::InstanceProfile
  EMRJobFlowRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role
    Type: AWS::IAM::Role
  EMRSampleCluster:
    Properties:
      Applications:
      - Name: Hadoop
      - Name: Hive
      - Name: Spark
      AutoScalingRole:
        Ref: EMR_AutoScaling_DefaultRole
      BootstrapActions:
      - Name: Dummy bootstrap action
        ScriptBootstrapAction:
          Args:
          - dummy
          - parameter
          Path: file:/usr/share/aws/emr/scripts/install-hue
      Configurations:
      - Classification: core-site
        ConfigurationProperties:
          hadoop.security.groups.cache.secs: '250'
      - Classification: mapred-site
        ConfigurationProperties:
          mapred.tasktracker.map.tasks.maximum: '2'
          mapreduce.map.sort.spill.percent: '90'
          mapreduce.tasktracker.reduce.tasks.maximum: '5'
      Instances:
        CoreInstanceGroup:
          EbsConfiguration:
            EbsBlockDeviceConfigs:
            - VolumeSpecification:
                SizeInGB: '10'
                VolumeType: gp2
              VolumesPerInstance: '1'
            EbsOptimized: 'true'
          InstanceCount: '1'
          InstanceType: m4.large
          Name: Core Instance
        Ec2KeyName:
          Ref: KeyName
        Ec2SubnetId:
          Ref: Subnet
        MasterInstanceGroup:
          InstanceCount: '1'
          InstanceType: m4.large
          Name: Master Instance
      JobFlowRole:
        Ref: EMRInstanceProfile
      Name: EMR Sample Cluster
      ReleaseLabel: emr-5.5.0
      SecurityConfiguration:
        Ref: EMRSecurityConfiguration
      ServiceRole:
        Ref: EMRServiceRole
      Tags:
      - Key: Name
        Value: EMR Sample Cluster
      VisibleToAllUsers: 'true'
    Type: AWS::EMR::Cluster
  EMRSecurityConfiguration:
    Properties:
      Name: EMRSampleClusterSecurityConfiguration
      SecurityConfiguration:
        EncryptionConfiguration:
          AtRestEncryptionConfiguration:
            LocalDiskEncryptionConfiguration:
              AwsKmsKey: arn:aws:kms:us-east-1:123456789012:key/1234-1234-1234-1234-1234
              EncryptionKeyProviderType: AwsKms
            S3EncryptionConfiguration:
              AwsKmsKey: arn:aws:kms:us-east-1:123456789012:key/1234-1234-1234-1234-1234
              EncryptionMode: SSE-KMS
          EnableAtRestEncryption: 'true'
          EnableInTransitEncryption: 'true'
          InTransitEncryptionConfiguration:
            TLSCertificateConfiguration:
              CertificateProviderType: PEM
              S3Object: s3://MyConfigStore/artifacts/MyCerts.zip
    Type: AWS::EMR::SecurityConfiguration
  EMRServiceRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Effect: Allow
          Principal:
            Service:
            - elasticmapreduce.amazonaws.com
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceRole
    Type: AWS::IAM::Role

まとめ

この記事では、EMR クラスターを保護するときに考え、従う一連のベストプラクティスを提供します。ご質問またはご提案については、コメントを残してください。

 


その他の参考資料

この記事が役に立つと思いましたら、リソースレベルの IAM 権限とリソースベースのポリシーを使用して AWS Glue データカタログへのアクセスを制限しAmazon EMR で Apache Ranger を使用して承認と監査を実行し暗号化を使用して Amazon EMR を保護してください。

 


著者について

Tony Nguyen は、AWS プロフェッショナルサービスのシニアコンサルタントです。彼の専門分野はデータと分析で、公共部門のお客様が独自のデータ問題を解決することに重点を置いています。彼は、AWS でビッグデータと分析ソリューションを設計、アーキテクト、実行するために、お客様と直接仕事をしています。ディープデータに目を向けないときは、バレーボールや料理を楽しみ、時にはそれなりに写真家のような写真を披露しています。

 

 

 

 

Aaron Friedman 博士は、アマゾン ウェブ サービスのヘルスケア&ライフサイエンス分野のパートナーソリューションアーキテクトです。彼は ISV や SI で、AWS のヘルスケアソリューションをアーキテクトし、お客様に最高の体験を提供いたします。その情熱は、科学、ビッグデータ、ソフトウェアに注がれています。空き時間には、屋外で探索したり、新しい料理を学んだり、妻と犬のマカロンと時間を過ごしています。