

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

# AWS Lambda を使用して ID プロバイダーを統合する
<a name="custom-lambda-idp"></a>

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

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

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

1. [AWS Transfer Family コンソール](https://console.aws.amazon.com/transfer/)を開きます。

1. [**Create server**] (サーバーの作成) を選択すると [**Create server**] (サーバーの作成) ページが開きます。[**Choose an identity provider**] (ID プロバイダーの選択) で [**Custom Identity Provider**] (カスタム ID プロバイダー) を選択します (次の画面例を参照)。  
![\[[ID プロバイダーの選択] コンソールセクションで、[カスタム ID プロバイダー] が選択されています。また、ユーザーはパスワードまたはキーのいずれかを使用して認証できるというデフォルト値が選択されています。\]](http://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/images/custom-lambda-console.png)
**注記**  
認証方法を選択できるのは、Transfer Familyサーバーのプロトコルの1つとしてSFTPを有効にした場合のみです。

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

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

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

## Lambda リソースベースのポリシー
<a name="lambda-resource-policy"></a>

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\"}}}
]}"
```

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

## イベントメッセージの構造
<a name="event-message-structure"></a>

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 関数
<a name="authentication-lambda-examples"></a>

さまざまな認証戦略を実装するには、Lambda 関数を編集します。アプリケーションのニーズを満たすために、CloudFormation スタックをデプロイできます。Lambda の詳細については、[AWS Lambda デベロッパーガイド](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)または「[Node.js による Lambda 関数の構築](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html)」を参照してください。

**Topics**
+ [有効な Lambda 値](#lambda-valid-values)
+ [Lambda 関数の例](#lambda-auth-examples)
+ [設定をテストする](#authentication-test-configuration)
+ [Lambda 関数のテンプレート](#lambda-idp-templates)

### 有効な Lambda 値
<a name="lambda-valid-values"></a>

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


|  値  |  説明  |  必須  | 
| --- | --- | --- | 
|  `Role`  |  Amazon S3 バケットまたは Amazon EFS ファイルシステムへのユーザーのアクセスを制御する IAM ロールの Amazon Resource Name (ARN) を指定します。このロールにアタッチされたポリシーにより、ファイルを Amazon S3 または Amazon EFS ファイルシステム間で転送する際のユーザーに付与するアクセスのレベルが決定されます。IAM ロールには、ユーザーの転送リクエストを処理する際に、サーバーによるリソースへのアクセスを許可する信頼関係も含まれる必要があります。 信頼関係の確立の詳細については、[信頼関係を確立するには](requirements-roles.md#establish-trust-transfer) を参照してください。  |  必須  | 
|  `PosixProfile`  |  ユーザーの Amazon EFS ファイルシステムへのアクセスを制御する、ユーザー ID (`Uid`)、グループ ID (`Gid`)、およびセカンダリグループ ID (`SecondaryGids`) を含む完全な POSIX ID。ファイルシステム内のファイルとディレクトリに設定される POSIX アクセス許可によって、Amazon EFS ファイルシステムとの間でファイルを転送するときにユーザーが得るアクセスのレベルが決まります。  |  Amazon EFS バッキングストレージに必須  | 
|  `PublicKeys`  |  このユーザーに有効な SSH パブリックキー値のリスト。空のリストはこれが有効なログインではないことを示します。パスワード認証中に返してはなりません。  |  オプションです。  | 
|  `Policy`  |  複数のユーザーに同じ IAM ロールの使用を可能にするユーザーのセッションポリシー。このポリシーは、ユーザーアクセスのスコープを Amazon S3 バケットの一部に絞り込みます。カスタム ID プロバイダーでセッションポリシーを使用する方法の詳細については、このトピックのセッションポリシーの例を参照してください。  |  オプションです。  | 
|  `HomeDirectoryType`  |  ユーザーがサーバーにログインするときにホームディレクトリにするランディングディレクトリ (フォルダ) のタイプ。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/custom-lambda-idp.html)  |  オプションです。  | 
|  `HomeDirectoryDetails`  |  ユーザーに表示する Amazon S3 または Amazon EFS のパスとキー、およびそれらをどのように表示するかを指定する論理ディレクトリマッピング。「`Entry`」と「`Target`」のペアを指定する必要があり、`Entry` はパスの表示方法を示し、`Target` は実際の Amazon S3 または Amazon EFS のパスです。  |  `HomeDirectoryType` に `LOGICAL` の値がある場合に必須  | 
|  `HomeDirectory`  |  ユーザーがクライアントを使用してサーバーにログインするときの、ユーザーのランディングディレクトリ。形式はストレージバックエンドによって異なります。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/custom-lambda-idp.html)  バケット名または 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 関数の例
<a name="lambda-auth-examples"></a>

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

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

------
#### [ Logical home directory, NodeJS ]

以下の NodeJS サンプル関数は、「[論理ホームディレクトリ](https://docs.aws.amazon.com/transfer/latest/userguide/logical-dir-mappings.html)」を持つユーザーの詳細を提供します。

```
// 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 サンプル関数は、「[論理ホームディレクトリ](https://docs.aws.amazon.com/transfer/latest/userguide/logical-dir-mappings.html)」を持つユーザーの詳細を提供します。

