

# 付録
<a name="appendix"></a>

## マルチテナンシー比較
<a name="multi-tenancy-comparison"></a>

表2 — マルチテナンシー比較**


|  マルチドメイン  |  マルチアカウント  |  単一のドメイン内の属性ベースのアクセス制御 (ABAC)  | 
| --- | --- | --- | 
| リソースの分離は、タグを使用して行われます。SageMaker AI Studio は、すべてのリソースにドメイン ARN およびユーザープロファイル/スペース ARN を自動的にタグ付けします。 | 各テナントはそれぞれのアカウントにあるため、リソースは完全に分離されます。 | リソースの分離は、タグを使用して行われます。ユーザーは、ABAC 用に作成されたリソースのタグ付けを管理する必要があります。 | 
| List API をタグで制限することはできません。リソースの UI フィルタリングは共有スペースで行われますが、AWS CLI または Boto3 SDK を介して行われた List API コールでは、リージョン全体のリソースが一覧表示されます。 | テナントはそれぞれの専用アカウントにあるため、List API の分離も可能です。 | List API をタグで制限することはできません。AWS CLI または Boto3 SDK を介して行われた List API コールでは、リージョン全体のリソースが一覧表示されます。 | 
| テナントごとの SageMaker AI Studio のコンピューティングコストとストレージコストは、ドメイン ARN をコスト配分タグとして使用することで簡単にモニタリングできます。 | テナントごとの SageMaker AI Studio のコンピューティングコストとストレージコストは、専用アカウントで簡単にモニタリングできます。 | テナントあたりの SageMaker AI Studio コンピューティングコストは、カスタムタグを使用して計算する必要があります。<br /> すべてのテナントが同じ EFS ボリュームを共有するため、SageMaker AI Studio のストレージコストをドメインごとにモニタリングすることはできません。 | 
| Service Quotas はアカウントレベルで設定されるため、1 つのテナントですべてのリソースを使用することができます。 | Service Quotas は、テナントごとにアカウントレベルで設定できます。 | Service Quotas はアカウントレベルで設定されるため、1 つのテナントですべてのリソースを使用することができます。 | 
| Infrastructure as Code (IaC) または Service Catalog を使用して、複数のテナントへのスケーリングを実現できます。 | 複数のテナントへのスケーリングには、Organizations と複数のアカウントの供給が含まれます。 | スケーリングでは新しいテナントごとにテナント固有のロールが必要で、ユーザープロファイルではテナント名を手動でタグ付けする必要があります。 | 
| テナント内のユーザー間のコラボレーションは、共有スペースを通じて行えます。 | テナント内のユーザー間のコラボレーションは、共有スペースを通じて行えます。 | すべてのテナントは、コラボレーションのために同じ共有スペースにアクセスできます。 | 

## SageMaker AI Studio ドメインのバックアップとリカバリ
<a name="sagemaker-studio-domain-backup-and-recovery"></a>

EFS を誤って削除した場合や、ネットワークや認証の変更によりドメインを再作成する必要がある場合は、以下の手順に従ってください。

### オプション 1: EC2 を使用して既存の EFS からバックアップする
<a name="option-1"></a>

#### SageMaker Studio ドメインのバックアップ
<a name="sagemaker-studio-domain-backup"></a>

