AWS Transfer Family で SFTP サーバーを構築して閉域のオンプレミスからエンドポイント経由で S3 にアクセスする

システム間で認証認可が必要なファイル連携をすることを考える時、例えば連携したいシステムがいずれも AWS に構築しているのであれば、Amazon S3 を使うのが効率的です。

ここで、地方公共団体情報システムの標準化における標準準拠システム間でファイル連携をする場合は、オブジェクトストレージを使った連携を行う仕様となっており、閉域の環境からオブジェクトストレージにアクセスした上で、通信を暗号化し、認証認可も必要なことから、AWS 環境同士の連携であれば S3 を使った連携を構築することが多いです。

一方、AWS と他の CSP 環境、オンプレミスとの連携をする場合でかついずれも閉域である場合、AWS のマネージドサービスだけでは認証認可が行えないため、個別に認証認可サーバーを立てるなどの対応が必要です。

認証認可サーバーの管理は手間がかかるため、なるべく AWS のマネージドサービスに寄せつつ、オブジェクトストレージを使った、暗号化通信が可能で、認証認可も行えるサービスを考えた時、AWS Transfer Family で SFTP サーバーを構築することが候補となります。

AWS Transfer Family であれば、認証に関するユーザー管理を AWS 側で行うことができ、かつ IAM ロール、IAM ポリシーでバケットに対するアクセス権限を管理することができます。

そこで、ガバメントクラウド環境で使うことを想定し、閉域のオンプレミスと AWS を接続し、オンプレミスのクライアントから Transfer Family の VPC エンドポイント経由で、SFTP で S3 バケットにファイルを連携する構成について試してみました。

## 構築する Transfer Family 検証環境の概要

1. 内部向けの VPC エンドポイントしか持たない Transfer Family の SFTP サーバーを立てます。
2. VPN で VPC に接続している閉域のオンプレミス環境の SFTP クライアントから、Transfer Family の VPC エンドポイント経由でアクセスします。
3. 閉域のオンプレミス環境の DNS と Route 53 インバウンドエンドポイントを連携し、独自のドメイン名で Transfer Family の VPC エンドポイントへアクセスできるようにします。

![TransferFamily.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/fd023e6b-ba94-44b9-82a4-3693211bd7d6.png)

## Transfer Family SFTP サーバーの作成

Transfer Family のマネージメントコンソールから SFTP サーバーを作成します。

![スクリーンショット 2025-06-07 11.52.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/750ab577-a43b-4463-8669-0fcf1a9c4acd.png)

ID プロバイダーの選択は、ユーザーの作成を Transfer Family 側に任せたいので「サービスマネージド」を選択します。

![スクリーンショット 2025-06-07 11.52.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/bfee55ec-853e-4686-b3e9-05a0f3323e97.png)

エンドポイントのタイプは、閉域からのみアクセスさせたいので「VPC でホスト」を選択し、エンドポイントを作成する VPC とサブネットを選択します。また、SFTP を許可するために SSH を許可したセキュリティグループを作成してアタッチします。

![スクリーンショット 2025-06-07 11.55.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/15c70e2a-30ea-438e-a96a-eada01af486b.png)

![スクリーンショット 2025-06-07 12.00.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/b44e6245-6326-484b-bbbc-d173a4b6e669.png)

Transfer Family で使うストレージサービスを選択します。S3 を選択します。

![スクリーンショット 2025-06-07 12.00.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/449c724a-eec0-48e1-8e6f-752796f1758a.png)

追加の詳細設定は、ここでは全てデフォルトとしました。

![スクリーンショット 2025-06-07 12.13.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/acb1eaa6-9e21-48fe-ae4f-10520248620a.png)

次の画面でオプションが正しいことを確認したら、SFTP サーバーを作成します。

![スクリーンショット 2025-06-07 12.18.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/bd147be1-79dd-4bc4-baf8-7e42a2be846f.png)

この時点ではまだ SFTP にアクセスできるユーザーがいないので、後でユーザーを追加していきます。

なお、サーバーを作成した時点で、CloudWatch Logs に Transfer Family のイベントが記録されるようになるので確認してください。

![スクリーンショット 2025-06-07 16.45.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/cbdcd13b-f390-4e33-8d09-670a7f3ac078.png)

## VPC エンドポイントの名前解決の確認