```
# 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
```

------

### 設定をテストする
<a name="authentication-test-configuration"></a>

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

------
#### [ Console ]

**AWS Transfer Family コンソールを使用して設定をテストするには**

1. [AWS Transfer Family コンソール](https://console.aws.amazon.com/transfer/)を開きます。

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

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

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

------
#### [ CLI ]

**AWS CLI を使用して設定をテストするには**

1. [test-identity-provider](https://docs.aws.amazon.com/cli/latest/reference/transfer/test-identity-provider.html) コマンドを実行します。以降のステップで説明するように、それぞれの `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
   ```

1. サーバー ID を入力します。

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

1.  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 関数のテンプレート
<a name="lambda-idp-templates"></a>

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

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

**認証に使用する CloudFormation スタックを作成するには**

1. [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/) で CloudFormation コンソールを開きます。

1. 「 *AWS CloudFormation ユーザーガイド*」の CloudFormation 「スタックテンプレート[の選択」の「既存のテンプレートからスタックを](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-using-console-create-stack-template.html)デプロイする手順」に従います。

1. 以下のテンプレートのいずれかを使用して、Transfer Family で認証に使用するLambda 関数を作成します。
   + [クラシック (Amazon Cognito) スタックテンプレート](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-basic-lambda-cognito-s3.template.yml)

     でカスタム ID プロバイダーとして使用する AWS Lambda を作成するための基本的なテンプレート AWS Transfer Family。Amazon Cognito に対してパスワードベースの認証を行い、パブリックキーベースの認証が使用されている場合、パブリックキーは Amazon S3 バケットから返されます。デプロイ後に Lambda 関数コードを変更すれば異なる処理を実行できます。
   + [AWS Secrets Manager スタックテンプレート](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-secrets-manager-lambda.template.yml)

     と AWS Transfer Family サーバー AWS Lambda を使用して Secrets Manager を ID プロバイダーとして統合する基本的なテンプレート。形式の AWS Secrets Manager のエントリに対して認証されます`aws/transfer/server-id/username`。さらに、シークレットは、Transfer Family に返されるすべてのユーザープロパティのキーバリューペアを保持する必要があります。デプロイ後に Lambda 関数コードを変更すれば異なる処理を実行できます。
   + [Okta スタックテンプレート](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-okta-lambda.template.yml): を AWS Transfer Family サーバー AWS Lambda で使用する基本テンプレートで、Okta をカスタム ID プロバイダーとして統合します。
   + [Okta-mfa スタックテンプレート](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-okta-mfa-lambda.template.yml): を AWS Transfer Family サーバー AWS Lambda で使用する基本テンプレートで、カスタム ID プロバイダーとして Okta を多要素認証と統合します。
   + [ Azure Active Directory テンプレート](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-basic-lambda-azure-ad.template.yml): このスタックの詳細については、ブログ記事[「Authenticating to AWS Transfer Family with Azure Active Directory and AWS Lambda](https://aws.amazon.com/blogs/storage/authenticating-to-aws-transfer-family-with-azure-active-directory-and-aws-lambda/)」を参照してください。

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

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