Amazon Web Services ブログ

閉域網で Amazon SageMaker を利用する際のポイントと手順

みなさま、こんにちは!ソリューションアーキテクトの辻です!

このブログでは Amazon SageMaker を閉域網で利用する際のポイントや設定方法、使い方を紹介します。長い記事となりますので、以下の構成に沿って、閉域網における利用まで順を追って説明します。

  • 全体像の紹介 – パート1
  • 閉域網の作成 (閉域網を新規作成したい方向けです) – パート2
  • ネットワークと権限の設定 (管理者による設定の手順などを紹介します) – パート3
  • エンドユーザーによる利用 (パート2, 3の手順で構築した環境での Amazon SageMaker の各種機能の利用方法を説明します) – パート4
  • リソースの後片付けとまとめ – パート5,6

いずれのパートも Amazon SageMaker に関して経験があり、SageMaker Python SDK などを利用したことのある方を前提としています。設定方法は東京リージョンを前提としているので、他のリージョンをお使いになる方は適切に読み替えてください。

1. 全体像の紹介

Amazon SageMaker をデフォルトの設定で利用する場合、API のリクエスト・レスポンスなどのデータ通信はインターネットを経由します。これらの通信はすべて SSL/TLS によって暗号化されており、セキュリティ上はこれで十分な場合がほとんどです。しかし、コンプライアンス要件などから、インターネットにトラフィックを出すことができない場合もあります。このブログでは、そのような場合に Amazon SageMaker をどのように設定し、閉域網で利用すればよいかを紹介します。

Amazon SageMaker には多くのサービス・機能が含まれています。全機能の閉域網における設定・利用方法について1つのブログで手順を紹介するのは困難なので、このブログでは次の3つの機能に絞って紹介します。

  1. SageMaker ノートブックインスタンス
  2. SageMaker 学習ジョブ
  3. SageMaker 推論エンドポイント

1 は開発、2 は学習、そして 3 は推論に該当し、機械学習のパイプラインを構成する主な要素となります。

Amazon SageMaker が作成するリソースは、(Amazon EC2 インスタンスのような) お客様の VPC 内のリソースではなく、VPC 外で Amazon SageMaker がサービスとして管理しているリソースです。下図の左の四角はお客様の VPC を、右は Amazon SageMaker のサービス範囲を表しています。

Accessing Amazon SageMaker via the Internet.

Amazon SageMaker に限らず、VPC 外のリソースへのアクセスは基本的にインターネットを経由します。インターネットを介さずに直接これらのリソースと通信したい場合は、そのサービスの VPC エンドポイントが必要です。VPC エンドポイントはお客様の VPC に紐づく形で作成され、インターネットへ抜けることなくアクセスすることを可能にします。

Accessing Amazon SageMaker via an VPC endpoint

VPC エンドポイントによって、VPC と Amazon SageMaker のサービス内のリソースとの間の通信はインターネット介さずに実現できます。ただし、これだけではサービスからインターネットへの通信を制限することができません。例えば、上の図にあるように、SageMaker のサービス内からインターネットへ通信をしてしまうケースが考えられます。これを制限するためには、リソース操作の API に適切な引数を与えることで実現します。

Blocking the Internet access using arguments.

まとめると閉域網で Amazon SageMaker を利用する際のポイントは次の 2 点です。

  1. 適切な VPC エンドポイントの作成
  2. 適切な API 引数の指定

この 2 点を意識しつつ、手順を追うことで見通しよく理解できるはずです。

2. 閉域網の作成

こちらは、閉域網を新規に作成したい方向けのパートです。すでに閉域網があり、そちらを利用する場合は次のパートまで読み飛ばしても問題ありません。

2.1 VPC とサブネットの作成

AWS 上に閉域網を構築するための第一歩は VPC の作成です。AWS マネジメントコンソールから新規に VPC を作成します。VPC にはプライベートサブネット (インターネットへ抜ける手段がないサブネット) を2つ作成します。

  • Amazon VPC のマネジメントコンソールへ移動し、左側のペインから「VPC」を選択します。
  • VPC 一覧のページの左上の「VPC を作成」をクリックします。名前タグには IFSM-VPC、IPv4 CIDR ブロックには 10.0.0.0/16 を入力し、他は変更せずに右下の「作成」をクリックします。

この VPC に2つのサブネットを作成します。

  • Amazon VPC のマネジメントコンソールに移動し、左側のペインから「サブネット」を選択します。
  • サブネット一覧のページの左上の「サブネットの作成」をクリックします。名前タグには IFSM-Subnet-1、VPCには先程の IFSM-VPC、アベイラビリティゾーンには ap-northeast-1a、IPv4 CIDR ブロックには 10.0.0.0/24 を入力し、右下の「作成」をクリックします。

もう1つのサブネットを別のアベイラビリティゾーンに作成します。

  • Amazon VPC のマネジメントコンソールに移動し、左側のペインから「サブネット」を選択します。
  • サブネット一覧のページの左上の「サブネットの作成」をクリックします。名前タグには IFSM-Subnet-2、VPCには先程の IFSM-VPC、アベイラビリティゾーンには ap-northeast-1c、IPv4 CIDR ブロックには 10.0.1.0/24 を入力し、右下の「作成」をクリックします。

2.2 EC2 インスタンスの起動

以上で閉域網が完成しましたが、この状態では閉域網内のリソースにアクセスする手段がありません。アクセスする手段としては専用線か VPN が利用できます。専用線は AWS Direct Connect と呼ばれるサービスを、VPN は AWS Site-to-Site VPN もしくは AWS Client VPN と呼ばれるサービスで実現できます。いずれの実現方法も多くの設定が必要なため、実験的に閉域網にアクセスするには少し面倒です。
今回は別の手段として AWS Systems Manager (SSM) の Session Manager という機能を利用して閉域網内のリソースにアクセスします。Session Manager では AWS IAM の認証情報を使い、AWS SSM を経由して閉域網である VPC 内にアクセスすることができます。

Accessing EC2 instance via AWS SSM