この時点で Transfer Family SFTP サーバーの VPC エンドポイントが自動的に作成されていますので、Route 53 インバウンドエンドポイントと連携しているオンプレミスの DNS を参照しているクライアントから VPC エンドポイントの名前解決ができるか確認しておきます。

![スクリーンショット 2025-06-07 15.07.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/da565b33-0de4-454b-9a65-4a0d70b1f079.png)

![スクリーンショット 2025-06-07 15.07.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/d7a3969a-a6cd-4c33-9794-415e192f34c1.png)

ここでは一旦 VPC エンドポイントのプライベート IP アドレスが返ってくることが確認できれば OK です。

なお、閉域オンプレミスと AWS の Route 53 と連携して名前解決する構成は、過去に記事を書きましたので参考にしてください。

https://qiita.com/takeda_h/items/bd7269a539079daeaa5d

## S3 バケットの作成

SFTP サーバー用として、適当な名前で空の S3 バケットを作成しておきます。この後、SFTP クライアントユーザーを作成する際にバケット名が必要になります。

## SFTP クライアントユーザーの作成

### IAM ポリシー・ISM ロールの作成

SFTP クライアントユーザー（以下ユーザー）の追加に際し、ユーザーがどのバケットにアクセスできるか制御（認可）するためには、IAM ポリシーを作成し、この IAM ポリシーをセットした IAM ロールを作成するユーザーに付ける必要があります。

#### IAM ポリシーの作成

