Amazon Web Services ブログ

EMRFSを利用して、別AWSアカウントからデータを安全に分析する

by AWS Japan Staff | on | in Amazon EMR, Amazon S3, AWS IAM |

分析されるデータは、異なるアカウントが所有するバケットに分散されることがあります。データのセキュリティを確保するためには、適切な認証情報管理が必要です。これは、さまざまな部門の異なるAmazon S3バケットにデータを格納している大企業にとって特に当てはまります。例えば、顧客サービス部門は、研究部門が所有するデータにアクセスする必要があるかもしれませんが、研究部門はそのアクセスを安全な方法で提供する必要があります。

データを保護するこの側面は非常に複雑になる可能性があります。 Amazon EMRは、統合メカニズムを使用して、S3に格納されたデータにアクセスするためのユーザー認証情報を提供します。 EMR上でアプリケーション(Hive、Sparkなど)を使用してS3バケットとの間でファイルを読み書きする場合、S3 API呼び出しには認証するための適切な認証情報で署名する必要があります。

通常、これらの認証情報は、クラスターの起動時に指定するEC2インスタンスプロファイルによって提供されます。そのオブジェクトが異なる認証情報セットを必要とするため、EC2インスタンスプロファイルの認証情報がS3オブジェクトにアクセスするのに十分でない場合はどうなるでしょうか?

このポストは、カスタム認証プロバイダを使用して、EMRFSのデフォルトの認証プロバイダがアクセスできないS3オブジェクトにアクセスする方法を示しています。

EMRFSおよびEC2インスタンスプロファイル

EMRクラスターを起動すると、Amazon EC2インスタンスプロファイルとしてIAMロールを指定する必要があります。インスタンスプロファイルは、EC2インスタンスの起動時にIAMロールに含まれる権限を渡すために使用されるコンテナです。基本的にIAMの役割は、その役割を担う人のための権限を定義します。

EMRの場合、インスタンスプロファイルに含まれるIAMロールは、Amazon S3、Amazon CloudWatch、Amazon Kinesisなどの他のAWSサービスにアクセスする権限を持ちます。このロールは、EC2インスタンスメタデータサービスを介して一時的な認証情報を取得し、他のAWSサービスにアクセスする必要のあるアプリケーションにそれを提供します。