今回は API を呼べる PC などが閉域網のネットワークに参加していないので、閉域網内から API を呼べるように Amazon EC2 インスタンスを作成します。また後ほど SSH でアクセスできるようにキーペアも作成します。

  • Amazon EC2 のマネジメントコンソールへ移動し、左側のペインから「キーペア」を選択します。
  • キーペア一覧のページの右上の「キーペアを作成」をクリックします。
  • 名前には IFSM-Key-Pair を入力し、他は変更せず右下の「キーペアを作成」をクリックします。クリック後にキーペアの秘密鍵がファイルとして PC にダウンロードされるので、ファイルのパスを覚えておきます。

続いて、EC2 インスタンスを作成します。

  • Amazon EC2 のマネジメントコンソールへ移動し、左側のペインから「インスタンス」を選択します。
  • インスタンス一覧のページの右上の「インスタンスを起動」をクリックします。
  • AMI は Amazon Linux 2 (HVM) を選択します (ここで他の AMI を使用すると AWS SSM の手順が変わるので Amazon Linux 2 を選択してください)。インスタンスタイプは t2.micro を選択し、「次のステップ」をクリックします。
  • インスタンスの詳細で、ネットワークには先程作成した VPC (IFSM-VPC) を選択し、他は変更せず「次のステップ」をクリックします。
  • ストレージは変更せず「次のステップ」をクリックします。
  • タグで、「クリックして Name タグを追加します」をクリックし IFSM-Instance などと判別しやすい名前を入力し、「次のステップ」をクリックします。
  • セキュリティグループでは、「既存のセキュリティグループを選択する」を選び default のセキュリティグループを選択し、「確認と作成」をクリックします。
  • 内容を確認したら「起動」をクリックします。
  • 最後にキーペアを指定する画面が表示されるので、先程作成したキーペア (IFSM-Key-Pair) を選択し、チェックボックスにチェックし「インスタンスの作成」をクリックします。

作成ステータスとして「インスタンスは現在作成中」が表示されていれば OK です。そのまま「インスタンスの表示」をクリックします。

2.3 EC2 インスタンスへのログイン

インスタンスは作成できたので、続いてこのインスタンスにアクセスします。AWS SSM Session Manager でのアクセスにはいくつか準備が必要です。具体的には次の3つです。

  1. AWS CLI 用の Session Manager Plugin をローカル PC にインストールする
  2. アクセスする EC2 インスタンスに対して IAM ロールをアタッチする
  3. EC2 インスタンスにアクセスするための VPC エンドポイントを作成する

順番に手順を説明します。

まず 1. はこちらの公式ドキュメントに Windows, macOS, Linux でのインストールの手順が書かれているので、参考にしつつインストールします。

続いて 2. は IAM ロールの作成と IAM ロールの EC2 インスタンスへのアタッチの2つのステップがあります。詳細はこちらの公式ドキュメントに書かれています。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ロール」を選択します。
  • ロール一覧のページの左上の「ロールの作成」をクリックします。
  • 信頼されたエンティティには AWS サービスの EC2 を選択し、「次のステップ」をクリックします。
  • アタッチする IAM ポリシーは AWS Managed Policy の AmazonSSMManagedInstanceCore です。フィルタで AmazonSSM と文字列検索することで見つけられます。IAM ポリシーの左にあるチェックボックスをチェックしたら、「次のステップ」をクリックします。
  • タグは追加せず「次のステップ」をクリックします。
  • 確認の画面で、ロール名には IFSM-EC2-Role を入力し、右下の「ロールを作成」をクリックします。

この IAM ロールを先程作成した EC2 インスタンスにアタッチします。

  • Amazon EC2 のマネジメントコンソールへ移動し、左側のペインから「インスタンス」を選択します。
  • インスタンス一覧のページから先程作成したインスタンス IFSM-Instance をクリックし、左上の「アクション」から「セキュリティ > IAM ロールを変更」をクリックします。IAM ロールを選択するドロップダウンがあるので、そこから先程作成した IFSM-EC2-Role を選択します。選択したら「保存」をクリックして、アクションを完了させます。

最後に 3. は、こちらの AWS ナレッジセンターに詳細が書かれています。

  • Amazon VPC のマネジメントコンソールへ移動し、左側のペインから「VPC」を選択します。
  • VPC 一覧のページから先程作成した VPC IFSM-VPC をクリックし、左上の「アクション」から「DNS ホスト名を編集」をクリックします。有効化にチェックを付け「変更の保存」をクリックします。

VPC の DNS ホスト名の有効化は、この後の手順の VPC エンドポイントの作成に必要なので、事前にやっておきます。

  • Amazon VPC のマネジメントコンソールへ移動し、左側のペインから「エンドポイント」を選択します。
  • エンドポイント一覧のページの左上の「エンドポイントの作成」をクリックします。
  • サービス名には com.amazonaws.ap-northeast-1.ssm を選択します (フィルタで ssm で文字列検索することで見つけられます)。
  • VPC には先程作成した IFSM-VPC を選択します。他は変更せずに右下の「エンドポイントの作成」をクリックします。

次の 2 つのサービス名についても、同じように VPC エンドポイントの作成の操作をします。

  • com.amazonaws.ap-northeast-1.ssmmessages
  • com.amazonaws.ap-northeast-1.ec2messages

いずれの VPC エンドポイントも保留中から使用可能になるまでに数分がかかります。すべて使用可能になるまで、ゆっくり待ちましょう。

これですべての設定が完了しました。 aws configure などで認証情報が設定済のローカル PC のターミナルから、次のコマンドで閉域網にいる EC2 インスタンスに接続してみます。

ssh -o ProxyCommand="sh -c '
  aws ssm start-session \
  --target <INSTANCE_ID> \
  --document-name AWS-StartSSHSession'" \
  -i <PRIVATE_KEY> \
  ec2-user@<PRIVATE_IP>

