Secure access to S3 buckets across accounts using instance profiles with an AssumeRole policy | Databricks on AWS [2022/12/13時点]の翻訳です。
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
AWSにおいては、あるアカウントの計算処理が別のアカウントのバケットにアクセスできるように、クロスアカウントアクセスをセットアップすることができます。アクセスを許可する方法の一つは、Databricksにおけるインスタンスプロファイルを用いたS3バケットへのセキュアなアクセスで説明されているように、アカウントに対して、別のアカウントのバケットへのアクセスを直接許可するというものです。バケットへのアクセスを許可する別の方法は、アカウントが別のアカウントの ロールの一時クレデンシャルを要求する(assume a role) ことを許可するというものです。
アカウントIDが<deployment-acct-id>
であるAWSアカウントAと、アカウントIDが<bucket-owner-acct-id>
であるAWSアカウントBを考えます。アカウントAはDatabricksにサインアップする際に用いたものであり、EC2サービスとDBFSルートバケットはこのアカウントによって管理されています。アカウントBはバケット<s3-bucket-name>
を保有しています。
本書では、アカウントAがアカウントBのロールとして<s3-bucket-name>
のファイルにアクセスするために、AWSのAssumeRoleアクションを使用するように設定するステップを説明します。このアクセスを有効にするために、アカウントA、アカウントB、そしてDatabricksのAdmin Consoleでの設定が必要となります。また、バケットにアクセスするノートブックや、Databricksクラスターに設定を行う必要があります。
要件
- DatabricksをデプロイしたAWSアカウントとS3バケットのAWSアカウントでIAMロール、ポリシーにアクセスできるAWS管理者
- ターゲットのS3バケット
- S3バケットに対する暗号化を有効化する場合には、設定で指定されるKMSキーに対するKey Userとしてインスタンスプロファイルを追加する必要があります。s3a://パスに対するKMS暗号化の設定をご覧ください。
ステップ1: アカウントAでMyRoleA
を作成し、ポリシーをアタッチする
-
アカウントAで
MyRoleA
というロールを作成します。インスタンスプロファイルのARNはarn:aws:iam::<deployment-acct-id>:instance-profile/MyRoleA
となります。 -
アカウントAのロールが、アカウントBのロール
MyRoleB
の一時クレデンシャルの要求 (AssumeRole)を許可するポリシーを作成します。ポリシーをMyRoleA
にアタッチします。をクリックし、ポリシーに貼り付けます。JSON{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1487884001000", "Effect": "Allow", "Action": [ "sts:AssumeRole" ], "Resource": [ "arn:aws:iam::<bucket-owner-acct-id>:role/MyRoleB" ] } ] }
-
Databricksをデプロイする際に作成したクロスアカウントIAMポリシーを更新します。
MyRoleA
に対するiam:PassRole
アクションを追加します。JSON{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1403287045000", "Effect": "Allow", "Action": [ "ec2:AssociateDhcpOptions", "ec2:AssociateIamInstanceProfile", "ec2:AssociateRouteTable", "ec2:AttachInternetGateway", "ec2:AttachVolume", "ec2:AuthorizeSecurityGroupEgress", "ec2:AuthorizeSecurityGroupIngress", "ec2:CancelSpotInstanceRequests", "ec2:CreateDhcpOptions", "ec2:CreateInternetGateway", "ec2:CreateKeyPair", "ec2:CreateRoute", "ec2:CreateSecurityGroup", "ec2:CreateSubnet", "ec2:CreateTags", "ec2:CreateVolume", "ec2:CreateVpc", "ec2:CreateVpcPeeringConnection", "ec2:DeleteInternetGateway", "ec2:DeleteKeyPair", "ec2:DeleteRoute", "ec2:DeleteRouteTable", "ec2:DeleteSecurityGroup", "ec2:DeleteSubnet", "ec2:DeleteTags", "ec2:DeleteVolume", "ec2:DeleteVpc", "ec2:DescribeAvailabilityZones", "ec2:DescribeIamInstanceProfileAssociations", "ec2:DescribeInstanceStatus", "ec2:DescribeInstances", "ec2:DescribePrefixLists", "ec2:DescribeReservedInstancesOfferings", "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroups", "ec2:DescribeSpotInstanceRequests", "ec2:DescribeSpotPriceHistory", "ec2:DescribeSubnets", "ec2:DescribeVolumes", "ec2:DescribeVpcs", "ec2:DetachInternetGateway", "ec2:DisassociateIamInstanceProfile", "ec2:ModifyVpcAttribute", "ec2:ReplaceIamInstanceProfileAssociation", "ec2:RequestSpotInstances", "ec2:RevokeSecurityGroupEgress", "ec2:RevokeSecurityGroupIngress", "ec2:RunInstances", "ec2:TerminateInstances" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": "iam:PassRole", "Resource": [ "arn:aws:iam::<deployment-acct-id>:role/MyRoleA" ] } ] }
注意
お使いのアカウントがDatabricksプラットフォームのE2バージョンの場合、ec2:CreateKeyPair
とec2:DeleteKeyPair
を削除することができます。アカウントバージョンが不明の場合には、Databricks担当者にお問い合わせください。
ステップ2: アカウントBでMyRoleB
を作成し、ポリシーをアタッチする
-
MyRoleB
というロールを作成します。ロールのARNはarn:aws:iam::<bucket-owner-acct-id>:role/MyRoleB
となります。 -
アカウントAのロール
MyRoleA
が、アカウントBのロールを引き受けられるように、MyRoleB
の信頼リレーションシップを編集します。IAM > Roles > MyRoleB > Trust relationships > Edit trust relationshipを選択し、以下を入力します。JSON{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::<deployment-acct-id>:role/MyRoleA" ] }, "Action": "sts:AssumeRole" } ] }
-
バケット
<s3-bucket-name>
に対するバケットポリシーを作成します。S3 ><s3-bucket-name>
> Permissions > Bucket Policyを選択します。バケットポリシーにロール(プリンシパル)MyRoleB
を含めます。JSON{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::<bucket-owner-acct-id>:role/MyRoleB" ] }, "Action": [ "s3:GetBucketLocation", "s3:ListBucket" ], "Resource": "arn:aws:s3:::<s3-bucket-name>" }, { "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::<bucket-owner-acct-id>:role/MyRoleB" ] }, "Action": [ "s3:PutObject", "s3:PutObjectAcl", "s3:GetObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::<s3-bucket-name>/*" } ] }
ティップス
Principal error
が表示された場合には、Trust relationshipだけを変更したことを確認してください。
ステップ3: MyRoleAをDatabricksワークスペースに追加する
DatabricksのAdmin Consoleで、ステップ1で取得したMyRoleA
のインスタンスプロファイルARNarn:aws:iam::<deployment-acct-id>:instance-profile/MyRoleA
を用いてMyRoleAのインスタンスプロファイルをDatabricksに追加します。
ステップ4: MyRoleAでクラスターを設定する
-
クラスターを選択、作成します。
-
Advanced Optionsセクションを展開します。
-
Instancesタブで、
MyRoleA
のインスタンスプロファイルを選択します。 -
Sparkタブで、オプションとして
assumeRole
の認証タイプと、ロールを委任するMyRoleB
のARNを指定します。注意
Databricksランタイム 7.3 LTS以降では、open-source Hadoop optionsを用いたS3Aファイルシステムの設定をサポートしています。グローバルプロパティあるいはバケットごとのプロパティを設定することができます。すべてのバケットに対して設定するには:
Bashfs.s3a.aws.credentials.provider org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider fs.s3a.assumed.role.arn arn:aws:iam::<bucket-owner-account-id>:role/MyRoleB
特定のバケットに設定するには:
Bashfs.s3a.bucket.<s3-bucket-name>.aws.credentials.provider org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider fs.s3a.bucket.<s3-bucket-name>.assumed.role.arn arn:aws:iam::<bucket-owner-account-id>:role/MyRoleB
-
クラスターを起動します。
-
ノートブックをクラスターにアタッチします。
-
以下のコマンドを実行して
<s3-bucket-name>
にアクセスできることを検証します。Pythondbutils.fs.ls("s3a://<s3-bucket-name>/")
ステップ5: AssumeRoleを用いてクロスアカウントバケットをマウントする
リモートデータにアクセスする際、相対パスを使えるようにクロスアカウントバケットをマウントすることができます。Mount a bucket using instance profiles with the AssumeRole policyをご覧ください。
Terraformを用いた設定の自動化
自動でAWS IAMロールとクラスターへのアタッチメントを設定するために、Databricks Terraformプロバイダーを活用することができます。
このサンプル設定に示すように最初に2つの変数を設定します。
variable "prefix" {
default = "changeme"
}
variable "databricks_account_id" {
description = "Account ID. You can get your account ID in the bottom left corner of the account console. See https://accounts.cloud.databricks.com"
}
aws_s3_bucketを用いてバケットを作成します。
resource "aws_s3_bucket" "ds" {
bucket = "${var.prefix}-ds"
acl = "private"
versioning {
enabled = false
}
force_destroy = true
tags = merge(var.tags, {
Name = "${var.prefix}-ds"
})
}
aws_iam_roleを用いてデータアクセスのためのIAMロールを作成します。
data "aws_iam_policy_document" "assume_role_for_ec2" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
identifiers = ["ec2.amazonaws.com"]
type = "Service"
}
}
}
resource "aws_iam_role" "data_role" {
name = "${var.prefix}-first-ec2s3"
description = "(${var.prefix}) EC2 Assume Role role for S3 access"
assume_role_policy = data.aws_iam_policy_document.assume_role_for_ec2.json
tags = var.tags
}
このバケットにフルアクセスを許可するdatabricks_aws_bucket_policyを用いたバケットポリシーを作成します。aws_s3_bucket_policyを用いて新規に作成したバケットにインラインのS3バケットポリシーを適用します。
data "databricks_aws_bucket_policy" "ds" {
provider = databricks.mws
full_access_role = aws_iam_role.data_role.arn
bucket = aws_s3_bucket.ds.bucket
}
resource "aws_s3_bucket_policy" "ds" {
bucket = aws_s3_bucket.ds.id
policy = data.databricks_aws_bucket_policy.ds.json
}
aws_iam_policyを用いてDatabricksがデータロールのリストをパスできるクロスアカウントポリシーを作成します。
data "databricks_aws_crossaccount_policy" "this" {
pass_roles = [aws_iam_role.data_role.arn]
}
resource "aws_iam_policy" "cross_account_policy" {
name = "${var.prefix}-crossaccount-iam-policy"
policy = data.databricks_aws_crossaccount_policy.this.json
}
aws_iam_role_policy_attachmentを用いた信頼関係の設定を通じてDatabrikcsがあなたのアカウント内でアクションを実行することを許可します。
data "databricks_aws_assume_role_policy" "this" {
external_id = var.databricks_account_id
}
resource "aws_iam_role" "cross_account" {
name = "${var.prefix}-crossaccount-iam-role"
assume_role_policy = data.databricks_aws_assume_role_policy.this.json
description = "Grants Databricks full access to VPC resources"
}
resource "aws_iam_role_policy_attachment" "cross_account" {
policy_arn = aws_iam_policy.cross_account_policy.arn
role = aws_iam_role.cross_account.name
}
E2 workspace setupにクロスアカウントロールを登録します。
resource "databricks_mws_credentials" "this" {
provider = databricks.mws
account_id = var.databricks_account_id
credentials_name = "${var.prefix}-creds"
role_arn = aws_iam_role.cross_account.arn
}
ワークスペースが作成されたら、databricks_instance_profileとしてaws_iam_instance_profileのデータロールを登録します。
resource "aws_iam_instance_profile" "this" {
name = "${var.prefix}-first-profile"
role = aws_iam_role.data_role.name
}
resource "databricks_instance_profile" "ds" {
instance_profile_arn = aws_iam_instance_profile.this.arn
}
最後のステップとして、指定されたインスタンスプロファイルを用いてマウントポイント/mnt/experiments
とクラスターを作成します。
resource "databricks_aws_s3_mount" "this" {
instance_profile = databricks_instance_profile.ds.id
s3_bucket_name = aws_s3_bucket.this.bucket
mount_name = "experiments"
}
data "databricks_node_type" "smallest" {
local_disk = true
}
data "databricks_spark_version" "latest_lts" {
long_term_support = true
}
resource "databricks_cluster" "shared_autoscaling" {
cluster_name = "Shared Autoscaling"
spark_version = data.databricks_spark_version.latest_lts.id
node_type_id = data.databricks_node_type.smallest.id
autotermination_minutes = 20
autoscale {
min_workers = 1
max_workers = 50
}
aws_attributes {
instance_profile_arn = databricks_instance_profile.ds.id
}
}