View a markdown version of this page

AWS Lambda を使用して ID プロバイダーを統合する - AWS Transfer Family

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

AWS Lambda を使用して ID プロバイダーを統合する

このトピックでは、カスタム ID プロバイダーに接続する AWS Lambda 関数を作成する方法について説明します。Okta、Secrets Manager、OneLogin や、認可および認証ロジックを含むカスタムデータストアなど、任意のカスタム ID プロバイダーを使用できます。

ほとんどのユースケースでは、カスタム ID プロバイダーを設定する推奨方法は、 を使用することですカスタム ID プロバイダーソリューション。

注記

Lambda を ID プロバイダーとして使用する Transfer Family サーバーを作成する前に、関数を作成する必要があります。サンプルの Lambda 関数については、「Lambda 関数の例」を参照してください。あるいは、いずれかの Lambda 関数のテンプレート を使用する CloudFormation スタックをデプロイすることもできます。また、Lambda 関数が Transfer Family と信頼関係にあるリソースベースのポリシーを使用していることを確認してください。ポリシーの例については「Lambda リソースベースのポリシー」を参照してください。

  1. AWS Transfer Family コンソールを開きます。

  2. [Create server] (サーバーの作成) を選択すると [Create server] (サーバーの作成) ページが開きます。[Choose an identity provider] (ID プロバイダーの選択) で [Custom Identity Provider] (カスタム ID プロバイダー) を選択します (次の画面例を参照)。

    [ID プロバイダーの選択] コンソールセクションで、[カスタム ID プロバイダー] が選択されています。また、ユーザーはパスワードまたはキーのいずれかを使用して認証できるというデフォルト値が選択されています。
    注記

    認証方法を選択できるのは、Transfer Familyサーバーのプロトコルの1つとしてSFTPを有効にした場合のみです。

  3. デフォルト値である AWS Lambda を使用して ID プロバイダーを接続します。

  4. 「AWS Lambda 関数」では、Lambda 関数の名前を選択します。

  5. 残りのフィールドに値を入力してから [Create server] (サーバーの作成) を選択します。サーバーを作成するための残りの手順の詳細については、「SFTP、FTPS、または FTP サーバーエンドポイントの設定」を参照してください。

Lambda リソースベースのポリシー

Transfer Family サーバーと Lambda ARN を参照するポリシーが必要です。たとえば、ID プロバイダーに接続する Lambda 関数で次のポリシーを使用できます。ポリシーは、JSON で文字列としてエスケープされます。

"Policy": "{\"Version\":\"2012-10-17\", \"Id\":\"default\", \"Statement\":[ {\"Sid\":\"AllowTransferInvocation\", \"Effect\":\"Allow\", \"Principal\":{\"Service\":\"transfer.amazonaws.com\"}, \"Action\":\"lambda:InvokeFunction\", \"Resource\":\"arn:aws:lambda:region:123456789012:function:my-lambda-auth-function\", \"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:transfer:region:123456789012:server/server-id\"}}} ]}"
注記

上記のポリシー例では、各「ユーザー入力プレースホルダー」をあなた自身の情報で置き換えます。

イベントメッセージの構造

SFTP サーバーからカスタム IDP のオーソライザー Lambda 関数に送信されるイベントメッセージ構造は次のとおりです。

{ "username": "value", "password": "value", "protocol": "SFTP", "serverId": "s-abcd123456", "sourceIp": "192.168.0.100" }

ここで、usernameおよびpasswordはサーバーに送信されるサインイン認証情報の値です。

例えば、以下のコマンドを入力して接続する:

sftp bobusa@server_hostname

その後、パスワードの入力を求められる:

Enter password: mysecretpassword

Lambda 関数内から渡されたイベントを出力することで、Lambda 関数からこれを確認できます。以下のテキストブロックのように見えるはずです。

{ "username": "bobusa", "password": "mysecretpassword", "protocol": "SFTP", "serverId": "s-abcd123456", "sourceIp": "192.168.0.100" }

イベントの構造は FTP と FTPS で似ています。唯一の違いは、SFTP ではなく、これらの値がprotocolパラメータに使用されることです。

