AWS Transfer FamilyでS3のファイルをSFTPで取得可能にする

# はじめに
AWS Transfer Familyとは、S3やEFSといったストレージサービスに SFTP、FTP、FTPSのプロトコルで送受信を行うことができるフルマネージド型のサービス。
今回、Lambdaで生成した顧客納品用のCSVファイルをS3に格納しており、定期実行される顧客側のバッチにより取得可能とするアーキテクチャを構成する際に使用した。

# サーバーの作成
まず必要となるのが送受信に使用するサーバーとなる。
作成時の手順を順を追って記載。

#### プロトコル
はじめにプロトコルを選択する。
ここではSFTPとした。
![スクリーンショット 2023-07-10 23.10.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/b3859b7a-2544-30a7-a3cd-7c69f61383c6.png)
#### SFTPユーザー管理
続いてSFTPでの接続時に利用するユーザーの管理法を選択。



- サービスマネージド（特に設定項目がないためスクショなし）
    - ユーザーを複数作成して個別の設定（秘密鍵、接続先や接続設定）をすることが可能
    - ID/PWでの認証不可
- AWS Directory Service（詳細割愛）
    - Active Directoryを使用した認証法
- カスタム ID プロバイダー
    - ユーザーを複数作成して個々の設定をすることが不可
    - APIGatewayやLambdaで認証可能
    - ユーザー名、パスワード、接続先（S3バケット、フォルダなど）をLambda側で指定

以下Lambda例
```python
def lambda_handler(event, context):
    if event["username"] == "test-user" and event["password"] == "test-pw":
    # Secrets Managerを使用すると良いか
        return { 
            'Role': 'arn:aws:iam::123456789:role/transfer-family-custom-id-provider-test-role',
            'HomeDirectory': '/test/20230710/'
        }
    else:
        return {}
```
![スクリーンショット 2023-07-10 23.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/cc2c1543-6593-596e-0b44-419b8fc9bc67.png)

#### エンドポイント
設定パターンは以下3種類。

- インターネット向け
    - パブリックアクセス可能（①）
        - IP制限不可
    - VPCでホスト（②）
        - SGによってIP制限可
        - VPCはigwと接続しておくのみでOK
        - EIP必須
- 内部向け（③）
    - VPCでホスト
    - プライベート IP アドレスを使用してのみエンドポイントからクライアントにアクセス可
    - NLBとネットワーク ACLを併用することでインターネット経由アクセスも併用可


つまりざっくり言うとこう。
```
①エンドポイント、ID/PWを知っていれば誰でもどこからでも接続可能
②SGで許可されていれば接続可能
③同一VPCであったりピアリング接続などされているリソースからであれば接続可能
```

今回はVPC外の顧客が接続しに来るので②を選択。
以下が実際の設定画面。

![スクリーンショット 2023-07-10 23.49.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/a61a3f02-74b3-76fb-11d7-46e21e088b18.png)

尚、カスタムホスト名を設定することで、Route53などに登録されているドメインをエンドポイントとすることも可能。

https://dev.classmethod.jp/articles/from-ec2-to-transfer/

#### ドメイン
どのストレージサービスに対しSFTP接続可能とするかの選択。
S3かEFSを選択する。

![スクリーンショット 2023-07-11 21.09.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/aa089141-242c-3866-bf93-aa24b0139f43.png)

#### ログ記録

SFTP接続時のログが記録できる。
基本的には新しいロググループを作成する。

![スクリーンショット 2023-07-11 21.29.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/572e014f-d6cc-e974-0462-983dc19c4ff9.png)


#### マネージドワークフロー

転送されたファイルに対して処理を実行するワークフローを以下5種類から指定できる

- 指定したS3バケット内の特定の場所にコピー
- タグ付け
- 転送されたファイルの削除（コピーして削除すれば移動を実現できる）
- Lambdaによるカスタム処理
- ファイルの復号（新機能のようで調べきれていない）

「完全なファイルアップロードのワークフロー」と「部分的なファイルアップロードのワークフロー」があるが、
完全なファイルアップロードはそのままの意味で、アップロードに成功した場合を指し、
部分的なファイルアップロードとは、セッションが途中で切断された場合などを指す。

ワークフローを実行するためには、「マネージドワークフロー実行ロール」をアタッチする必要がある。

![スクリーンショット 2023-07-11 21.20.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/aa325844-3153-8907-2417-2d592869681b.png)

