LoginSignup
0
0

More than 1 year has passed since last update.

DatabricksにおけるAssumeRoleポリシーを用いたS3バケットに対するセキュアなクロスアカウントアクセス

Last updated at Posted at 2021-11-29

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を作成し、ポリシーをアタッチする

  1. アカウントAでMyRoleAというロールを作成します。インスタンスプロファイルのARNはarn:aws:iam::<deployment-acct-id>:instance-profile/MyRoleAとなります。

  2. アカウント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"
          ]
        }
      ]
    }
    
  3. 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:CreateKeyPairec2:DeleteKeyPairを削除することができます。アカウントバージョンが不明の場合には、Databricks担当者にお問い合わせください。

ステップ2: アカウントBでMyRoleBを作成し、ポリシーをアタッチする

  1. MyRoleBというロールを作成します。ロールのARNはarn:aws:iam::<bucket-owner-acct-id>:role/MyRoleBとなります。

  2. アカウント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"
        }
      ]
    }
    
  3. バケット<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でクラスターを設定する

  1. クラスターを選択、作成します。

  2. Advanced Optionsセクションを展開します。

  3. Instancesタブで、MyRoleAインスタンスプロファイルを選択します。

  4. Sparkタブで、オプションとしてassumeRoleの認証タイプと、ロールを委任するMyRoleBのARNを指定します。

    注意
    Databricksランタイム 7.3 LTS以降では、open-source Hadoop optionsを用いたS3Aファイルシステムの設定をサポートしています。グローバルプロパティあるいはバケットごとのプロパティを設定することができます。

    すべてのバケットに対して設定するには:

    Bash
    fs.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
    

    特定のバケットに設定するには:

    Bash
    fs.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
    
  5. クラスターを起動します。

  6. ノートブックをクラスターにアタッチします。

  7. 以下のコマンドを実行して<s3-bucket-name>にアクセスできることを検証します。

    Python
    dbutils.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
  }
}

Databricks 無料トライアル

Databricks 無料トライアル

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0