認証用の Lambda 関数

さまざまな認証戦略を実装するには、Lambda 関数を編集します。アプリケーションのニーズを満たすために、CloudFormation スタックをデプロイできます。Lambda の詳細については、AWS Lambda デベロッパーガイドまたは「Node.js による Lambda 関数の構築」を参照してください。

有効な Lambda 値

次の表は、カスタム ID プロバイダーに使用される Lambda 関数について Transfer Family が受け入れる値の詳細についての説明です。

値 説明 必須

Role

Amazon S3 バケットまたは Amazon EFS ファイルシステムへのユーザーのアクセスを制御する IAM ロールの Amazon Resource Name (ARN) を指定します。このロールにアタッチされたポリシーにより、ファイルを Amazon S3 または Amazon EFS ファイルシステム間で転送する際のユーザーに付与するアクセスのレベルが決定されます。IAM ロールには、ユーザーの転送リクエストを処理する際に、サーバーによるリソースへのアクセスを許可する信頼関係も含まれる必要があります。

信頼関係の確立の詳細については、信頼関係を確立するには を参照してください。

必須

PosixProfile

ユーザーの Amazon EFS ファイルシステムへのアクセスを制御する、ユーザー ID (Uid)、グループ ID (Gid)、およびセカンダリグループ ID (SecondaryGids) を含む完全な POSIX ID。ファイルシステム内のファイルとディレクトリに設定される POSIX アクセス許可によって、Amazon EFS ファイルシステムとの間でファイルを転送するときにユーザーが得るアクセスのレベルが決まります。

Amazon EFS バッキングストレージに必須

PublicKeys

このユーザーに有効な SSH パブリックキー値のリスト。空のリストはこれが有効なログインではないことを示します。パスワード認証中に返してはなりません。

オプションです。

Policy

複数のユーザーに同じ IAM ロールの使用を可能にするユーザーのセッションポリシー。このポリシーは、ユーザーアクセスのスコープを Amazon S3 バケットの一部に絞り込みます。カスタム ID プロバイダーでのセッションポリシーの使用の詳細については、このトピックのセッションポリシーの例を参照してください。

オプションです。

HomeDirectoryType

ユーザーがサーバーにログインするときにホームディレクトリにするランディングディレクトリ (フォルダ) のタイプ。

  • PATH に設定した場合、ユーザーにはファイル転送プロトコルクライアント内の Amazon S3 バケットまたは Amazon EFS の絶対パスが表示されます。

  • LOGICAL に設定した場合、Amazon S3 または Amazon EFS のパスをユーザーから見えるようにするには、HomeDirectoryDetails パラメーターでマッピングを提供する必要があります。

オプションです。

HomeDirectoryDetails

ユーザーに表示する Amazon S3 または Amazon EFS のパスとキー、およびそれらをどのように表示するかを指定する論理ディレクトリマッピング。「Entry」と「Target」のペアを指定する必要があり、Entry はパスの表示方法を示し、Target は実際の Amazon S3 または Amazon EFS のパスです。

HomeDirectoryType に LOGICAL の値がある場合に必須

HomeDirectory

ユーザーがクライアントを使用してサーバーにログインするときの、ユーザーのランディングディレクトリ。形式はストレージバックエンドによって異なります。

  • Amazon S3 の場合: /bucket-name/user-home-directory

    例: /amzn-s3-demo-bucket/users/john

  • Amazon EFS の場合: /fs-12345/user-home-directory

    例: /fs-faa1a123/users/john

重要

バケット名または Amazon EFS ファイルシステム ID をパスに含める必要があります。この情報を省略すると、ファイル転送中に「ファイルが見つかりません」エラーが発生します。

オプションです。

注記

HomeDirectoryDetailsはJSON マップの文字列表現です。これは、実際のJSONマップ・オブジェクトであるPosixProfileや、文字列のJSON配列であるPublicKeysとは対照的です。言語固有の詳細については、コード例を参照してください。

HomeDirectory 形式の要件