ただし <INSTANCE_ID> は EC2 インスタンスのインスタンス ID、 <PRIVATE_KEY> は先程ダウンロードした秘密鍵までのパス、そして <PRIVATE_IP> は EC2 インスタンスの「プライベート」IP アドレスです。インスタンス ID とプライベート IP アドレスはコンソールから確認することができます。秘密鍵は macOS や Linux では権限を chmod などで事前に 600 に変更する必要があることに注意してください。コマンドを実行し、無事 EC2 インスタンスにアクセスすることができれば成功です。4.2 までは EC2 インスタンスは操作はないので、必要なければそのままログアウトしても構いません。

3. ネットワークと権限の設定

このパートは管理者権限のあるユーザーが、ネットワークやエンドユーザーの権限を設定する場合を想定して書かれています。大きく 2 つのセクションに分かれています。

  • VPC エンドポイントの作成
  • ユーザー用の IAM ポリシーの作成

3.1 VPC エンドポイントの作成

閉域網での Amazon SageMaker 利用の1つ目のポイントは VPC エンドポイントを利用したネットワークアクセスです。このセクションでは、各ワークロードで必要となる VPC エンドポイントを作成していきます。

  • Amazon VPC のマネジメントコンソールへ移動し、左側のペインから「エンドポイント」を選択します。
  • エンドポイント一覧のページの左上の「エンドポイントの作成」をクリックします。
  • サービス名には com.amazonaws.ap-northeast-1.sagemaker.api を選択します (フィルタで sagemaker で文字列検索することで見つけられます)。
  • VPC には先程作成した IFSM-VPC を選択します。他は変更せずに右下の「エンドポイントの作成」をクリックします。

次の 5 つのサービス名についても、同じように VPC エンドポイントの作成の操作をします。

  • com.amazonaws.ap-northeast-1.sagemaker.runtime
  • aws.sagemaker.ap-northeast-1.notebook
  • com.amazonaws.ap-northeast-1.s3 (ルートテーブルにチェックを入れて作成します)
  • com.amazonaws.ap-northeast-1.logs
  • com.amazonaws.ap-northeast-1.ec2

はじめに作成するものと合わせて、合計 6 つ (閉域網を作成した場合は AWS SSM で必要となるものと合わせて 9 つ) 作成しています。6 つそれぞれについて、どの場面で必要となるか簡単に説明します。
*.sagemaker.api は、SageMaker の API 呼び出し (一覧はこちら) で必要となる VPC エンドポイントです。
*.sagemaker.runtime は、SageMaker の推論エンドポイントに対して推論処理を実行する API (InvokeEndpoint API) で必要となる VPC エンドポイントです。
aws.sagemaker.*.notebook は、SageMaker ノートブックインスタンスへのアクセスに必要となる VPC エンドポイントです。SageMaker ノートブックインスタンスが提供する Jupyter 環境を利用する場合はこちらがないとアクセスできません。
*.s3*.logs は、Amazon S3 と Amazon CloudWatch Logs の API 呼び出しで必要となる VPC エンドポイントです。 これらの VPC エンドポイントが必要な理由は、SageMaker Python SDK でサービスにアクセスするためです。これらが無い場合、閉域網内で SageMaker Python SDK を利用した際に、正しく動作しません。
*.ec2 は、Amazon EC2 の API 呼び出しで必要となる VPC エンドポイントです。このブログでは、SageMaker ノートブックインスタンスを作成する際に EC2 の API を呼び出すため、必要となります。

VPC に対してこれらの VPC エンドポイントを作成しておけば、トラフィックはこのエンドポイントを通ることができるため、インターネットにアクセスせずとも各処理を実行することができます。

VPC endpoint for Internet-free SageMaker

3.2 ユーザー用の権限の作成と付与

閉域網での Amazon SageMaker 利用の2つ目のポイントは、SageMaker からインターネットに抜けないように API に引数を与えることです。リソース作成や実行の API を呼び出すのは、管理者ではなく一般のユーザーです。ユーザーが故意にまたは誤ってインターネットを抜けられるリソース等を作成してしまわないように権限を絞ります。

権限を付与する場合の設計方針として、最小権限の原則と呼ばれるものがあります。本番環境では、誤操作による障害やセキュリティ攻撃から防ぐために最小権限の原則に従うのが良いでしょう。一方で、本番環境ではない開発環境で試行錯誤して柔軟にリソースの作成・変更・削除などを実行をしたい場合は、権限を不必要に絞ってしまっては開発の速度を妨げる要因になってしまいます。このブログは SageMaker ノートブックインスタンスを使用するような開発環境を想定しています。そのため、最小権限の原則に則るのではなく、あくまでガードレールとして権限を絞る方法を説明します。ガードレールによって、閉域網の外にアクセスが出ていかないようします。

SageMaker 上で開発をするため IAM ポリシーの作成

Amazon SageMaker を利用した機械学習の開発をする場合、AWS マネージドの IAM ポリシーである AmazonSageMakerFullAccess を IAM ユーザーや IAM ロールにアタッチするのが一般的です。この IAM ポリシーは、名前からも推測できるように、 Amazon SageMaker に関連するリソースを自由に操作できるような強い権限を定義しています。今回はユーザーにこの AmazonSageMakerFullAccess の権限を付与しつつ、インターネットへ出るような API の使用を「明示的に禁止」するように IAM ポリシーを記述していきます。

インターネットへアクセスできる経路のある Amazon SageMaker のリソースには、作成時にパラメータで指定することで、その経路を塞ぐことができます。このパラメータを「指定しない」ような呼び出しを明示的に禁止するのが目標です。そのようなパラメータのある API を IAM ポリシーに一つずつ列挙していっても良いですが、面倒な作業なのでシンプルにまとめて記述したいところです。このような要件に対して便利なのが、IAM ポリシーの Null 条件演算子です (Null 条件演算子は公式ドキュメントのこちらのページに詳しく書かれています)。この条件演算子を利用して「特定のパラメータのあるすべての API」においてインターネットに抜けないように制限をかけていきます。
具体的には次の 4 つのパラメータに対して、次のように制限をかけていきます。

  1. sagemaker:NetworkIsolation → false のときに API を禁止する
  2. sagemaker:VpcSubnets → 閉域網内のサブネットを指定していないときに API を禁止する
  3. sagemaker:DirectInternetAccess → Enabled (有効化) ときに API を禁止する
  4. aws:SourceVpce → 閉域網の VPC の VPCエンドポイントを経由していないときに API を禁止する

