AWS Transfer Familyで簡単FTPサーバ
FTP???と言われてしまいそうですが、とある案件でシステム間連携をする際にどうしてもFTPで接続したいんです。という要望を頂きまして構築した時のメモです。
DirectConnectで接続した先の環境からのFTP接続なので、通信経路のセキュリティ的な意味ではまあいっか?と。。。こちらで用意したFTPサーバに、システム間連携先のお客様サーバから接続してくるという構成です。
SFTP(もしくはFTPS)に変更してもそんなに工数かからないと思うのですが。SFTPにしちゃえばいいのに。。。というお話はしつつAWS Transfer Familyを使って構築していきます。
サーバを作成を押してインスタンスを作成します。
要件でFTPとなっているので、FTPにチェックを入れて次へ
IDプロバイダー(FTPする際のユーザ管理)で、管理は楽にしたいのでサービスマネージドを選ぼうとすると、FTPSとFTPでは選べないと言われます。
早速イライラしながら、DirectoryServiceなんて使ってないので、カスタムを選択します。
カスタムプロバイダー(API GatewayのURL)を聞かれるので、ここで一旦終了。
API Gatewayを先に作ります。
公式の「カスタムIDプロバイダーの操作」手順を参考に進めていきます
Transfer Family カスタム認証に API Gateway メソッドを使用するには
のところにテンプレートがあるので、基本的なスタックテンプレートを使ってみます。
AWS CloudFormation コンソール(https://console.aws.amazon.com/cloudformation) を開いて、スタックの作成をポチっとします。
テンプレートのURL(「カスタム ID プロバイダーを使用した認証」に書いてあります)を設定して、次へ
CreateServerをfalseにして、その他の設定値は変更せず進めていきます。
作成完了したらOKです。
作成されたリソースを確認します。
Lambdaの認証サンプルで以下のコードが設定されています。
'use strict';
// 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 serverId, only that it is provided.
if (event.password == '' && ( event.protocol == 'FTP' || event.protocol == 'FTPS')) {
// Return HTTP status 200 but with no role in the response to indicate authentication failure
response = {};
} else if (event.serverId !== "" && event.username == 'myuser') {
response = {
Role: 'arn:aws:iam::000000000000:role/MyUserS3AccessRole', // The user will be authenticated if and only if the Role field is not blank
Policy: '', // Optional JSON blob to further restrict this user's permissions
HomeDirectory: '/' // Not required, defaults to '/'
};
// Check if password is provided
if (event.password == "") {
// If no password provided, return the user's SSH public key
response['PublicKeys'] = [ "ssh-rsa myrsapubkey" ];
// Check if password is correct
} else if (event.password !== 'MySuperSecretPassword') {
// 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);
};
これでログインできそうですね。
ユーザ名:myuser
パスワード:MySuperSecretPassword
S3や専用のロール作ってから認証部分を更新したいと思います。
API Gatewayの準備ができたので、再度Transfer Familyを作成していきます。
カスタムプロバイダーにAPI Gateway URLを設定する必要があるので、確認しておきます。
URLの呼び出し:
https://a7mbwowjjd.execute-api.ap-northeast-1.amazonaws.com/prod
の部分をメモしておきます。
TransferFamilyの作成は、カスタムプロバイダーは先程メモしたもの、ロールはCloudFormationで作成されたTransferIdentityProviderRoleを設定します。以降の設定項目のVPC、AZ、セキュリティグループは環境にあったものを設定していきます。
途中でドメイン(TransferFamilyのデータアクセス先)はS3を選択します。
作成できたら接続テストを実施します。作成したTransfer Familyを開いて、画面右上のアクション - テスト を選択します。
接続情報を入力しテストを実施します。
ユーザ名:myuser
パスワード:MySuperSecretPassword
送信元IP:8.8.8.8(どこのIPでもOKです)
StatusCodeが200で返ってくればOKです。
次は任意の名前でS3バケットを作成し、テスト用のファイルをアップロードしておきます。
次にFTPログイン時に使用するロールを作成していきます。
権限はS3FullAccessにしていますが、本番運用では対象バケットを絞るなど適切な権限にしてください。
Lambdaの認証を変更します。
response = {
Role: 'arn:aws:iam::925722219028:role/transferfamily', // The user will be authenticated if and only if the Role field is not blank
Policy: '', // Optional JSON blob to further restrict this user's permissions
HomeDirectory: '/tf-test-20210822/' // Not required, defaults to '/'
};
これで準備出来たので動作確認していきます。
[root@ip-10-0-0-29 ~]# ftp
ftp> open 10.0.2.105
Connected to 10.0.2.105 (10.0.2.105).
220 Service ready for new user.
Name (10.0.2.105:root): myuser
331 User name okay, need password for myuser.
Password:
230 User logged in, proceed.
Remote system type is UNIX.
ftp> ls
227 Entering Passive Mode (10,0,2,105,32,5)
150 File status okay; about to open data connection.
-rwxr--r-- 1 - - 206292 Aug 22 02:28 image.png
226 Closing data connection.
ftp> bin
200 Command TYPE okay.
ftp> get image.png
local: image.png remote: image.png
227 Entering Passive Mode (10,0,2,105,32,3)
150 File status okay; about to open data connection.
226 Transfer complete.
206292 bytes received in 0.769 secs (268.14 Kbytes/sec)
無事接続とファイル一覧表示、ファイルの取得が出来ました。今後サーバの保守がなくなるのはとても良いと思います。
あと、SFTPで構成すれば認証部分の実装も必要ないので、もっと簡単に構築できますね。