HomeDirectory パラメータを使用する場合は、完全なパス形式を含めてください。

  • Amazon S3 ストレージの場合: バケット名は常に 形式で含めます。 /bucket-name/path

  • Amazon EFS ストレージの場合: ファイルシステム ID は必ず 形式で含めます。 /fs-12345/path

「ファイルが見つかりません」エラーの一般的な原因は、HomeDirectoryパスからバケット名または EFS ファイルシステム ID を省略することです。ストレージ識別子/なしで HomeDirectoryを に設定すると、認証は成功しますが、ファイルオペレーションは失敗します。

Lambda 関数の例

このセクションでは、NodeJS と Python の両方で使用される Lambda 関数の例をいくつか紹介します。

注記

これらの例では、ユーザー、ロール、POSIX プロファイル、パスワード、ホームディレクトリの詳細はすべて例であり、実際の値に置き換える必要があります。

Logical home directory, NodeJS

以下の NodeJS サンプル関数は、「論理ホームディレクトリ」を持つユーザーの詳細を提供します。

// GetUserConfig Lambda exports.handler = (event, context, callback) => { console.log("Username:", event.username, "ServerId: ", event.serverId); var response; // Check if the username presented for authentication is correct. This doesn't check the value of the server ID, only that it is provided. if (event.serverId !== "" && event.username == 'example-user') { var homeDirectoryDetails = [ { Entry: "/", Target: "/fs-faa1a123" } ]; response = { Role: 'arn:aws:iam::123456789012:role/transfer-access-role', // The user is authenticated if and only if the Role field is not blank PosixProfile: {"Gid": 65534, "Uid": 65534}, // Required for EFS access, but not needed for S3 HomeDirectoryDetails: JSON.stringify(homeDirectoryDetails), HomeDirectoryType: "LOGICAL", }; // Check if password is provided if (!event.password) { // If no password provided, return the user's SSH public key response['PublicKeys'] = [ "ssh-rsa abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" ]; // Check if password is correct } else if (event.password !== 'Password1234') { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } } else { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } callback(null, response); };
Path-based home directory, NodeJS

以下の NodeJS サンプル関数は、パスベースのホーム・ディレクトリを持つユーザーの詳細を提供します。

// GetUserConfig Lambda exports.handler = (event, context, callback) => { console.log("Username:", event.username, "ServerId: ", event.serverId); var response; // Check if the username presented for authentication is correct. This doesn't check the value of the server ID, only that it is provided. // There is also event.protocol (one of "FTP", "FTPS", "SFTP") and event.sourceIp (e.g., "127.0.0.1") to further restrict logins. if (event.serverId !== "" && event.username == 'example-user') { response = { Role: 'arn:aws:iam::123456789012:role/transfer-access-role', // The user is authenticated if and only if the Role field is not blank Policy: '', // Optional, JSON stringified blob to further restrict this user's permissions // HomeDirectory format depends on your storage backend: // For S3: '/bucket-name/user-home-directory' (e.g., '/my-transfer-bucket/users/john') // For EFS: '/fs-12345/user-home-directory' (e.g., '/fs-faa1a123/users/john') HomeDirectory: '/my-transfer-bucket/users/example-user' // S3 example - replace with your bucket name // HomeDirectory: '/fs-faa1a123/users/example-user' // EFS example - uncomment for EFS }; // Check if password is provided if (!event.password) { // If no password provided, return the user's SSH public key response['PublicKeys'] = [ "ssh-rsa abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" ]; // Check if password is correct } else if (event.password !== 'Password1234') { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } } else { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } callback(null, response); };
Logical home directory, Python

以下の Python サンプル関数は、「論理ホームディレクトリ」を持つユーザーの詳細を提供します。