まず、ユーザーがアクセスできるバケットを限定するため、IAM ポリシーを作成します。AWS のドキュメントにあるサンプルから、先に作成した S3 バケット名へ書き換えただけです。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid":"ReadWriteS3",
      "Action": [
            "s3:ListBucket"
                ],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::test01-dev-bucket-sftptest-01"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:GetObjectTagging",
        "s3:DeleteObject",              
        "s3:DeleteObjectVersion",
        "s3:GetObjectVersion",
        "s3:GetObjectVersionTagging",
        "s3:GetObjectACL",
        "s3:PutObjectACL"
      ],
      "Resource": ["arn:aws:s3:::test01-dev-bucket-sftptest-01/*"]
    }
  ]
}
```

https://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/users-policies-all-access.html

次にこの IAM ポリシーをセットした IAM ロールを作成します。信頼されたエンティティタイプは「AWS のサービス」を選び、ユースケースには「Transfer」を選択します。

![スクリーンショット 2025-06-07 13.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/71118681-2675-4600-930e-c380aea9b45f.png)

許可ポリシーは先ほど作成した IAM ポリシーを選択します。

![スクリーンショット 2025-06-07 13.12.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/32c80b3a-6406-4748-97ae-33a253caae98.png)

「信頼されたエンティティを選択する」が以下のとおりになっていることを確認し、IAM ポリシーを作成します。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "transfer.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

https://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/requirements-roles.html

#### S3 バケットのセッションポリシーの作成

次に、ユーザーがアクセスできる S3 バケット内のディレクトリを制御する IAM ポリシー（セッションポリシー）を作成します。

ユーザーは、自身のホームディレクトリ以外にはアクセスできないようセッションポリシーで制御しようと思います。

こちらも AWS のドキュメントのサンプルのとおりとしていて、JSON 内で変数を使えるため、ユーザーごとに IAM ポリシーを作成する必要はないとのことです。

```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:DeleteObjectVersion",
              "s3:DeleteObject",
              "s3:GetObjectVersion",
              "s3:GetObjectACL",
              "s3:PutObjectACL"
          ],
          "Resource": "arn:aws:s3:::${transfer:HomeDirectory}/*"
       }
  ]
}
```

https://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/users-policies-session.html

### SSH 認証用の公開鍵キーペアの作成

Transfer Family のユーザーは公開鍵認証が必要なため、ローカルでキーペアを作成しておきます。

```console
$ ssh-keygen -t rsa -b 4096
```

![スクリーンショット 2025-06-07 14.58.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/ce8903e2-4c20-4e6d-888e-8f29c42b497e.png)

### ユーザーの作成

ここまで準備ができたら、いよいよユーザーを作成します。設定値は次のとおりです。

| 項目 | 値 |
|:-|:-|
| ユーザー名  | 任意  |
| ロール  | 先ほど作成した IAM ロール  |
| ポリシー  | 先ほど作成した IAM ポリシー（セッションポリシー）  |
| ホームディレクトリ  | 先ほど作成した S3 バケット名と、任意のディレクトリパス |
| SSH パブリックキー  | 先ほど作成したキーペアの公開鍵の方をペーストする  |

![スクリーンショット 2025-06-07 14.59.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/4746be4e-bf5e-4a7b-bd9b-b8302feee6ab.png)

## オンプレミスから Transfer Family SFTP サーバーの VPC エンドポイントへアクセス

ユーザーが作成できたら、このユーザーの認証情報を使ってオンプレミスから SFTP で Transfer Family SFTP サーバーの VPC エンドポイントに向かって接続してみます。先ほど作成したキーペアの秘密鍵の方をパラメーターに指定して SFTP クライアントを実行します。

```console
$ sftp -i 作成したキーペアの秘密鍵 作成したユーザー名@作成されたエンドポイント名
```

![スクリーンショット 2025-06-07 15.10.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/d67755dd-f0fe-4699-b9d1-d515bdb6c727.png)

SFTP のプロンプトが返ってきました。早速適当なテキストファイルを PUT してみます。

![スクリーンショット 2025-06-07 15.34.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/00205a49-9239-41b7-a903-2d63fe5311ff.png)

ユーザーを作成する時に指定したホームディレクトリへファイルを PUT したことが分かります。

では PUT したファイルが S3 側で見えているか確認してみます。

![スクリーンショット 2025-06-07 15.13.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/3cda3248-e999-4d79-b32a-0681e4b5c548.png)

S3 側でもホームディレクトリに指定されていたパスにファイルがアップロードされたことを確認できました。

ここまででオンプレミスから SFTP で S3 へファイルを連携できることを確認できていますが、せっかくなので Transfer Family SFTP サーバーの VPC エンドポイント名ではなく、独自のドメイン名でアクセスできるようにしてみます。

## Route 53 プライベートホストゾーンにエンドポイントのエイリアスレコードを追加

Route 53 インバウンドエンドポイントのある VPC に関連づけられているプライベートホストゾーンに、Transfer Family SFTP サーバーの VPC エンドポイントに対するエイリアスレコードを追加します。

![スクリーンショット 2025-06-07 15.29.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/f0bba4ae-a791-4bc5-a980-ee3a40280f3f.png)

登録したレコードが名前解決できるか確認します。

![スクリーンショット 2025-06-07 15.32.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/1067fc98-5d4f-460f-96de-ea46ee5ab4a0.png)

これで独自ドメイン名で Transfer Family SFTP サーバーへアクセスできるようになりました。

```console
$ sftp -i 作成した秘密鍵 ユーザー名@プライベートホストゾーンで作成したホスト名
```

![スクリーンショット 2025-06-07 15.33.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443658/2c989f4f-d8a3-4f80-86aa-0f23f75e427f.png)

## まとめ

Transfer Family を使うと、比較的簡単に閉域内で接続できる SFTP サーバーを構築できることが分かりました。

一方、ガバメントクラウド環境で地方自治体が運用することを考えると、以下の点が課題だと思いました。

- ユーザーごとに公開鍵認証のキーペアを自身で管理しなければならない（職員でできる？運用管理補助者に依頼するなら委託仕様書に書く必要あるよね。）
- ユーザーのホームディレクトリの管理の煩雑さ。業務が一つならいいが複数ある場合、ホームディレクトリの下にディレクトリ分ける？業務ごとにユーザー自体分ける？悩ましい。
- 単純に高い（月に 5 万円くらいかかる）

とはいえ、認証認可サーバーの管理が不要で、クライアント側も S3 API を叩きにいく開発が不要になるのは魅力です。

当面、AWS と別 CSP、オンプレミスとのファイル連携の主力になるのではないでしょうか。

全自治体で認証認可サーバーを立てるくらいなら、ガバメントクラウド上に共同で使える認証認可の仕組みを整備した方が効率良さそうです。ｼﾞｰｷｬｽ!!

## 参考 URL

https://docs.aws.amazon.com/ja_jp/transfer/latest/userguide/users-policies.html

https://dev.classmethod.jp/articles/reinvent2018-sftp-iam/

https://dev.classmethod.jp/articles/transfer-family-setting-items/

https://www.digital.go.jp/policies/local_governments/specification