Amazon Web Services ブログ

AWS SFTP 論理ディレクトリを使用して、シンプルデータ配布サービスを構築する

当社は 2018 年 11 月に AWS Transfer for SFTP (AWS SFTP) サービスを開始し、それ以来多くの組織で採用され、 Amazon S3 でホストされるデータへの安全な SFTP アクセスを使用可能にしてきました。AWS では、当社のサービスを継続的に反復し、多くのお客様から、SFTPを接続したユーザーのために複数の S3 バケットやキーを統合された論理的ネームスペースにマッピングするオプションが欲しいというご希望をお話をされてきました。このニーズに応えるために、 当社は最近、「論理的ディレクトリ」と呼ばれる AWS SFTP の新機能を開始しました。この機能を使用して、お客様は S3 バケットパスを SFTP エンドユーザーに見ることができるようにする方法をカスタマイズすることができ、そのことにより、次のことが可能になります。

  • S3 バケットのファイルやフォルダーへのアクセス (例; サブスクリプションベースのアクセス) を容易に制限する
  • 既存のアプリケーションとスクリプトで参照されたファイルおよびフォルダーを保存する
  • ファイルのコピーを作成せずに複数のコンシューマーにファイルを配信する
  • コンプライアンス/規制目的で SFTP エンドユーザーに S3 バケット名が表示されないようにする

この記事では、論理ディレクトリを使用して、AWS SFTP を使用してサブスクライバーとデータを共有するための簡単なデータ配信サービスを実装する方法を示します。

簡単なデータ配信サービスの構築

「Bob」が SmartTrade という金融サービス組織のクラウドアーキテクトとして働いているとします。Bob はサブスクライバーが投資戦略を導くために財務データを利用できるようにするデータ配信サービスを構築しています。ユーザーは、サブスクリプションプロファイルに応じて、さまざまなデータセットにアクセスできます。また、ユーザーは権限をもつデータにのみアクセスできることを確認したいと思っています。

Bob のデータレポジトリは現在、「public-research」「subscriptions」という名前の 2 つの S3 バケットの上に構築されています。各 SmartTrade サブスクライバーは、「public-research」バケットのデータにアクセスできます。しかし、 「subscriptions」バケットのデータへのアクセスはユーザーのサブスクリプションに基づいて制限され、多くのサブフォルダーにわたって保存されます。