# GetUserConfig Python Lambda with LOGICAL HomeDirectoryDetails import json def lambda_handler(event, context): print("Username: {}, ServerId: {}".format(event['username'], event['serverId'])) response = {} # Check if the username presented for authentication is correct. This doesn't check the value of the server ID, only that it is provided. if event['serverId'] != '' and event['username'] == 'example-user': homeDirectoryDetails = [ { 'Entry': '/', 'Target': '/fs-faa1a123' } ] response = { 'Role': 'arn:aws:iam::123456789012:role/transfer-access-role', # The user will be authenticated if and only if the Role field is not blank 'PosixProfile': {"Gid": 65534, "Uid": 65534}, # Required for EFS access, but not needed for S3 'HomeDirectoryDetails': json.dumps(homeDirectoryDetails), 'HomeDirectoryType': "LOGICAL" } # Check if password is provided if event.get('password', '') == '': # If no password provided, return the user's SSH public key response['PublicKeys'] = [ "ssh-rsa abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" ] # Check if password is correct elif event['password'] != 'Password1234': # Return HTTP status 200 but with no role in the response to indicate authentication failure response = {} else: # Return HTTP status 200 but with no role in the response to indicate authentication failure response = {} return response
Path-based home directory, Python

以下の Python サンプル関数は、パスベースのホームディレクトリを持つユーザーの詳細を提供します。

# GetUserConfig Python Lambda with PATH HomeDirectory def lambda_handler(event, context): print("Username: {}, ServerId: {}".format(event['username'], event['serverId'])) response = {} # Check if the username presented for authentication is correct. This doesn't check the value of the server ID, only that it is provided. # There is also event.protocol (one of "FTP", "FTPS", "SFTP") and event.sourceIp (e.g., "127.0.0.1") to further restrict logins. if event['serverId'] != '' and event['username'] == 'example-user': response = { 'Role': 'arn:aws:iam::123456789012:role/transfer-access-role', # The user will be authenticated if and only if the Role field is not blank 'Policy': '', # Optional, JSON stringified blob to further restrict this user's permissions # HomeDirectory format depends on your storage backend: # For S3: '/bucket-name/user-home-directory' (e.g., '/my-transfer-bucket/users/john') # For EFS: '/fs-12345/user-home-directory' (e.g., '/fs-faa1a123/users/john') 'HomeDirectory': '/my-transfer-bucket/users/example-user', # S3 example - replace with your bucket name # 'HomeDirectory': '/fs-faa1a123/users/example-user', # EFS example - uncomment for EFS 'HomeDirectoryType': "PATH" # Not strictly required, defaults to PATH } # Check if password is provided if event.get('password', '') == '': # If no password provided, return the user's SSH public key response['PublicKeys'] = [ "ssh-rsa abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" ] # Check if password is correct elif event['password'] != 'Password1234': # Return HTTP status 200 but with no role in the response to indicate authentication failure response = {} else: # Return HTTP status 200 but with no role in the response to indicate authentication failure response = {} return response

設定をテストする

カスタム ID プロバイダーを作成したら、設定をテストする必要があります。

Console
AWS Transfer Family コンソールを使用して設定をテストするには
  1. AWS Transfer Family コンソールを開きます。

  2. [Servers] (サーバー) ページで新しいサーバーを選択し、[Actions] (アクション) を選択してから [Test] (テスト) を選択します。

  3. CloudFormation スタックをデプロイしたときに設定したユーザー名とパスワードのテキストを入力します。デフォルトのオプションのままだと、ユーザー名は myuser、パスワードは MySuperSecretPassword となります。

  4. CloudFormation スタックをデプロイしたときに設定した場合は、サーバープロトコルを選択し、送信元 IP の IP アドレスを入力します。

CLI
AWS CLI を使用して設定をテストするには
  1. test-identity-provider コマンドを実行します。以降のステップで説明するように、それぞれの user input placeholder を独自の情報に置き換えます。

    aws transfer test-identity-provider --server-id s-1234abcd5678efgh --user-name myuser --user-password MySuperSecretPassword --server-protocol FTP --source-ip 127.0.0.1
  2. サーバー ID を入力します。

  3. CloudFormation スタックをデプロイしたときに設定したユーザー名とパスワードを入力します。デフォルトのオプションのままだと、ユーザー名は myuser、パスワードは MySuperSecretPassword となります。

  4. CloudFormation スタックのデプロイ時に設定する場合は、サーバープロトコルとソース IP アドレスを入力します。