たとえば、EMR上のHiveアプリケーションがS3バケット(S3バケットパスがs3://URIによって指定されている)から入力データを読み取る必要がある場合、EMRFSのデフォルトの認証プロバイダ機能を呼び出します。プロバイダは、EC2インスタンスプロファイルから一時的な認証情報を取得し、それを使用してS3 GETリクエストに署名します。

カスタム認証プロバイダ

場合によっては、デフォルト認証プロバイダによって取得された認証情報では、IAMユーザーがアクセス権を持たないS3バケットへのリクエストに署名するには不十分かもしれません。 特定のIAMユーザーまたは役割へのアクセスのみを許可する、異なる所有者または制限付きバケットポリシーがバケットにある可能性があります。

このような状況では、IAMユーザーがデータにアクセスできるようにするオプションがあります。 S3バケットポリシーを変更してIAMユーザーにアクセスできるようにすることはできますが、これはセキュリティリスクの可能性があります。 より良いオプションは、S3要求が正しい認証情報で署名されていることを確認するために、EMRFSのカスタム認証プロバイダを実装することです。 カスタム認証プロバイダは、設定されたEMRクラスターのみがS3のデータにアクセスできるようにします。 誰がデータにアクセスできるかをはるかに上手く制御できます。

EMRFS用のカスタム認証プロバイダの設定

AWSCredentialsProvider(AWS Java SDKの)とHadoop Configurableクラスの両方を実装して、Amazon S3を呼び出すときにEMRFSで使用するために、認証プロバイダを作成します。

AWSCredentialsProviderの各実装では、ユースケースに応じて認証情報を読み込む独自の戦略を選択できます。 特定のIAMユーザーの認証情報を使用してAPI呼び出しを行う場合は、AWS STS AssumeRole APIアクションを使用して認証情報をロードするか、もしくは、Javaプロパティファイルから認証情報をロードできます。 次に、カスタム認証プロバイダをJARファイルにパッケージ化し、JARファイルをEMRクラスターにアップロードし、emrfs-siteコンフィグレーション分類でfs.s3.customAWSCredentialsProviderを設定してクラス名を指定します。

ウォークスルー

独自のAWSアカウントを持つあなたの会社の研究部門が所有するS3バケットに格納されているデータを分析したいとします。 アカウントでEMRクラスターを起動し、EMRFSを利用して、研究部門が所有するバケットに保管されているデータにアクセスすることができます。

この例では、会社の2つのアカウントは次のとおりです。

  • 研究部門:research@yourcompany.com(アカウントID:123456789012)
  • あなたの部署:aws@yourcompany.com(アカウントID:111222333444)

また、aws@yourcompany.comに “data_analyst”というIAMユーザーがいます。 このユーザーには、research@yourcompany.comの”research-data”と呼ばれるバケットからデータを読み取るためのクロスアカウントアクセスが許可されている必要があります。 クロスアカウントアクセスを有効にするには、次の手順に従います。

  • IAMのアカウントをresearch@yourcompany.comに設定する
  • 内部アカウントを設定するaws@yourcompany.com

IAMのアカウントをresearch@yourcompany.comに設定する

  1. IAMコンソールにサインインします
  2. Rolesを選択し、Create New Roleに進みます
  3. “demo-role”のように、ロールの名前を入力します
  4. Role for Cross-Account Accessセクションを展開し、Provide access between AWS accounts you ownロールタイプを選択します。
  5. IAMユーザーがresearch@yourcompany.comにアクセスできるアカウントとしてaws@yourcompany.comを追加します。 これはaws@yourcompany.comのAWSアカウントIDを指定することで実行できます。 アカウントIDは、AWS管理コンソールのMy Accountページから取得できます。
  6. Attach Policyページで、Next Stepを選択します
  7. 詳細を確認し、Create Roleを選択します
  8. 左側のナビゲーションで、Policiesを選択して、Create Policyに進みます
  9. Create Your Own Policyを選択し、ポリシーにdemo-role-policyという名前を付けます。ポリシードキュメントは次のとおりです
  10. {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": [
                    "arn:aws:s3:::research-data",
                    "arn:aws:s3:::research-data/*"
                ]
            }
        ]
    }
  11. 左側のナビゲーションペインで、Rolesページを選択し、demo-roleロールを開き、Attach Policyを選択します。 表示されたポリシーのリストから、demo-role-policy(手順9で作成したばかり)を開き、ポリシーを添付します
  12. ロールの信頼関係を構成するには、Trust Relationshipsを選択して、Edit Trust Relationshipに進みます
  13. Edit Trust Relationshipページで、ポリシードキュメントでこのロールを担うことができるIAMユーザーdata_analystを指定する必要があります
  14. {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "AWS": "arn:aws:iam:: 111222333444:data_analyst"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }

IAMのアカウントをaws@yourcompany.comに設定する

IAMポリシーをユーザー”data_analyst”に添付します。これにより、ユーザーはresearch@yourcompany.comというアカウントで作成されたIAMロール”demo-role”を引き受けることができます。

  1. IAMコンソールにサインインする
  2. Policiesを選択して、Create Policyに進みます
  3. Create Your Own Policyを選択し、ポリシーの名前を”data-analyst-policy”とします。ポリシードキュメントは次のとおりです。
  4. {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "sts:AssumeRole",
                "Resource": "arn:aws:iam:: 123456789012:role/demo-role"
            }
        ]
    }
  5. Create Policyを選択する
  6. 作成したばかりのポリシーを選び、Policy actionsを選択して、Attachします
  7. Principal entityとして、ユーザー”data_analyst”を選択して、Attach policyを選択します

