この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
いわさです。
Transfer Family の マネージドワークフローを構築する機会が最近多くて、サーバーとユーザー含めて作っては壊してってのを繰り返しているのですが、さすがにCloudFormationテンプレートでも用意するか...となりました。
そして、マネージドワークフローのテンプレートがまだ記事で見当たらなかったので一式を公開したいと思います。
作るもの
サーバープロトコルはSFTPで、IDプロバイダーはサービスマネージドのものを構築します。
そして、エンドポイントタイプはVPCでパブリックIPを付与しており、ローカルからのみにIPアドレス制限を行えるように構成してみます。
ワークフローは、実はステップの種類ごとに設定方法が異なるので、コピー・カスタム・削除の3つのステップを組み合わせてみました。
作ったもの
まず、テンプレート全体はこちらのリポジトリに置いておきます。
サーバー
Transfer Family サーバー本体の部分です。
EndpointDetails
でVPCの構成およびIPアドレスの関連付けを行っています。
サービスマネージドユーザーを使うので、IdentityProviderType
のみ指定しています。
Transfer Familyは自動でCloudWatch Logsへログ出力してくれるので、AWSTransferLoggingAccess
マネージドポリシーをアタッチしたIAMロールを指定しています。
後ほどワークフローの中身を見ていきますが、サーバーのWorkflowDetails
でワークフローIDとワークフロー実行ロールを指定します。
CloudFormationで今回実装して気づいたんですが、OnUpload
というトリガーに設定を行っていますね。
本日時点ではファイルアップロード時のみワークフローが実行されますが、将来別のトリガーも実装される可能性を感じます。楽しみです。
:
SFTP:
Type: AWS::Transfer::Server
Properties:
Domain: S3
Protocols:
- SFTP
EndpointType: VPC
EndpointDetails:
AddressAllocationIds:
- !GetAtt EipTransfer.AllocationId
SecurityGroupIds:
- !Ref SecurityGroup
SubnetIds:
- !Ref PublicSubnet1
VpcId: !Ref VPC
IdentityProviderType: SERVICE_MANAGED
LoggingRole: !GetAtt TransferLoggingRole.Arn
WorkflowDetails:
OnUpload:
- WorkflowId: !Ref Workflow
ExecutionRole: !GetAtt WorkflowExecutionRole.Arn
:
TransferLoggingRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: transfer.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSTransferLoggingAccess
:
ユーザー
こちらはユーザーを作成してます。
スタック作成時のパラメータで公開鍵を設定するようにしています。
テンプレートから切り離すことで複数ユーザー向けに汎用的に利用出来そうです。
Transfer Familyユーザーに、S3バケットへのアクセス権限をIAMロールで渡す必要があります。
ここではさぼってAmazonS3FullAccess
を指定しまっているのでご注意ください。
実際には、対象のS3バケットやプレフィックスのみなど絞り込むべきです。
Parameters:
:
UserName:
Type: String
Default: user1
UserPublicKey:
Type: String
Resources:
:
TransferUser:
Type: AWS::Transfer::User
Properties:
ServerId: !GetAtt SFTP.ServerId
HomeDirectory: !Sub "/${S3Bucket}/${UserName}"
HomeDirectoryType: "PATH"
Role: !GetAtt TransferExecutionRole.Arn
UserName: !Ref UserName
SshPublicKeys:
- !Ref UserPublicKey
TransferExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: transfer.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
S3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: !Sub s3-${AWS::StackName}-${AWS::AccountId}-${AWS::Region}
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
:
ワークフロー
ここでは以前ご紹介した新機能のマネージドワークフローを構成しています。
Steps
プロパティで複数のステップを構成していて、それぞれにTYPE
とxxxStepDetails
を指定しています。
このStepDetailはTYPEごとに違っていて、かつドキュメントではJSON形式との指定がありますが、具体的なパラメータが記載されていません。
このあたりはCloudFormationのテンプレートリファレンスよりも、ユーザーガイドのAPIリファレンスが参考になります。
CreateWorkflow-AWS Transfer Family
マネージドワークフローではふたつのIAMロールが登場します。
ひとつはワークフローの実行ロールです。ここではS3バケットのファイルコピーと削除、そしてLambdaの実行が出来る必要があります。
ふたつめはLambda関数の実行ロールです。
カスタムステップのLambda関数では、Transfer Familyに対して、ワークフローステップのステータスを送信してやる必要があります。CloudFormationのカスタムリソースに似ています。
ですので、最低でもTransfer Familyへのsend_workflow_step_state
が出来る権限が必要です。
:
Workflow:
Type: AWS::Transfer::Workflow
Properties:
Steps:
- Type: COPY
CopyStepDetails:
Name: !Sub ${AWS::StackName}-copy-step
DestinationFileLocation:
S3FileLocation:
Bucket: !Ref S3Bucket
Key: "${transfer:UserName}/copy.dat"
OverwriteExisting: "TRUE"
SourceFileLocation: "${previous.file}"
- Type: CUSTOM
CustomStepDetails:
Name: !Sub ${AWS::StackName}-custom-step
Target: !GetAtt lambdaFunction.Arn
TimeoutSeconds: 60
SourceFileLocation: "${previous.file}"
- Type: DELETE
DeleteStepDetails:
Name: !Sub ${AWS::StackName}-delete-step
SourceFileLocation: "${original.file}"
WorkflowExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: transfer.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaRole
- arn:aws:iam::aws:policy/AmazonS3FullAccess
lambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-transfer-customstep
Role: !GetAtt lambdaExecutionRole.Arn
Handler: index.lambda_handler
Runtime: python3.8
Code:
ZipFile: |
import json
import boto3
transfer = boto3.client('transfer')
def lambda_handler(event, context):
print(json.dumps(event))
transfer_response = transfer.send_workflow_step_state(
WorkflowId=event['serviceMetadata']['executionDetails']['workflowId'],
ExecutionId=event['serviceMetadata']['executionDetails']['executionId'],
Token=event['token'],
Status='SUCCESS'
)
return {
'statusCode': 200,
'body': json.dumps(transfer_response)
}
lambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AWSTransferFullAccess
:
デプロイと実行
リソースは期待どおり作成されていますね。
SFTPクライアントからファイルをアップロードしてみます。
$ sftp -i user1 user1@52.192.236.242
Connected to 52.192.236.242.
sftp> put hoge1.txt
Uploading hoge1.txt to /s3-hogesftp-123456789012-ap-northeast-1/user1/hoge1.txt
hoge1.txt 100% 15 0.4KB/s 00:00
ファイルがアップロードされ、マネージドワークフローが動作してオリジンファイルが削除されていますね。ヨシ!
さいごに
本日は、Transfer Family の CloudFormation 対応リソース一式を作ってデプロイしてみました。
Transfer Familyで構築したい時はとりあえずこのテンプレートをベースに修正していってみようかなと思ってます。
途中触れていますが、注意事項があって、IAMロールが登場しすぎてマネージドポリシーばかり使ってしまいました。マネージドポリシーが悪いというより権限が大きいまま放置しているので良くないですね。
もし参考にされる方がいらっしゃいましたら、その点ご認識頂き必要に応じてより厳格なポリシーを付与して頂ければと思います。