ユーザー認証が成功した場合、テストはStatusCode: 200 HTTP レスポンス、空の文字列Message: ""(これがなければ失敗の理由を含む)、およびResponseフィールドを返します。

注記

以下のレスポンス例では、Responseフィールドは「文字列化」された (プログラム内で使用できるフラットな JSON 文字列に変換された) JSON オブジェクトで、ユーザーのロールと権限の詳細が含まれています。

{ "Response":"{\"Policy\":\"{\\\"Version\\\":\\\"2012-10-17\\\",\\\"Statement\\\":[{\\\"Sid\\\":\\\"ReadAndListAllBuckets\\\",\\\"Effect\\\":\\\"Allow\\\",\\\"Action\\\":[\\\"s3:ListAllMybuckets\\\",\\\"s3:GetBucketLocation\\\",\\\"s3:ListBucket\\\",\\\"s3:GetObjectVersion\\\",\\\"s3:GetObjectVersion\\\"],\\\"Resource\\\":\\\"*\\\"}]}\",\"Role\":\"arn:aws:iam::000000000000:role/MyUserS3AccessRole\",\"HomeDirectory\":\"/\"}", "StatusCode": 200, "Message": "" }

Lambda 関数のテンプレート

認証に Lambda 関数を使用する CloudFormation スタックをデプロイできます。ログイン認証情報を使用してユーザーを認証および認可するテンプレートがいくつか用意されています。これらのテンプレートまたは AWS Lambda コードを変更して、ユーザーアクセスをさらにカスタマイズできます。

注記

テンプレートで FIPS 対応セキュリティポリシーを指定 CloudFormation することで、 を使用して FIPS 対応 AWS Transfer Family サーバーを作成できます。使用可能なセキュリティポリシーについては、AWS Transfer Family サーバーのセキュリティポリシーで説明しています。

認証に使用する CloudFormation スタックを作成するには
  1. https://console.aws.amazon.com/cloudformation で CloudFormation コンソールを開きます。

  2. AWS CloudFormation 「 ユーザーガイド」の CloudFormation 「スタックテンプレートの選択」の「既存のテンプレートからスタックをデプロイする手順」に従います。

  3. 以下のテンプレートのいずれかを使用して、Transfer Family で認証に使用するLambda 関数を作成します。

    • クラシック (Amazon Cognito) スタックテンプレート

      でカスタム ID プロバイダーとして使用する AWS Lambda を作成するための基本的なテンプレート AWS Transfer Family。Amazon Cognito に対してパスワードベースの認証を行い、パブリックキーベースの認証が使用されている場合、パブリックキーは Amazon S3 バケットから返されます。デプロイ後に Lambda 関数コードを変更すれば異なる処理を実行できます。

    • AWS Secrets Manager スタックテンプレート

      と AWS Transfer Family サーバー AWS Lambda を使用して Secrets Manager を ID プロバイダーとして統合する基本的なテンプレート。形式の AWS Secrets Manager のエントリに対して認証されますaws/transfer/server-id/username。さらに、シークレットは、Transfer Family に返されるすべてのユーザープロパティのキーバリューペアを保持する必要があります。デプロイ後に Lambda 関数コードを変更すれば異なる処理を実行できます。

    • Okta スタックテンプレート: が AWS Transfer Family サーバー AWS Lambda と使用して Okta をカスタム ID プロバイダーとして統合する基本テンプレート。

    • Okta-mfa スタックテンプレート: を AWS Transfer Family サーバー AWS Lambda で使用する基本テンプレートで、カスタム ID プロバイダーとして Okta を多要素認証と統合します。

    • Azure Active Directory テンプレート: このスタックの詳細については、ブログ記事「Authenticating to AWS Transfer Family with Azure Active Directory and AWS Lambda」を参照してください。

    スタックのデプロイ後には、CloudFormation コンソールの [Output] (出力) にタブにスタックについての詳細が表示されます。

    これらのスタックのいずれかをデプロイすることが、カスタム ID プロバイダーをTransfer Family ワークフローに統合するうえで最も簡単な方法です。