DatabricksにおけるクロスアカウントS3アクセス(実践編)

こちらを昨年書きましたが、より詳細な手順にまとめます。

https://qiita.com/taka_yayoi/items/a534bdcdfc37e1142c93

# 全体像

以下では、AWSアカウントIDが`<deployment-acct-id>`であるDatabricksをデプロイしたAWSアカウントAと、AWSアカウントIDが`<bucket-owner-acct-id>`であるアクセス先のS3バケットがあるAWSアカウントBを考えます。

![Screenshot 2023-01-19 at 15.09.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/140ac95c-a1b3-1da8-b707-ddad1a5612f7.png)

この作業では、以下のロールARN、インスタンスプロファイルのARNを使用します。

- `arn:aws:iam::<deployment-acct-id>:role/deployment-acct-cross-account-s3-role`
- `arn:aws:iam::<deployment-acct-id>:instance-profile/deployment-acct-cross-account-s3-role`
- `arn:aws:iam::<bucket-owner-acct-id>:role/bucket-owner-acct-s3-access-role`

# DatabricksがデプロイされているAWSアカウントでの作業(1回目)

## アクセス先S3があるAWSアカウントにアクセスするIAMロールの作成

1. DatabricksがデプロイされているAWSアカウントでAWSマネジメントコンソールにログインします。
1. **IAM > ロール**に移動し、**ロールを作成**をクリックします。
1. **信頼されたエンティティタイプ**では**AWSのサービス**、**一般的なユースケース**で**EC2**を選択し、**次へ**をクリックします。
![Screenshot 2023-01-19 at 13.45.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0507efc6-25d2-8e9a-db73-05977109f394.png)
1. ポリシーはあとで設定するので、ロール名を付けてロールを作成します。ここでは`deployment-acct-cross-account-s3-role`というロールとしています。
![Screenshot 2023-01-19 at 13.58.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/67a53024-9394-51df-cc53-d4dc836f60c4.png)
1. ロール`deployment-acct-cross-account-s3-role`のARNをメモしておきます。


# アクセス先S3があるAWSアカウントでの作業

## S3バケットの作成

1. アクセス先S3があるAWSアカウントでAWSマネジメントコンソールにログインします。
1. S3バケットが存在しない場合には作成します。ここでは`ty-databricks-cross-account-bucket`というバケットを作成します。

## S3にアクセスするロールの作成

1. **IAM > ロール**に移動し、**ロールを作成**をクリックします。
1. **信頼されたエンティティタイプ**では**AWSのサービス**、**一般的なユースケース**で**EC2**を選択し、**次へ**をクリックします。
1. ポリシーはあとで設定するので、ロール名を付けてロールを作成します。ここでは`bucket-owner-acct-s3-access-role`というロールとしています。
![Screenshot 2023-01-19 at 14.02.38.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/99d9472e-d932-524b-b955-c9f36bf2517d.jpeg)
1. 作成した`bucket-owner-acct-s3-access-role`ロールにアクセスし、**信頼関係**を開き、**信頼ポリシーを編集**をクリックします。
![Screenshot 2023-01-19 at 14.03.41.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/6f2848a6-2476-a6b8-afce-ac83452992f1.jpeg)
1. 以下の信頼ポリシーを入力します。これによって、DatabricksをデプロイしたAWSアカウントAのロール`deployment-acct-cross-account-s3-role`がこのロールに対してAssumeRoleアクションを実行できるようになります。

    ```json:JSON
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::<deployment-acct-id>:role/deployment-acct-cross-account-s3-role"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }
    ```

## S3のバケットポリシーの設定

上のロールによるS3へのアクセスを許可します。

1. S3バケット`ty-databricks-cross-account-bucket`にアクセスし、**アクセス許可**を開きます。
1. **バケットポリシー**を編集します。
1. 以下の内容を入力して保存します。これによって、ロール`bucket-owner-acct-s3-access-role`がこのS3バケットを操作できるようになります。

    ```json:JSON
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::<bucket-owner-acct-id>:role/bucket-owner-acct-s3-access-role"
                },
                "Action": [
                    "s3:GetBucketLocation",
                    "s3:ListBucket"
                ],
                "Resource": "arn:aws:s3:::ty-databricks-cross-account-bucket"
            },
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::<bucket-owner-acct-id>:role/bucket-owner-acct-s3-access-role"
                },
                "Action": [
                    "s3:PutObject",
                    "s3:PutObjectAcl",
                    "s3:GetObject",
                    "s3:DeleteObject"
                ],
                "Resource": "arn:aws:s3:::ty-databricks-cross-account-bucket/*"
            }
        ]
    }
    ```

# DatabricksがデプロイされているAWSアカウントでの作業(2回目)

## アクセス先S3があるAWSアカウントにアクセスするIAMロールのポリシーの更新

1. DatabricksがデプロイされているAWSアカウントでAWSマネジメントコンソールにログインします。
1. **IAM > ロール**に移動し、ロール`deployment-acct-cross-account-s3-role`にアクセスします。
1. **許可を追加**、**インラインポリシーを作成**をクリックします。
![Screenshot 2023-01-19 at 14.20.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/575d89ce-31ee-1834-18e2-16eb438186de.png)
1. **JSON**を開き、以下の内容を入力します。

    ```json:JSON
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "Stmt1487884001000",
          "Effect": "Allow",
          "Action": [
            "sts:AssumeRole"
          ],
          "Resource": [
            "arn:aws:iam::<bucket-owner-acct-id>:role/bucket-owner-acct-s3-access-role"
          ]
        }
      ]
    }
    ```