これらを IAM ポリシーとして記述したのが次の JSON です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "sagemaker:*",
            "Resource": "*",
            "Condition": {
                "Null": {
                    "sagemaker:NetworkIsolation": false
                },
                "Bool": {
                    "sagemaker:NetworkIsolation": false
                }
            }
        },
        {
            "Effect": "Deny",
            "Action": "sagemaker:*",
            "Resource": "*",
            "Condition": {
                "Null": {
                    "sagemaker:VpcSubnets": false
                },
                "ForAnyValue:StringNotEquals": {
                    "sagemaker:VpcSubnets": [
                        "subnet-xxxxxxxxxxxxxxxxx",
                        "subnet-yyyyyyyyyyyyyyyyy"
                    ]
                }
            }
        },
        {
            "Effect": "Deny",
            "Action": "sagemaker:*",
            "Resource": "*",
            "Condition": {
                "Null": {
                    "sagemaker:DirectInternetAccess": false
                },
                 "StringEquals": {
                    "sagemaker:DirectInternetAccess": "Enabled"
                }
            }
        },
        {
            "Effect": "Deny",
            "Action": "sagemaker:*",
            "Resource": "*",
            "Condition": {
                "Null": {
                    "aws:SourceVpce": false
                },
                "ForAllValues:StringNotEquals": {
                    "aws:SourceVpce": [
                        "vpce-xxxxxxxxxxxxxxxxx",
                        "vpce-yyyyyyyyyyyyyyyyy",
                        "vpce-zzzzzzzzzzzzzzzzz"
                    ]
                }
            }
        }
    ]
}

4 つの Statement すべて {"Effect": "Deny"} となっていることが分かります。 上記 JSON における subnet-xxxxxxxxxxxxxxxxxsubnet-yyyyyyyyyyyyyyyyy は閉域網内のサブネットの ID であり、 vpce-xxxxxxxxxxxxxxxxxvpce-yyyyyyyyyyyyyyyyyvpce-zzzzzzzzzzzzzzzzz は上で作成した 3 つの Amazon SageMaker に関連した VPC エンドポイントの ID です (すべてコンソールから確認することができます)。サブネット ID は後の操作でも記述するので、メモ帳などにコピーしておくと便利です。この JSON で定義された IAM ポリシーを作成します。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ポリシー」を選択します。
  • ポリシー一覧のページの左上の「ポリシーの作成」をクリックします。
  • JSON タブを選択して上記の JSON をコピーアンドペーストします (サブネット ID と VPC エンドポイント ID は適宜編集します)。ペーストしたら右下の「ポリシーの確認」をクリックします。
  • 名前には RestrictInternetAccess とし、他の変更せずに右下の「ポリシーの作成」をクリックします。

SageMaker ノートブックインスタンス内で使用する IAM ロールの作成

SageMaker ノートブックインスタンスは、環境内で使用する IAM ロールが必要です。明示的に指定しない場合は AWS マネージドの AmazonSageMakerFullAccess IAM ポリシーがアタッチされた IAM ロールが使用または新規作成されます。そのままこの IAM ロールを使用してしまうと閉域網を出るようなリソースが作成できてしまうので、先程作成した IAM ポリシー RestrictInternetAccess も一緒にアタッチして、このようなリソースの作成できないようにします。この2つの IAM ポリシーがアタッチされた IAM ロールを作成しましょう。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ロール」を選択します。
  • ロール一覧のページの左上の「ロールの作成」をクリックします。
  • 信頼されたエンティティには AWS サービスの SageMaker を選択し、「次のステップ」をクリックします。
  • アタッチする IAM ポリシーにて AmazonSageMakerFullAccess がデフォルトで選択されているはずです。そのまま「次のステップ」をクリックします。
  • タグは任意で追加し、「次のステップ」をクリックします。
  • 確認の画面で、ロール名には IFSM-SageMaker-Role を入力し、右下の「ロールを作成」をクリックします。この状態では、1つしか IAM ポリシーがアタッチされていないので、禁止する IAM ポリシーもアタッチします。
  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ロール」を選択します。
  • ロール一覧のページの検索窓から先程作成した IFSM-SageMaker-Role の文字列を入力し、表示された IAM ロール名をクリックします。
  • ロールの概要の画面で「アクセス権限」のタブが直下の「ポリシーをアタッチします」をクリックします。ポリシー一覧のページに移るので、検索窓から先程作成した IAM ポリシーである RestrictInternetAccess を検索し、IAM ポリシーの左にあるチェックボックスをチェックし、右下の「ポリシーのアタッチ」をクリックします。

SageMaker ノートブックインスタンス作成時には、この IFSM-SageMaker-Role を選択することで、閉域網に閉じたリソースのみ作成できるようになります。

SageMaker ノートブックインスタンスに渡せる IAM ロールを制限

SageMaker ノートブックインスタンスが使用する IAM ロールは、IAM ユーザーが指定します。この IAM ユーザーがもし管理者権限のある IAM ロールを指定しまった場合、SageMaker ノートブックインスタンスを踏み台にして、好きなように AWS のリソースを操作できてしまいます。このような事故や攻撃を防ぐために、IAM ロールを渡す権限を定義できるようになっています。具体的には iam:PassRole という API アクションを IAM ポリシーで制限することで記述できます。
RestrictInternetAccess IAM ポリシーだけでは、この API アクションに対しては何も制限しておらず、さらに AmazonSageMakerFullAccess によって明示的に許可されてしまっています。制限するために、別の IAM ポリシー RestrictPassRole を作成します。これら 3 つの IAM ポリシーを IAM ロールにアタッチします。最終的に SageMaker ノートブックインスタンスで使用する IAM ロールの権限のイメージとしては下の図になります。