1. SageMaker Studio のユーザープロファイルとスペースを一覧表示します ([CLI](https://docs.aws.amazon.com/cli/latest/reference/sagemaker/list-user-profiles.html)、[SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.list_user_profiles))。

1. ユーザープロファイル/スペースを EFS の UID にマップします。

   1. ユーザー/スペースのリスト内のユーザーごとに、ユーザープロファイル/スペースを記述します ([CLI](https://docs.aws.amazon.com/cli/latest/reference/sagemaker/describe-user-profile.html)、[SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.describe_user_profile))。

   1. ユーザープロファイル/スペースを `HomeEfsFileSystemUid` にマップします。

   1. ユーザー別に実行ロールが異なる場合は、ユーザープロファイルを `UserSettings['ExecutionRole']` にマップします。

   1. スペースのデフォルトの実行ロールを特定します。

1. 新しいドメインを作成し、スペースのデフォルトの実行ロールを指定します。

1. ユーザープロファイルとスペースを作成します。
   + ユーザーリスト内のユーザーごとに、実行ロールのマッピングを使用してユーザープロファイルを作成します ([CLI](https://docs.aws.amazon.com/cli/latest/reference/sagemaker/create-user-profile.html)、[SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_user_profile))。

1. 新しい EFS と UID のマッピングを作成します。

   1. ユーザーリスト内のユーザーごとに、ユーザープロファイルを記述します ([CLI](https://docs.aws.amazon.com/cli/latest/reference/sagemaker/describe-user-profile.html)、[SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.describe_user_profile))。

   1. ユーザープロファイルを `HomeEfsFileSystemUid` にマップします。

1. 必要に応じて、すべてのアプリ、ユーザープロファイル、スペースを削除し、その後にドメインを削除します。

#### EFS のバックアップ
<a name="efs-backup"></a>

EFS をバックアップするには、次の手順に従います。

1. EC2 インスタンスを起動し、古い SageMaker Studio ドメインのインバウンド/アウトバウンドセキュリティグループを、新しい EC2 インスタンスにアタッチします (ポート 2049 で TCP 経由の NFS トラフィックを許可します)。「[VPC 内の SageMaker Studio ノートブックを外部リソースに接続する](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html#:~:text=NFS%20traffic%20over%20TCP%20on%20port%202049%20between%20the%20domain%20and%20the%20Amazon%20EFS%20volume.)」を参照してください。

1. SageMaker Studio の EFS ボリュームを新しい EC2 インスタンスにマウントします。「[EFS ファイルシステムをマウントする](https://docs.aws.amazon.com/efs/latest/ug/mounting-fs.html)」を参照してください。

1. ファイルを EBS ローカルストレージにコピーします (`>sudo cp -rp /efs /studio-backup:`)。

   1. 新しいドメインセキュリティグループを EC2 インスタンスにアタッチします。

   1. 新しい EFS ボリュームを EC2 インスタンスにマウントします。

   1. ファイルを新しい EFS ボリュームにコピーします。

   1. ユーザーのコレクション内のユーザーごとに以下の操作を行います。

      1. ディレクトリを作成します (`mkdir new_uid`)。

      1. 古い UID ディレクトリから新しい UID ディレクトリにファイルをコピーします。

      1. すべてのファイルの所有権を変更します (`chown <new_UID>`)。

### オプション 2: S3 とライフサイクル設定を使用して既存の EFS からバックアップする
<a name="option-2"></a>

1. 「[Amazon Linux 2 を使用して Amazon SageMaker ノートブックインスタンスに作業内容を移行する](https://aws.amazon.com/blogs/machine-learning/migrate-your-work-to-amazon-sagemaker-notebook-instance-with-amazon-linux-2/)」を参照します。

1. バックアップ用の S3 バケット (`>studio-backup` など) を作成します。

1. 実行ロールを持つすべてのユーザープロファイルを一覧表示します。

1. 現在の SageMaker Studio ドメインで、デフォルトの LCC スクリプトをドメインレベルで設定します。
   + LCC で、`/home/sagemaker-user` のすべてを S3 のユーザープロファイルプレフィックス (`s3://studio-backup/studio-user1` など) にコピーします。

1. デフォルトの Jupyter Server アプリをすべて再起動します (LCC を実行するため)。

1. アプリ、ユーザープロファイル、ドメインをすべて削除します。

1. 新しい SageMaker Studio ドメインを作成します。

1. ユーザープロファイルと実行ロールのリストから新しいユーザープロファイルを作成します。

1. LCC をドメインレベルで設定します。
   + LCC で、S3 のユーザープロファイルプレフィックスのすべてを `/home/sagemaker-user` にコピーします。

1. [LCC 設定](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateApp.html#:~:text=%22ResourceSpec%22%3A%20%7B%20%0A%20%20%20%20%20%20%22InstanceType%22%3A%20%22string%22%2C%0A%20%20%20%20%20%20%22LifecycleConfigArn%22%3A%20%22string%22%2C) を使用してすべてのユーザー向けのデフォルトの Jupyter Server アプリを作成します ([CLI](https://docs.aws.amazon.com/cli/latest/reference/sagemaker/create-app.html)、[SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.create_app))。

## SAML アサーションを使用した SageMaker Studio へのアクセス
<a name="sagemaker-studio-access-using-saml"></a>

ソリューションのセットアップ:

1. 外部 IdP で SAML アプリケーションを作成します。

1. 外部 IdP を IAM の ID プロバイダーとして設定します。

1. IdP からアクセスできる `SAMLValidator` Lambda 関数を (関数 URL または API ゲートウェイを通じて) 作成します。

1. `GeneratePresignedUrl` Lambda 関数と、この関数にアクセスするための API ゲートウェイを作成します。

1. API ゲートウェイを呼び出すためにユーザーが引き受けることができる IAM ロールを作成します。このロールは、次の形式を使用して SAML アサーションに属性として渡す必要があります。
   + 属性名: https://aws.amazon.com/SAML/Attributes/Role
   + 属性値: `<IdentityProviderARN>`、`<RoleARN>`

1. SAML Assertion Consumer Service (ACS) エンドポイントを `SAMLValidator` 呼び出しの URL に更新します。

SAML バリデーターのサンプルコード:

```
import requests
import os
import boto3
from urllib.parse import urlparse, parse_qs
import base64
import requests
from aws_requests_auth.aws_auth import AWSRequestsAuth
import json


# Config for calling AssumeRoleWithSAML
idp_arn = "arn:aws:iam::0123456789:saml-provider/MyIdentityProvider"
api_gw_role_arn = 'arn:aws:iam:: 0123456789:role/APIGWAccessRole'
studio_api_url = "abcdef.execute-api.us-east-1.amazonaws.com"
studio_api_gw_path = "https://" + studio_api_url + "/Prod "

# Every customer will need to get SAML Response from the POST call
def get_saml_response(event):
    saml_response_uri = base64.b64decode(event['body']).decode('ascii')
    request_body = parse_qs(saml_response_uri)
    print(f"b64 saml response: {request_body['SAMLResponse'][0]}")
    return request_body['SAMLResponse'][0]


def lambda_handler(event, context):
    sts = boto3.client('sts')
    
    # get temporary credentials 
    response = sts.assume_role_with_saml(
                    RoleArn=api_gw_role_arn,
                    PrincipalArn=durga_idp_arn,
                    SAMLAssertion=get_saml_response(event)
                )    
    auth = AWSRequestsAuth(aws_access_key=response['Credentials']['AccessKeyId'],
                      aws_secret_access_key=response['Credentials']['SecretAccessKey'],
                      aws_host=studio_api_url,
                      aws_region='us-west-2',
                      aws_service='execute-api',
                      aws_token=response['Credentials']['SessionToken'])
                      
    presigned_response = requests.post(
        studio_api_gw_path,
        data=saml_response_data,
        auth=auth)
        
    return presigned_response
```