1. 名前をつけてポリシーを作成します。ここでは、`deployment-acct-cross-account-s3-policy`というポリシーにしています。これによって、ロール`deployment-acct-cross-account-s3-role`がS3のあるAWSアカウントのロール`bucket-owner-acct-s3-access-role`に対して、AssumeRoleアクションを実行できるようになります。

## クロスアカウントIAMポリシーの更新

最後に、Databricksサービスからロール`deployment-acct-cross-account-s3-role`を利用できるようにします。

1. Databricksデプロイ時に作成したクロスアカウントIAMロールにアクセスします。
1. ポリシーを編集します。以下のブロックをポリシーに追加します。これによって、Databricksからロール`deployment-acct-cross-account-s3-role`にアクセスできるようになります。

    ```json:JSON
    {
        "Effect": "Allow",
        "Action": "iam:PassRole",
        "Resource": "arn:aws:iam::<deployment-acct-id>:role/deployment-acct-cross-account-s3-role"
     }
    ```

## インスタンスプロファイルARNの取得

ロール`deployment-acct-cross-account-s3-role`にアクセスして、**インスタンスプロファイルの ARN**をメモしておきます。

# Databricksでの作業

## インスタンスプロファイルの作成

1. Databricksワークスペースにログインし、**管理コンソール**にアクセスします。
1. **Instance Profiles**にアクセスし、**+インスタンスプロファイルを追加**をクリックします。
![Screenshot 2023-01-19 at 14.33.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e2fa2ef9-f022-2e23-c2d7-529ea3832c34.png)
1. **インスタンスプロファイルARN**に、ロール`deployment-acct-cross-account-s3-role`のインスタンスプロファイルARNを入力して、**追加**をクリックします。
![Screenshot 2023-01-19 at 14.34.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f6ab6496-8833-b994-00d7-5e3d1bd3417a.png)

    :::note
    **注意**
    インスタンスプロファイルを追加する際にエラーが発生する場合、上述のIAMの設定が適切に行われていない可能性があります。IAMのポリシーを確認してください。
   :::

1. インスタンスプロファイルが追加されました。
![Screenshot 2023-01-19 at 14.36.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/acd6f3c0-8288-cff9-3c47-ed7bc2f60f4f.png)

## クラスターの設定

上のステップで追加したインスタンスプロファイルとSpark設定を行います。

1. クラスターにアクセスし、**編集**をクリックします。
1. **インスタンスプロファイル**で上のステップで追加したインスタンスプロファイルを選択します。
![Screenshot 2023-01-19 at 14.39.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/4759a71c-ad55-a25b-a7ee-88ee2343dfe1.png)
1. **高度なオプション**を展開して、**Spark**にアクセスします。
1. 以下の行を**追加**します。

    ```
    fs.s3a.assumed.role.arn arn:aws:iam::<bucket-owner-acct-id>:role/bucket-owner-acct-s3-access-role
    fs.s3a.aws.credentials.provider org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider
    ```
1. **確認**をクリックして編集を終了します。
1. クラスターを起動します。

## 動作確認

一旦ここで接続を確認します。

1. アクセス先のS3バケットが空の場合は、適当なファイルをアップロードしておきます。
1. 上で設定したクラスターにノートブックをアタッチします。
1. 以下のセルを実行します。

    ```py:Python
    display(dbutils.fs.ls("s3a://ty-databricks-cross-account-bucket"))
    ```

1. 以下のようにファイル一覧が表示されれば成功です。
![Screenshot 2023-01-19 at 14.50.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e30a5157-e7b0-41ba-cbf5-49384fda469d.png)

## マウントポイントの作成

上の通り、直パスでもアクセスは可能ですが、マウントポイントを作成することも可能です。

```py:Python
# S3バケットのURL
bucket_url = "s3a://ty-databricks-cross-account-bucket"
# マウントポイント名
mount_point_name = "cross-account-bucket"
# S3バケットのAWSアカウントにあるS３アクセス用IAMロールのARN
s3_access_arn = "arn:aws:iam::<bucket-owner-acct-id>:role/bucket-owner-acct-s3-access-role"
```

```py:Python
dbutils.fs.mount(bucket_url, f"/mnt/{mount_point_name}",
  extra_configs = {
    "fs.s3a.credentialsType": "AssumeRole",
    "fs.s3a.stsAssumeRole.arn": s3_access_arn,
    "fs.s3a.canned.acl": "BucketOwnerFullControl",
    "fs.s3a.acl.default": "BucketOwnerFullControl"
  }
)
```

これで、`/mnt/cross-account-bucket/`というマウントポイント経由でクロスアカウントのS3バケットにアクセスすることができるようになります。このマウントポイントは明示的にアンマウントしない限り永続化されます。

```py:Python
display(dbutils.fs.ls("/mnt/cross-account-bucket/"))
```
![Screenshot 2023-01-19 at 14.53.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/05b46c85-3762-84e1-e8d4-4125874d4ac7.png)

# 参考資料

- [DatabricksにおけるAssumeRoleポリシーを用いたS3バケットに対するセキュアなクロスアカウントアクセス \- Qiita](https://qiita.com/taka_yayoi/items/c971c7c5411df054b621)
- [AWS iam:PassRoleって何だ \- karakaram\-blog](https://www.karakaram.com/granting-iam-user-permission-to-pass-iam-role-to-aws-services/#why-iam-passrole)
- [Access cross\-account S3 buckets with an AssumeRole policy \| Databricks on AWS](https://docs.databricks.com/archive/admin-guide/assume-role.html#step-1-in-account-a-create-role-myrolea-and-attach-policies)
- [Mounting cloud object storage on Databricks \| Databricks on AWS](https://docs.databricks.com/dbfs/mounts.html#mount-a-bucket-using-instance-profiles-with-the-assumerole-policy)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)