Permission of the role in a notebook instance

通常 IAM ポリシーには、特定の IAM ロールを指定して、それを明示的に許可するように記述すれば良いですが (それ以外の IAM ロールは暗示的に拒否されるため)、今回は AmazonSageMakerFullAccess がアタッチされてしまっているため、明示的に「拒否」することで実現します。
IAM ポリシーには、以下の内容を記述します。

  • IAM ロールを渡す対象が Amazon SageMaker であるときに IFSM-SageMaker-Role のIAM ロール以外を渡すことを禁止する。

IAM ロールの ARN を arn:aws:iam::000000000000:role/IFSM-SageMaker-Role としたとき、IAM ポリシーは次のようになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "iam:PassRole",
            "NotResource": "arn:aws:iam::000000000000:role/IFSM-SageMaker-Role",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "sagemaker.amazonaws.com"
                }
            }
        }
    ]
}

ここでは「特定の IAM ロール以外」を禁止するために NotResource というキーを使用しています。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ポリシー」を選択します。
  • ポリシー一覧のページの左上の「ポリシーの作成」をクリックします。
  • JSON タブを選択して上記の JSON をコピーアンドペーストします (アカウント ID 000000000000 は適宜編集します)。ペーストしたら右下の「ポリシーの確認」をクリックします。
  • 名前には RestrictPassRole とし、他の変更せずに右下の「ポリシーの作成」をクリックします。

この IAM ポリシーで IAM ユーザーの権限を絞ることができます。しかしこれで十分ではありません。既存の SageMaker ノートブックインスタンスを踏み台にして、新しく管理者権限を持つ SageMaker ノートブックインスタンスを作成してしまわないよう IFSM-SageMaker-Role にもこの IAM ポリシーをアタッチする必要があります。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ロール」を選択します。
  • ロール一覧のページの検索窓から先程作成した IFSM-SageMaker-Role の文字列を入力し、表示された IAM ロール名をクリックします。
  • ロールの概要の画面で「アクセス権限」のタブが直下の「ポリシーをアタッチします」をクリックします。
  • ポリシー一覧のページに移るので、検索窓から先程作成した IAM ポリシーである RestrictPassRole を検索し、IAM ポリシーの左にあるチェックボックスをチェックし、右下の「ポリシーのアタッチ」をクリックします。

SageMaker ノートブックインスタンス作成時には、この IFSM-SageMaker-Role を選択することで、許可されていない IAM ロールの譲渡を禁止した上で、閉域網に閉じたリソースのみ作成できるようになります。

IAM ユーザーの作成

3.2 の最後は SageMaker で開発するための IAM ユーザーの作成です。IAM ユーザーの権限は、エンドユーザーの開発方法によって変わってきます。Amazon SageMaker 上の開発方法としては、大きく二種類存在します。

  1. SageMaker ノートブックインスタンス「内」での開発
  2. SageMaker ノートブックインスタンス「外」での開発

1番目は SageMaker ノートブックインスタンスが提供する Jupyter 環境を利用した開発です。一方で2番目はローカル PC などを利用した開発です。開発環境は違えども両者とも SageMaker Python SDK を利用して開発できます。このブログでは前者の開発環境を想定します。
さて、SageMaker ノートブックインスタンスを利用した開発のみをするユーザーに対してどのような権限が必要かを考えてみると、それは「SageMaker ノートブックインスタンスを作成・確認・変更・削除する、そして Jupyter 環境にアクセスする」権限であることが想像できます。この権限を提供している Amazon SageMaker の API を公式ドキュメントから探すと、次のようになります。

  • 作成: sagemaker:CreateNotebookInstance
  • 確認: sagemaker:DescribeNotebookInstance, sagemaker:ListNotebookInstances
  • 変更: sagemaker:UpdateNotebookInstance, sagemaker:StartNotebookInstance, sagemaker:StopNotebookInstance
  • 削除: sagemaker:DeleteNotebookInstance
  • Jupyter 環境へアクセスする: sagemaker:CreatePresignedNotebookInstanceUrl

これらの API の権限があれば、問題なく SageMaker ノートブックインスタンスを操作できると思いたいところですが、残念ながらいくつか API 権限を追加しないと権限不足で上記のいくつか(作成と変更の箇所)の API は失敗してしまいます。具体的には次の API が追加で必要です (マネジメントコンソールではこれらすべての API が必要ですが、CLI/SDK ではリソース ID が事前把握できている場合に限り、いくつかの API 必須ではありません)。

  • iam:ListRoles : IAM ロールの一覧を取得する
  • iam:PassRole : IAM ロールをサービスに対して渡す
  • ec2:CreateNetworkInterface : ENI (Elastic Network Interface) を作成する
  • ec2:DescribeSecurityGroups : セキュリティグループの一覧と詳細を取得する
  • ec2:DescribeSubnets : サブネットの一覧と詳細を取得する
  • ec2:DescribeVpcs : VPC の一覧と詳細を取得する
  • ec2:DescribeNetworkInterfaces : ENI の一覧と詳細を取得する

Amazon SageMaker の API、そして上記の AWS IAM と Amazon EC2 の API をまとめて IAM ポリシーにまとめると、次の JSON として記述できます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sagemaker:CreatePresignedNotebookInstanceUrl",
                "sagemaker:*NotebookInstance",
                "sagemaker:*NotebookInstances",
                "iam:ListRoles",
                "iam:PassRole",
                "ec2:CreateNetworkInterface",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "ec2:DescribeNetworkInterfaces"
            ],
            "Resource": "*"
        }
    ]
}

インターネットに抜ける経路を制限する必要がなければ、この IAM ポリシーをそのまま利用できます。制限する場合は、API の利用を制限する 2 つの IAM ポリシー ( RestrictInternetAccessRestrictPassRole ) を IAM ユーザーに同時に付与します。このIAM ポリシーを作成します。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ポリシー」を選択します。
  • ポリシー一覧のページの左上の「ポリシーの作成」をクリックします。
  • JSON タブを選択して上記の JSON をコピーアンドペーストします 。ペーストしたら右下の「ポリシーの確認」をクリックします。
  • 名前には DeveloperPolicy とし、他の変更せずに右下の「ポリシーの作成」をクリックします。