![スクリーンショット 2023-07-11 21.22.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/0a1247a7-8a32-d044-6d0e-06d2c3db2d65.png)



![スクリーンショット 2023-07-11 21.24.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/f24a0b0f-bab8-8229-34ba-8320d118c0d0.png)

#### 暗号化

暗号化アルゴリズムのオプションはデフォルトのままでOK。
サーバーホストキーは以下記載の通り。
> 既存の SFTP サーバーからユーザーを移行する場合を除き、このセクションは無視できる。


![スクリーンショット 2023-07-11 21.31.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/b57be990-fa39-1dd9-be33-172505737d3d.png)

この他いくつか設定項目があるが一旦デフォルトのままでOK。
続いてユーザー作成。

# ユーザー作成

サーバー作成時に「サービスマネージド」での認証にした場合にユーザーを作成する。

![スクリーンショット 2023-07-11 21.37.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/b69ac9f8-375c-d5de-cf55-0bbe75831d69.png)

ただこの前に、ユーザーがTransfer Familyにアクセスする権限が必要となるため、あらかじめロールを作成しておく。
例えば以下のようなポリシーとなる。
こうすることで、`transfer-family-test-bucket`というバケットとその配下の`hogehoge`ディレクトリ配下へのアクセスが可能となる

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::transfer-family-test-bucket/hogehoge/*",
                "arn:aws:s3:::transfer-family-test-bucket"
            ]
        }
    ]
}
```
以下ユーザー作成画面。
ロールは先程作成したものを設定する。（キャプチャでは適当に選択しているだけなので命名が適当）

![スクリーンショット 2023-07-11 21.44.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/e87f0c83-c306-930f-0ecf-3b44bbeaebbf.png)

「ポリシー」という項目では、ロールとは別で「スコープダウンポリシー」というものを設定できる。
スコープダウンポリシーとは、ユーザーのアクセスをある一部のホームディレクトリ（バケット/フォルダ）のみに制限できる機能。

各ユーザーの権限をIAMロールで制御することももちろん可能だが、Transfer Familyで用意したポリシー変数である`${transfer:HomeBucket}` `${transfer:HomeDirectory}` `${transfer:HomeFolder}` `${transfer:UserName}`などの使用が可能。

この機能がないと、ユーザーごとにアクセスできるバケットを分けたい場合、ユーザーごとにポリシーを作成しなければならない。
一方スコープダウンポリシーでは、これらの変数をユーザー名やホームディレクトリの適切な値に置き換えてくれるので、柔軟に複数ユーザーで同じポリシードキュメントを使うことができる。
ちなみに以下2つの違いが曖昧だったのでメモ。

```
HomeDirectory = バケット名を含んだディレクトリ
HomeFolder = バケットから下のフォルダ
```

https://dev.classmethod.jp/articles/transfer-family-wildcard-scope-down-policy/

「ホームフォルダに基づくポリシーの自動生成」を選択し「表示」を押すと、勝手にポリシーを表示してくれるのでとても便利。

![スクリーンショット 2023-07-11 21.56.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/e2ba8f17-b69b-e63a-5907-ec7226b2bf3f.png)

![スクリーンショット 2023-07-11 21.57.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1131391/d3dcfe3a-f5b5-c568-a830-e3ce650a70ac.png)

キャプチャでは収まらなかったが実際のドキュメントはこんな感じ。
```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowListingOfUserFolder",
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::${transfer:HomeBucket}"
      ],
      "Condition": {
        "StringLike": {
          "s3:prefix": [
            "${transfer:HomeFolder}/*",
            "${transfer:HomeFolder}"
          ]
        }
      }
    },
    {
      "Sid": "HomeDirObjectAccess",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::${transfer:HomeDirectory}*"
    }
  ]
}
```

最後に「制限付き」という項目について。
これは、コンソールから確認できる通り以下のような設定。
同じサーバーで複数顧客からの接続を許可する場合などに有効かと思われる。
> ユーザーはフォルダ外のものにアクセスできず、S3 バケットやフォルダ名も表示できなくなります。

あとはSSHパブリックキーを設定して完了。
キーの作成法は以下記事などを参照。

https://qiita.com/suthio/items/2760e4cff0e185fe2db9

これで準備は整ったので、好きにS3からファイルを取っていってもらえるようになった。