カスタム認証プロバイダを実装する

IAM設定が完了したら、カスタム認証プロバイダを実装して、EMRクラスターがS3バケットの”research-data”に格納されているオブジェクトにアクセスできるようにします。

次に、JavaプロパティファイルからIAMユーザーのdata_analyst認証情報を読み取るカスタム認証プロバイダのサンプルコードを示します。 バケットURIがresearch@yourcompany.comアカウントのバケットを指している場合、プロバイダは一時的な認証情報を取得する役割を引き受けます。 一方、バケットURIがユーザー自身のアカウントのバケットを指している場合は、EMRクラスターのEC2インスタンスプロファイルから認証情報が読み取られます。

import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.conf.Configuration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
import com.amazonaws.services.securitytoken.model.AssumeRoleResult;

final class MyAWSCredentialsProviderWithUri implements AWSCredentialsProvider, Configurable {

	private Configuration configuration;
	private static AWSCredentials credentials, iamUserCredentials;
	private static final String role_arn =
			"arn:aws:iam::123456789012:role/demo-role";
	
	//Specifying the S3 bucket URI for the other account
	private static final String bucket_URI = "s3://research-data/";

	public MyAWSCredentialsProviderWithUri(URI uri, Configuration conf) {
		this.configuration = conf;
		if (uri.toString().startsWith(bucket_URI)) {
			try {
				//Reading the credentials of the IAM users from Java properties file
				iamUserCredentials = new PropertiesCredentials
						(MyAWSCredentialsProviderWithUri.class.getResourceAsStream("Credentials.properties"));
			} catch (IOException e) {
				e.printStackTrace();
			}
			AWSSecurityTokenServiceClient stsClient = new
					AWSSecurityTokenServiceClient(iamUserCredentials);
			//Assuming the role in the other account to obtain temporary credentials
			AssumeRoleRequest assumeRequest = new AssumeRoleRequest()
			.withRoleArn(role_arn)
			.withDurationSeconds(3600)
			.withRoleSessionName("demo");
			AssumeRoleResult assumeResult =
					stsClient.assumeRole(assumeRequest);
			BasicSessionCredentials temporaryCredentials =
					new BasicSessionCredentials(
							assumeResult.getCredentials().getAccessKeyId(),
							assumeResult.getCredentials().getSecretAccessKey(),
							assumeResult.getCredentials().getSessionToken());
			credentials = temporaryCredentials;
		} else {
			//Extracting the credentials from EC2 metadata service
			Boolean refreshCredentialsAsync = true;
			InstanceProfileCredentialsProvider creds = new InstanceProfileCredentialsProvider
					(refreshCredentialsAsync);
			credentials = creds.getCredentials();
		}
	}

	@Override
	public AWSCredentials getCredentials() {
		//Returning the credentials to EMRFS to make S3 API calls
		return credentials;
	}

	@Override
	public void refresh() {}

	@Override
	public void setConf(Configuration conf) {
	}

	@Override
	public Configuration getConf() {
		return configuration;
	}
}

上記のコードから気づかれるように、 “Credentials.properties”ファイルを使用して、IAMユーザーのdata_analyst認証情報を読み込みます。そのファイルの内容は次のとおりです。

accessKey = AKIAxxxxxxxxxxxxxxxx
secretKey = iXbXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