続いてこの IAM ポリシーと RestrictInternetAccessRestrictPassRole がアタッチされた IAM ユーザーを作成します。

  • AWS IAM のマネジメントコンソールへ移動し、左側のペインから「ユーザー」を選択します。
  • ユーザー一覧のページの左上の「ユーザーを追加」をクリックします。
  • ユーザー名には Developer を入力し、アクセスの種類として「プログラムによるアクセス」と「AWS マネジメントコンソールへのアクセス」両方にチェックを入れます。パスワードには、要件次第で自動生成かカスタムを選んでください。「次のステップ」をクリックします。
  • アクセス許可のページにて、「既存のポリシーを直接アタッチ」を選択します。ここで DeveloperPolicy, RestrictInternetAccess, と RestrictPassRole の 3 つの IAM ポリシーを検索フィルターを駆使しながらチェックボックスにチェックを入れていきます。すべてチェックを入れることができたならば、右下の「次のステップ」をクリックします。
  • タグは任意で追加し「次のステップ」をクリックします。
  • 権限の内容を確認し、右下の「ユーザーの作成」をクリックします。
  • 作成に成功すると、CSV ファイルをダウンロードする画面が表示されます。ユーザーに配布できるようにダウンロードしておきます。ダウンロードが済んだならば「閉じる」をクリックします。

以上で、SageMaker ノートブックインスタンスを操作できる IAM ユーザーが作成されました。注意として、実際に利用する際は、実際のユーザーごとに別々の IAM ユーザーを作成してください。今回は例として Developer のような汎用的な名前を使用しています。
ここまで作成して IAM ポリシーと IAM ロール・ユーザーの関係は以下の図のようになっています。

Relation between policies and roles, users

4. ユーザーによる利用

こちらは、一つ前のパートで作成した環境で Amazon SageMaker を使うエンドユーザー向けのパートです。このパートは次の 6 つのセクションに分かれて構成されています。

  • 学習データの準備
  • EC2 インスタンスへのログインと認証情報の指定
  • SageMaker ノートブックインスタンスの作成
  • SageMaker ノートブックインスタンスへのアクセス
  • SageMaker 学習ジョブの実行
  • SageMaker 推論エンドポイントの作成と推論処理の実行

いずれのセクションも前のパートで作成した閉域網の環境での操作を想定しています。他の環境の場合は適切に読み替えてください。また CLI を操作するのは Developer の IAM ユーザーです。

4.1 学習データの準備

後述の 4.5 では SageMaker 学習ジョブを実行しますが、学習をするためにはデータが必要です。閉域網の場合は通常、学習データは事前に S3 に置かれています。しかし、今回はデモのためデータがないため、例外的にデータの取得のみインターネットを経由することとします。
利用するコードやデータは、GitHub に公開されているこちらの MNIST の線形分類器の Jupyter Notebook を利用します。
以下で記述する、学習データの準備、学習ジョブの実行、推論処理の実行、すべてこの Jupyter Notebook をベースにしているので、別途参照しつつ読むことをおすすめします。

Jupyter Notebook の 2 つ目のコードブロックに書かれている MNIST のデータセットをローカル PC にダウンロードします。ブラウザの URL 欄から http://deeplearning.net/data/mnist/mnist.pkl.gz にアクセスすることで、ファイル ( mnist.pkl.gz ) をダウンロードすることができます。このファイルは後ほど利用するので、保存した場所を記憶しておきます。

4.2 EC2 インスタンスへのログインと認証情報の指定

Amazon SageMaker に限らず、閉域網で AWS の操作する場合、ブラウザベースの GUI である AWS マネジメントコンソールが利用できない場合があります。このような場合は、SDK や CLI を利用して操作することとなります。このセクションでは CLI を利用した操作方法を紹介します。

既にある閉域網を使っている場合

この場合、ローカル PC も閉域網に参加していると思うので、AWS CLI をインストールされていることを確認すれば準備完了です。

パート 2.で作成した閉域網を使っている場合

この場合、まず 3.3 と同じく SSH で EC2 インスタンスにログインします。その後、4.2 で作成された IAM ユーザーの認証情報を設定します。先程ダウンロードした CSV ファイルにアクセスキー ID とシークレットアクセスキーの値があります。これを aws configure で入力すれば設定できます。この際にリージョンを東京リージョン (ap-northeast-1) に設定しておきます。詳細は公式ドキュメントのこちらのページを参照ください。

4.3 SageMaker ノートブックインスタンスの作成

パート 2. で閉域網を作成した場合、そのパートの最後で VPC 内の EC2 インスタンスに SSH で接続したはずです。この EC2 インスタンスからコマンドを叩くことで SageMaker ノートブックインスタンスの作成します。SSH でログインしていない方は、ログインして CLI で操作ができようにしておきます。SageMaker ノートブックインスタンスを作成していきます。

SageMaker ノートブックインスタンスは CreateNotebookInstance という API を叩くことで作成できます。まずは CLI の help 画面でどのような引数があるのか確認してみましょう。

aws sagemaker create-notebook-instance help

Help 画面で次の 3 つの引数が必須であることが分かります。

  • --notebook-instance-name
  • --instance-type
  • --role-arn

1 つ目は SagaMaker ノートブックインスタンスの名前です。今回は例えば IFSM-Notebook-Instance とします。2 つ目は SageMaker ノートブックインスタンスのインスタンスタイプです。こちらの公式ドキュメントにどのようなインスタンスタイプを選択できるのかを確認できます。今回は特別重い処理や GPU が必要な処理は行わないので ml.t3.medium を選択します。最後 3 つ目は SageMaker ノートブックインスタンスが利用する IAM ロールの ARN です。手順と同じ名前を指定していれば、arn:aws:iam::000000000000:role/IFSM-SageMaker-Role のような ARN になっているはずです (12桁の 000000000000 は、自分のアカウントIDに読み替えます)。