Bob には現在、2 人のサブスクライバー、Alice と Bryan がおり、次のフォルダー構造 (例: s3:// で示される生の S3 バケットパスではない) を通じて彼らがデータを利用できるようにしたいと思っています。

Alice

/
├── public
│   └── research      --> s3://public-research
│       └── global   
└── subscribed
    ├── 2018
    │   └── indices   --> s3://subscriptions/historical/2018/indices
    └── 2019
        ├── indices   --> s3://subscriptions/historical/2019/indices
        └── equities  --> s3://subscriptions/historical/2019/equities

Bryan

/
├── public
│   └── research      --> s3://public-research
│       └── global
└── subscribed
    ├── 2018
    │   ├── equities  --> s3://subscriptions/historical/2018/equities
    │   └── indices   --> s3://subscriptions/historical/2018/indices
    └── 2019
        ├── credit    --> s3://subscriptions/historical/2019/credit
        └── equities  --> s3://subscriptions/historical/2019/equities

また、SFTP クライアントを使用して、サブスクライバーがログインするとき、Bob はログインディレクトリーにアクセスする権限を持つフォルダーのみが表示されるようにします。

この記事の残りの部分では、Bob がデータリポジトリの要件を満たすために使用できるアーキテクチャについて説明します。このアーキテクチャは、AWS SFTP カスタム ID プロバイダーと論理ディレクトリを利用して、Bob がサブスクライバーに必要なカスタマイズされたフォルダー構造を作成します。以下のコード スニペットは、GitHub で使用可能なカスタム ID プロバイダーの例に基づいています。

アーキテクチャ

下図に示されるように、アーキテクチャ例には 4 つの重要なコンポーネントがあります。AWS Transfer for SFTP サーバー、Amazon API GatewayAWS Lambda、および データリポジトリのための 2 つの S3 バケットです。

データリポジトリ要件を満たすために AWS SFTP カスタム ID プロバイダーを使用するアーキテクチャの例。アーキテクチャ例には 4 つの重要なコンポーネントがあります。AWS Transfer for SFTP サーバー、Amazon API Gateway、AWS Lambda、および データリポジトリのための 2 つの S3 バケットです。

ユーザーがクライアントを使用して認証すると、AWS SFTP はカスタムアイデンティティプロバイダーをクエリ―するための構成された API ゲートウェイメソッドを呼び出します。このメソッドでは、AWS Lambda 関数を使用して、ユーザーを認証し、許可します。AWS Lambda 関数はユーザーを認証することを試み、認証が正常に行われると、ユーザーの SFTP セッションを記述する JSON オブジェクトを返します。JSON オブジェクトは、1 つ以上の S3 バケットへのユーザーアクセスを管理する IAM ロールとオプションのスコープダウンポリシーを含みます。また、ユーザーに表示されるフォルダー構造と S3 バケットパスにフォルダーをマップする方法も説明しています。JSON ドキュメントが AWS SFTP サーバーに返され、それは認証された S3 バケットからそのセッションのユーザーに提示するために使用されます。そこから、AWS SFTP はユーザーのクライアントから、getls、および put などの標準の SFTP コマンドを処理します。

カスタム ID プロバイダー

ユーザー認証は、SFTP ソリューションの重要な部分です。AWS SFTP は、立ち上がり、素早く実行するためことにユーザーを追加することを容易にするサービス管理型 ID プロバイダーを提供します。しかし、一部の顧客は既存の認証システムを使用することを希望しています。Amazon Cognito、Microsoft Active Directory、LDAP サービス、または Okta などのサードパーティプロバイダーです。この目的のため、AWS SFTP はカスタム ID プロバイダーをサポートします。

上記のダイアグラムで示したように、カスタム ID プロバイダーを使用するためには、AWS Lambda 関数を呼び出す Amazon API Gateway メソッドを作成します。ユーザーが SFTP クライアントを使用して認証するたびに、API メソッドが AWS SFTP サーバーにより呼び出されます。代わりに、API Gateway メソッドは、ユーザー名とパスワードと共に、イベントオブジェクトを Lambda 関数に渡します。下記の Lambda 関数で、Bob はユーザー名とパスワードを「authenticated」関数に渡します。

function authenticated(username, password) {
    if (username in userDb) {
        var userRecord = userDb[username];

        if (password == userRecord.password) {
            return true;
        }
    }

    return false;
}

この関数は単に指定されたユーザー名が Bob の「ユーザーデータベース」にあることを確認してから、パスワードを比較するだけです。パスワードが一致すると、ユーザーは認証されます。一致しない場合、認証は失敗します。本番稼働する前に、Bob はこのコードを彼の組織で使用される ID プロバイダーへのコールに置き換えたいと考えるはずです。

ここで注意することは、パスワードの認証に加えて、Bob はキーベースの認証も使用することができ、それでは応答の一部としてユーザーに対して保存されたパブリックキーを返すことが要求されます。

ユーザーが正常に認証されると、ユーザーがアクセスできる S3 バケットと、バケットへのアクセスを制御する IAM ロールを指定することにより、応答が構築されます。

では、Bob が彼のユーザーの論理ディレクトリを構築する方法を見ていきましょう。

論理ディレクトリのエントリ

Bob がサブスクライバーのためのフォルダー構造の構築は、論理ディレクトリを使用して簡単に実行できます。論理ディレクトリでは、1 つ以上の S3 バケットがユーザーに対するシングルネームスペースとして提示できます。このデータを AWS SFTP に返すために、AWS IAM ロールに加えて、Lambda 関数の応答のために JSON ドキュメントに 2 つの追加フィールドが追加されました。HomeDirectoryType およびHomeDirectoryDetailsです。

{ 
  "Role": "ARN of IAM role with configured S3 permissions",
  "Policy": "JSON string of STS Assume role scope down policy",
  "HomeDirectoryType": "LOGICAL",
  "HomeDirectoryDetails": "JSON string of Entry / Target pairs"
}

HomeDirectoryDetails の各論理ディレクトリには、「Entry」 および 「Target」 の 2 つのフィールドが含まれます。「Entry」 はユーザーに表示されるフォルダーの名前で、「Target」 は S3 フォルダーパスです。「Entry」の値は絶対的な UNIX 形式のパスで、先頭は「/」で始まり、後にはスラッシュが続きません。同様に、「Target」 値の先頭はスラッシュで始まり、次に S3 バケット名が入り、その後、キープレフィックスが続き、スラッシュは続きません。それぞれの「Entry」/「Target」ペアは、その他の論理ディレクトリとは独立しており、それぞれの「Target」は必要な場合、異なる S3 バケットをポイントできます。たとえば、下記は Alice のユーザーデータベースの論理ディレクトリのエントリです。

"directoryMap": [
    {
        "Entry": "/public/research",
        "Target": "/"+ public_bucket
    },
    {
        "Entry": "/subscribed/2018/indices",
        "Target": "/"+ subscription_bucket + "/historical/2018/indices"
    },
    {
        "Entry": "/subscribed/2019/indices",
        "Target": "/"+ subscription_bucket + "/historical/2019/indices"
    },
    {
        "Entry": "/subscribed/2019/equities",
        "Target": "/"+ subscription_bucket + "/historical/2019/equities"
    }
]

上記に示したように、Bob にはパブリックバケットとサブスクリプションバケットの 2 つのバケットの論理ディレクトリがあります。彼は、IAM ロール がこれらの両方のバケットに対してアクセスを付与することを確認する必要があります。Check out the AWS SFTP docs for more information on ユーザーの IAM ロールの作成に関する詳細については、AWS SFTP をチェックアウトします。

また、応答 JSON で指定された IAM ロールが S3 バケット全体へのアクセスを提供する場合でも、Bob のエンドユーザーは論理ディレクトリマッピング機能で指定されたフォルダーにのみアクセスできることに注意してください。また、論理ディレクトリを使用する場合、JSONドキュメントの 「HomeDirectory」 フィールドの値は、ユーザーがログインディレクトリとして表示するものを決定するため、それは必要なくなりました。この値は現在、「HomeDirectoryDetails」 リストの「Entry」フィールドに指定する内容により暗示されます。

コード例では、ディレクトリマッピングがユーザーデータベースに保存され、「getDirectoryMapping」関数で直接返すことができます。

function getDirectoryMapping(username) {
    var userRecord = userDb[username];
    return userRecord.directoryMap;
}

Bob の更新済みの Lambda Handler

すべての Lambda 関数には、Lambda 関数の実行が開始される「ハンドラー」と呼ばれるエントリポイントがあります。Bob の Lambda ハンドラーが ID プロバイダーにクエリを送り、正常にユーザーを認証すると、アクセスは IAM ロールと論理ディレクトリを使用して定義されます。Bob の Lambda 関数は AWS SFTP サーバーに次の応答オブジェクトを返します。

response = {
    Role: userRoleArn,
    HomeDirectoryType: "LOGICAL",
    HomeDirectoryDetails: JSON.stringify(directoryMapping)
};

応答オブジェクトは AWS SFTP サーバーに返され、 「HomeDirectoryDetails」で指定されたディレクトリマッピングを使用して、認証済みユーザーに表示されるフォルダーが構築されます。

たとえば、Alice が SFTP クライアントを使用してログインして、正常に認証されるようにしている場合、彼女には次のフォルダー構造が表示されます。

SFTP クライアントを使用してログインして、正常な認証を受けた後のフォルダー構造

まとめ

この記事では、AWS SFTP 論理ディレクトリ、Amazon API Gateway、AWS Lambda 関数を使用して簡単なデータ配信サービスを作成する方法を示しました。AWS SFTP カスタム ID プロバイダーと新しい論理ディレクトリ機能を使用して、きめ細かなフォルダー構造を作成して、ユーザーが S3 バケットのデータにアクセスする方法をコントロールし、SFTP クライアントを使用して参照しやすいエクスペリエンスを提供できます。

環境でこれを使用するには、AWS SFTP ドキュメントで提供されている CloudFormation スタックから開始し、この GitHub リポジトリでサンプルコードを使用して Lambda 関数を修正します。さらに、次のとおり推奨します。

  • 認証された機能を更新して、Amazon Cognito、Active Directory、またはその他の IDプ ロバイダーなどの安全な認証プロバイダーを使用する
  • ハードコーディングされたユーザーデータベースを、おそらく、Amazon Relational Database Service (RDS) または Amazon DynamoDB テーブルを搭載した、よりスケーラブルな資格システムに置き換える
  • ユーザーアクセスをさらに管理するか、エンドユーザーにデータセットをアドバタイズする方法として、スコープダウンポリシーを調べる