今度は、クロスアカウントS3アクセスのためにEMRクラスターが使用するJARファイルにコードをコンパイルしてパッケージ化します。 次の手順を実行します。

  1. SSHを実行中のEMRクラスターのマスターノードに追加し、Hadoopユーザーのホームディレクトリに移動し、MyAWSCredentialsProviderという名前のフォルダーを作成し、フォルダー内に次のファイルを追加します。
    • MyAWSCredentialsProviderWithUri.java
    • Credentials.properties
  2. フォルダ内で、次のコマンドを実行してJavaコードをコンパイルしてJARファイルにパッケージします
  3. $ javac -cp $(hadoop classpath) MyAWSCredentialsProviderWithURI.java
    $ jar -cvf MyAWSCredentialsProviderWithUri.jar MyAWSCredentialsProviderWithUri.class Credentials.properties
  4. 生成されたJARファイルをS3バケットにアップロードします
  5. $ aws s3 cp MyAWSCredentialsProviderWithUri.jar s3://<YOUR-BUCKET>/ 

上記の手順を実行した後、次の内容のブートストラップアクションスクリプト(configure_emrfs_lib.sh)を作成します

sudo aws s3 cp s3://<YOUR-BUCKET>/MyAWSCredentialsProviderWithUri.jar /usr/share/aws/emr/emrfs/auxlib/

そして、新しいEMRクラスターを立ち上げてください。 emrfs-siteコンフィグレーション分類でfs.s3.customAWSCredentialsProviderを設定することによって、認証プロバイダの完全なクラス名を指定します。 カスタムブートストラップアクション(configure_emrfs_lib.sh)を追加すると、JARファイルがクラスターのすべてのノード上のEMRFSの補助ライブラリフォルダにコピーされます。

AWS CLIを使用して、次のコマンドを実行して、カスタム認証プロバイダで設定されたEMRクラスターを起動します。 この設定には、カスタムJARファイルを関連ディレクトリに配置するためのブートストラップアクションも含まれています。

aws emr create-cluster --applications Name=Hive --bootstrap-actions '[{"Path":"s3://<YOUR-BUCKET>/configure_emrfs_lib.sh","Name":"Custom action"}]' --ec2-attributes '{"KeyName":"<YOUR-KEY-PAIR>","InstanceProfile":"EMR_EC2_DefaultRole","SubnetId":"subnet-xxxxxxxx","EmrManagedSlaveSecurityGroup":"sg-xxxxxxxx","EmrManagedMasterSecurityGroup":"sg-xxxxxxxx"}' --service-role EMR_DefaultRole --enable-debugging --release-label emr-5.4.0 --log-uri 's3n://<YOUR-BUCKET/' --name 'test-awscredentialsprovider-emrfs' --instance-type=m3.xlarge --instance-count 3  --configurations '[{"Classification":"emrfs-site","Properties":{"fs.s3.customAWSCredentialsProvider":"MyAWSCredentialsProviderWithUri"},"Configurations":[]}]'

研究部門アカウントのデータにアクセスする機能を備えたクラスターがあるので、Hive、Pig、SparkなどのEMRで利用可能なさまざまなデータ処理アプリケーションや、YARNのMapReduceなどの大きなデータ処理モデルを使用してデータを分析できます。

PrestoやOozieのように、EMRFSを使用せずS3とやり取りするアプリケーションもEMRにはあります。このシナリオでは、これらのアプリケーションを使用することはできません。

まとめ

このポストでは、EMRFSがS3へのAPI呼び出しに署名するための認証情報を取得する方法について説明しました。 EMRFS用のカスタム認証プロバイダを実装して、デフォルトの認証プロバイダを使用してアクセスできないS3バケット内のオブジェクトにアクセスする方法について説明しました。 また、クロスアカウントS3 APIアクセスを設定する方法と、カスタム認証情報を提供するためにEMRFSを使用する方法についても説明しました。これにより、EMR上で動作する大規模なデータアプリケーションが、異なるアカウントに属するS3バケットに格納されたデータにアクセスすることができます。

EMRFSカスタム認証プロバイダの使用の詳細については、EMRFSのAWSCredentialsProviderの作成を参照してください。

ご質問やご提案がありましたら、ぜひコメントをお寄せください。

原文:Securely Analyze Data from Another AWS Account with EMRFS(翻訳:半場光晴)