以上で、SageMaker ノートブックインスタンスの作成に必須な 3 つの値が揃いました。しかし、今回はこれだけでは不十分です (試しに、この 3 つの引数を指定してコマンドを実行してみると失敗します)。
今回の閉域網の環境で SageMaker ノートブックインスタンスを作成するためには上記 3 つの必須の引数に加えて、さらに 3 つの引数を与える必要があります。

  • --direct-internet-access
  • --subnet-id
  • --security-group-ids

1 つ目の引数は名前から判断できますが、SageMaker ノートブックインスタンスから直接インターネットへのアクセスをコントロールする引数です。 Enabled もしくは Disabled のどちらかの文字列を渡します。今回は当然アクセスさせたくないので Disabled を渡します (権限で絞られているためそもそも Enabled を渡すことができません)。
2 つ目は SageMaker ノートブックインスタンス、へのアクセス、からのアクセスを許可したい VPC のサブネットの ID を渡します。4.2 でサブネット ID のメモをとっていなかった方は、CLI でサブネット ID を取得します。

aws ec2 describe-subnets \
  --query 'Subnets[?Tags[?Key==`Name` && starts_with(Value, `IFSM`)]]'

IFSM という文字列を検索しています。サブネットの情報が 2 つ出力されるので、どちらかのサブネットを任意で選択し SubnetId キーの値 ( subnet-xxxx という形式) をコピーします。

3 つ目は SageMaker ノートブックインスタンスとのアクセスを許可したい VPC のセキュリティグループの ID を渡します。こちらもサブネットと同様に CLI で取得します。

VpcId=$(
aws ec2 describe-vpcs \
  --query 'Vpcs[?Tags[?Key==`Name` && starts_with(Value, `IFSM`)]].VpcId' \
  --output text
)

aws ec2 describe-security-groups \
  --filters Name=vpc-id,Values=$VpcId

出力された JSON から GroupId キーの値 ( sg-xxxx という形式 ) をコピーします。
今コピーしたこの SubnetId キーの値と GroupId キーの値を CreateNotebookInstance に渡してあげます。

aws sagemaker create-notebook-instance \
  --notebook-instance-name IFSM-Notebook-Instance \
  --instance-type ml.t3.medium \
  --role-arn aws:arn:iam::000000000000:role/IFSM-SageMaker-Role \
  --direct-internet-access Disabled \
  --subnet-id subnet-xxxx \
  --security-group-ids sg-xxxxx

出力として、SageMaker ノートブックインスタンスの ARN が出力されれば OK です。これで、無事 SageMaker ノートブックインスタンスが作成されました。この SageMaker ノートブックインスタンスがどのようなネットワーク構成になっているかの具体的な説明はこちらのブログが参考になります。続いて、Jupyter 環境にアクセスするための署名付き URL を発行していきます。

4.4 SageMaker ノートブックインスタンスへのアクセス

AWS マネジメントコンソールを普段利用している方だと意識したことがないかもしれませんが、SageMaker ノートブックインスタンスが提供する Jupyter 環境へのアクセスは、Amazon SageMaker が発行する「署名付き URL 」にブラウザからアクセスすることで実現しています。Amazon SageMaker においてこの署名付き URL を発行するのが CreatePresignedNotebookInstance という API です。例えば、Amazon SageMaker のマネジメントコンソールから Jupyter 環境にアクセスする場合、SageMaker ノートブックインスタンス一覧のページから「Jupyter を開く」または「JupyterLab を開く」というリンクをクリックするはずです。これらのリンクをクリックすると、この API が叩かれることで署名付き URL が発行され、その URL へリダイレクトする、という流れによってユーザーは Jupyter 環境にアクセスできるようになっています。
先程の SageMaker ノートブックインスタンスの作成のセクションと同じように、このセクションでも EC2 上での CLI 操作を前提とします。次のコマンドで署名付き URL を発行します。

aws sagemaker create-presigned-notebook-instance-url \
  --notebook-instance-name IFSM-Notebook-Instance

URL が出力されるのでコピーします。URL にアクセスする方法は、既にある閉域網を使っているか、もしくはパート 3. 閉域網で作成したリソースを使っているかで異なってきます。

既にある閉域網を使っている場合

この場合、操作しているローカル PC も閉域網に参加しているので、そのままブラウザで URL を叩くことで Jupyter 環境にアクセスすることができます。

パート 2. で作成した閉域網を使っている場合

この場合はローカル PC 自体は閉域網には参加していません。なのでそのままブラウザで URL を叩いてもアクセスすることができません (HTTP 403 になる)。エラーになるのは、SageMaker ノートブックインスタンスへの VPC エンドポイント経由でないためです。VPC エンドポイントを経由するため、ブラウザからのリクエストをすべて VPC、そして VPC エンドポイントを経由するように設定します。今回はこれを実現するために VPC 内の EC2 インスタンスが SOCKS proxy となるようにします。

SOCKS プロトコルで通信できるようにするために、まずは dynamic port forwarding ( -D 8888 ) を有効にして SSH でログインします (すでにログインしている場合は新しくターミナルを開きます)。

ssh -o ProxyCommand="sh -c '
    aws ssm start-session \
        --target <INSTANCE_ID> \
        --document-name AWS-StartSSHSession'" \
    -i <PRIVATE_KEY> \
    -D 8888 \
    ec2-user@<PRIVATE_IP>

上のコマンドでは 8888 番ポートとしていますが、任意に変更できます。これで経路が確保されたので、ブラウザで 8888 番ポートを SOCKS proxy サーバーとして設定します。ブラウザごとに設定方法を異なるので、お使いのブラウザのドキュメントなどを参照して設定します。
例として macOS の Chrome の場合は以下のようなオプションを指定してターミナルから起動することで localhost:8888 を SOCKS proxy として設定できます。

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --proxy-server="socks5://localhost:8888" \
  --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost"

Accessing the notebook instance via the SOCKS proxy

SOCKS proxy の設定が正しく行われたら、再度コピーした URL をブラウザから叩けば、Jupyter 環境にアクセスできるはずです。

4.5 SageMaker 学習ジョブの実行

Jupyter Notebook を読み進める前に、先程ローカル PC にダウンロードした学習データ ( mnist.pkl.gz ) をアップロードします。Jupyter のファイル一覧の画面から右上の “Upload” をクリックし、ファイルを選択すればアップロードできます。
4.1 でも紹介したように、今回はこちらの Jupyter Notebook をベースにしています。“Training the linear model” セクションより上まで以下の 2 つの変更をし、Notebook をそのまま実行します。

  • “Permission and environment variables” で bucket を書き換える必要があります。ユーザーがアクセス権限のある S3 バケットを指定します (デフォルトでは sagemaker の prefix がついた同一アカウント内の S3 バケットはアクセス可能です)。
  • “Data ingestion” で urllib.request.urlretrieve(...) というコードがありますが、すでにデータはローカル PC からアップロード済なのでコメントアウトします。他のコードはそのまま実行します。

“Training the linear model” セクションの1つ目のセルは学習ジョブの基盤のコンテナイメージの URI を取得しています。この部分は変更しません。2つ目のセルは Estimator オブジェクトを作成して、実際に学習ジョブを開始しています。閉域網では Estimator コンストラクタに渡す引数が重要となります。具体的には次の 3 つの引数です。

  • enable_network_isolation
  • subnets
  • security_group_ids

引数の詳細はこちらのドキュメントに書かれています。 4.2 で SageMaker ノートブックインスタンスを作成した際の引数とほぼ同じで、なぜ閉域網で必要となるかは想像しやすいと思います。これらの引数を追加すると、 linear = sagemaker... のコードが次のように書き換わります。

linear = sagemaker.estimator.Estimator(container,
                                       role, 
                                       train_instance_count=1, 
                                       train_instance_type='ml.c4.xlarge',
                                       output_path=output_location,
                                       sagemaker_session=sess,
                                       enable_network_isolation=True,
                                       subnets=['subnet-xxxx', 'subnet-yyyy'],
                                       security_group_ids=['sg-xxxx'])

サブネットとセキュリティグループの ID は適宜変更してください。他のコードはそのままでセルを実行し、出力として Billable seconds: .. が確認できれば無事学習成功です。

4.6 SageMaker 推論エンドポイントの作成と推論処理の実行

学習ジョブによってモデルが作成されたので、このモデルを使って推論エンドポイントを作成し、実際に推論処理を実行してみます。Jupyter Notebook では “Set up hosting for the model” セクション以下を実行します。
このパートで変更を加えるのは 1 つ目のセルの linear_predictor = linear.deploy(...) のコードです。このコードは学習したモデルを推論エンドポイントにデプロイする API です。推論エンドポイントのネットワークの構成を変更したい場合、この API に次の引数を渡します。

  • enable_network_isolation
  • vpc_config_override

引数の詳細はこちらのドキュメントに書かれています。 vpc_config_override はいままで登場したことのなかった名前ですが、値としてサブネットとセキュリティグループの ID を dict 型にして渡すので、実態としては SageMaker ノートブックインスタンス、学習ジョブと同じです。これらの引数を追加すると、コードは次のように書き換わります。

linear_predictor = linear.deploy(initial_instance_count=1,
                                 instance_type='ml.m4.xlarge',
                                 enable_network_isolation=True,
                                 vpc_config_override={
                                    'Subnets': ['subnet-xxxx', 'subnet-yyyy'],
                                    'SecurityGroupIds': ['sg-xxxx']
                                 })

処理の完了には 10 分弱かかります。出力で ---! と出れば完了です。

このセル以下の実行はそのまま実行できます。閉域網であることを噛み締めながら実行しましょう。Jupyter Notebook の最後に推論エンドポイントを削除しています。課金の発生を止めるため忘れずに最後のセルまで実行します。

5. 後片付け

最後にいままで作成したリソースの後片付けをします。権限を気にせずにリソースの削除等を行うため、ここでは管理者権限での操作を前提としてます。

5.1 ユーザーが作成したリソース

Jupyter Notebook を最後のセルまで実行した方ならば、この時点に残っているリソースは大きく 1 つだけです。

  • SageMaker ノートブックインスタンス

コンソールから停止・削除します。SageMaker ノートブックインスタンス以外には、学習データとモデルが置かれている S3 バケット、操作ログが置かれている CloudWatch Logs のロググループも必要に応じて削除します。

5.2 管理者が作成したリソース

IAM ポリシーや VPC などのリソースを削除していきます。

  • EC2 インスタンス: IFSM-Instance
  • キーペア: IFSM-Key-Pair
  • VPC エンドポイント (多数)
  • サブネット: IFSM-Subnet-1, IFSM-Subnet-2
  • VPC: IFSM-VPC
  • IAM ユーザー: Developer
  • IAM ロール: IFSM-EC2-Role, IFSM-SageMaker-Role
  • IAM ポリシー: RestrictInternetAccess, RestrictPassRole, DeveloperPolicy

依存関係があるため、上から順番に削除していくことをおすすめします。これで後片付けは完了です。

6. まとめ

いかがだったでしょうか?このブログでは、閉域網で Amazon SageMaker の機能を利用する方法を紹介しました。前半部分では管理者によるネットワークと権限の設定、後半部分はエンドユーザーによる利用を想定して書きました。社内のコンプライアンス等で閉域網が必要な場合、こちらのブログが参考になれば幸いです。


著者について


Yohei Tsuji's profile picture
辻 陽平 (Yohei Tsuji) は AWS Japan のエンタープライズ ソリューションアーキテクトで、製造領域や研究開発領域のお客様を中心にアーキテクチャ設計や構築をサポートしています。HPC や機械学習の領域を得意としており、特に分散深層学習は大好物です。最近はダイエット目的でロードバイクを購入し、脂肪燃焼に努めています。