From fd334907157c330dd4b7fc6c7aa681b26efda5d1 Mon Sep 17 00:00:00 2001 From: Biswanath Mukherjee Date: Mon, 29 Apr 2024 09:01:14 +0530 Subject: [PATCH 1/7] Initial checkin --- awstransfer-s3-sam/README.md | 165 +++++++++++++++++++++ awstransfer-s3-sam/deploy.sh | 90 +++++++++++ awstransfer-s3-sam/example-pattern.json | 63 ++++++++ awstransfer-s3-sam/images/architecture.png | Bin 0 -> 27895 bytes awstransfer-s3-sam/sample1.txt | 1 + awstransfer-s3-sam/sample2.txt | 1 + awstransfer-s3-sam/sample3.txt | 1 + awstransfer-s3-sam/template1.yaml | 165 +++++++++++++++++++++ awstransfer-s3-sam/template2.yaml | 126 ++++++++++++++++ awstransfer-s3-sam/undeploy.sh | 14 ++ 10 files changed, 626 insertions(+) create mode 100644 awstransfer-s3-sam/README.md create mode 100644 awstransfer-s3-sam/deploy.sh create mode 100644 awstransfer-s3-sam/example-pattern.json create mode 100644 awstransfer-s3-sam/images/architecture.png create mode 100644 awstransfer-s3-sam/sample1.txt create mode 100644 awstransfer-s3-sam/sample2.txt create mode 100644 awstransfer-s3-sam/sample3.txt create mode 100644 awstransfer-s3-sam/template1.yaml create mode 100644 awstransfer-s3-sam/template2.yaml create mode 100644 awstransfer-s3-sam/undeploy.sh diff --git a/awstransfer-s3-sam/README.md b/awstransfer-s3-sam/README.md new file mode 100644 index 000000000..28b7a5592 --- /dev/null +++ b/awstransfer-s3-sam/README.md @@ -0,0 +1,165 @@ +# Bidirectional selective file transfer between remote SFTP server and Amazon S3 using AWS Transfer Family Connector + +This pattern shows how to setup an AWS Transfer Family SFTP connector to list files from the remote server and transfer specific file to Amazon S3 bucket. You can also transfer specific file from Amazon S3 bucket to the remote SFTP Server. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/awstransfer-s3-sam. + +Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed +* [JQ](https://docs.aws.amazon.com/solutions/latest/dynamic-object-and-rule-extensions-for-aws-network-firewall/operation-and-customization.html#install-jq) should be installed. + + + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` + +2. Change directory to the pattern directory: + ``` + cd serverless-patterns/awstransfer-s3-sam + ``` + +3. From the command line, run the below command to deploy the pattern: + ``` + bash deploy.sh + ``` + +4. During the prompts: + * Enter a stack name + * Enter the desired AWS Region + +5. The deployment script deploys both `template1.yaml` and `template2.yaml`. Please make a note of the output both the deployments as they will be used during testing. + + +## How it works + +Please refer to the architecture diagram below: + +![End to End Architecture](images/architecture.png) + +* The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remove SFTP server outside of AWS. +* SFTP Connector is configured to comment the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake. +* Amazon S3 bucket file storage on AWS side. +* User can list files on the remote server and selectively transfer file from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands. +* User can also transfer files from Amazon S3 to the remote server using the AWS Transfer Family API or CLI commands. + +## Testing + +1. Use the endpoint to test the SFTP server with transferring a file using a client, the rest of this test steps are shown using OpenSSH. Please refer to [Transferring files over a server endpoint using a client](https://docs.aws.amazon.com/transfer/latest/userguide/transfer-file.html) for other options. + +2. Test the connection using using the below command from your command line. Please replace `SFTPTransferConnector` from the deployment output: + ```bash + aws transfer test-connection --region {your-region} --connector-id {SFTPTransferConnector} + ``` + It should give an output similar to below: + ```json + { + "Status": "OK", + "StatusMessage": "Connection succeeded" + } + ``` + +3. Transfer `sample1.txt` and `sample2.txt` files to the remote SFTP server (similated) using the below commands. In this sample project replace `SSHPrivateKeyFileName` and `SSHPrivateKeyFileName` with `sftpuser`. Replace the value of `TransferServerEndpoint` from the deployment output: + ```bash + sftp -i {SSHPrivateKeyFileName} {TransferServerUser}@{TransferServerEndpoint} + pwd + mkdir Remote + cd Remote + put sample1.txt + put sample2.txt + ls + ``` + Confirm to proceed with the connection after the first command. + +5. List the files on the remote SFTP server using the below command. Please replace `SFTPTransferConnector` and `MyLocalS3Bucket` from the deploy output: + + ```bash + aws transfer start-directory-listing --region {your-region} --connector-id {SFTPTransferConnector} --remote-directory-path /Remote --output-directory-path /{MyLocalS3Bucket}/FromRemoteSFTPServer + ``` + + The command invokes async API. The outpul of the command will be as follows: + ```json + { + "ListingId": "273e5b33-xxxx-xxxx-xxxx-xxxxx9a507f53", + "OutputFileName": "c-cxxxxxxxx-xxxxxx-xxxx-xxxx-xxxx-xxxxxa507f53.json" + } + ``` + +6. Log into [Amazon S3 console](https://console.aws.amazon.com/s3). Open the `MyLocalS3Bucket` and navigate to `FromRemoteSFTPServer` folder. Check the content of the JSON file. It should look something like below: + ```json + { + "files": [ + { + "filePath": "/Remote/sample1.txt", + "modifiedTimestamp": "2024-04-28T07:47:27Z", + "size": 146 + }, + { + "filePath": "/Remote/sample2.txt", + "modifiedTimestamp": "2024-04-28T07:47:46Z", + "size": 146 + } + ], + "paths": [], + "truncated": false + } + ``` + +7. Transfer one of the files from the remote SFTP server to Amazon S3 bucket using the following command: + ```bash + aws transfer start-file-transfer --region {your-region} --connector-id {SFTPTransferConnector} --retrieve-file-paths /Remote/sample1.txt --local-directory-path /{MyLocalS3Bucket}/FromRemoteSFTPServer + ``` + + The output of the command should something like below: + ```json + { + "TransferId": "e863xxxx-xxxx-xxxx-xxxx-xxxxa40c5ff9" + } + ``` + +8. Log into [Amazon S3 console](https://console.aws.amazon.com/s3). Open the `MyLocalS3Bucket` and navigate to `FromRemoteSFTPServer` folder. You should be able to find the transferred `sample1.txt` file. + +9. Upload a file into the `MyLocalS3Bucket` bucket using the following command. Replace the `MyLocalS3Bucket` from the deploy output: + ```bash + aws s3 cp sample3.txt s3://{MyLocalS3Bucket}/local/sample3.txt + ``` + +10. Transfer the `sample3.txt` file Amazon S3 `MyLocalS3Bucket` bucket to the remove SPT server using the following command: + ```bash + aws transfer start-file-transfer --region {your-region} --connector-id {SFTPTransferConnector} --send-file-paths /{MyLocalS3Bucket}/local/sample3.txt --remote-directory-path /FromAmazonS3 + ``` + +11. Validate the file transfer by logging into the the remove SFTP server using the below commands: + ```bash + sftp -i {SSHPrivateKeyFileName} {TransferServerUser}@{TransferServerEndpoint} + ls + cd FromAmazonS3 + ls + ``` + +## Cleanup + +1. Delete the content in the Amazon S3 bucket using the following command. Please *ensure* that the correct bucket name is provided to avoid accidental data loss: + ```bash + aws s3 rm s3://{MySFTPServerS3Bucket} --recursive --region {my-region} + aws s3 rm s3://{MyLocalS3Bucket} --recursive --region {my-region} + ``` + +2. Delete the stack + ```bash + bash undeploy.sh + ``` + +---- +Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/awstransfer-s3-sam/deploy.sh b/awstransfer-s3-sam/deploy.sh new file mode 100644 index 000000000..0f12ebac1 --- /dev/null +++ b/awstransfer-s3-sam/deploy.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Take the stack name +echo "Enter a stack name" +read -r STACK_NAME + +# Take the desired AWS Region +echo "Enter the desired AWS Region:" +read -r AWS_REGION + + +USER_NAME="sftpuser" + +# Generate key-pair +# AWS Documentation: https://docs.aws.amazon.com/transfer/latest/userguide/configure-sftp-connector.html#format-sftp-connector-key +ssh-keygen -t rsa -b 4096 -m PEM -f $USER_NAME -N "" + +# Check if the public key file exists +if [ -f "$USER_NAME.pub" ]; then + + # Store the content of the public key in a variable + PUBLIC_KEY=$(cat "$USER_NAME.pub") + + # Deploy template1.yaml + sam deploy \ + --template-file template1.yaml \ + --stack-name "$STACK_NAME-1" \ + --parameter-overrides "UserName=\"$USER_NAME\"" "SSHPublicKey=\"$PUBLIC_KEY\"" \ + --capabilities CAPABILITY_IAM \ + --region $AWS_REGION + + # Get the stack ID + STACK_ID=$(aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE --query "StackSummaries[?contains(StackName, '$STACK_NAME-1')].StackId" --output text --region $AWS_REGION) + + # Check if the stack ID is empty + if [ -z "$STACK_ID" ]; then + echo "Stack not found. Exiting..." + exit 1 + fi + + # Get the stack outputs + OUTPUTS=$(aws cloudformation describe-stacks --stack-name "$STACK_ID" --query "Stacks[0].Outputs" --output json --region $AWS_REGION) + + # Get a TransferServerId output value + TRANSFER_SERVER_ID=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey == "TransferServerId") | .OutputValue') + + # Get a TransferServerEndpoint output value + TRANSFER_SERVER_ENDPOINT=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey == "TransferServerEndpoint") | .OutputValue') + + # Get a TransferLoggingRoleArn output value + TRANSFER_LOGGING_ROLE_ARN=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey == "TransferLoggingRoleArn") | .OutputValue') + + # Get a SSHPrivateKey in single line without double quotes + # AWS Documentation: https://docs.aws.amazon.com/transfer/latest/userguide/sftp-connectors-tutorial.html + FORMATTED_PK=$(jq -sR . < "$USER_NAME"| sed 's/^"//;s/"$//') + + # Wait for the server to be ready + STATE="NOT_AVAILABLE" + + # Loop until the server is available + while [ "$STATE" != "ONLINE" ]; do + # Get the server state using the AWS CLI + STATE=$(aws transfer describe-server --server-id "$TRANSFER_SERVER_ID" --query "Server.State" --output text) + + # Print the server state + echo "Server state: $STATE" + + # Wait for 1 minute before checking again + sleep 60 + done + + # Print a message when the server is available + echo "Server is online! Proceesing with the next steps..." + + # Get the TrustedHostKey from the TransferServer + # AWS Documentation: https://docs.aws.amazon.com/transfer/latest/userguide/API_SftpConnectorConfig.html + TRUSTED_HOST_KEY=$(ssh-keyscan $TRANSFER_SERVER_ENDPOINT) + + # Deploy template2.yaml + sam deploy \ + --template-file template2.yaml \ + --stack-name "$STACK_NAME-2" \ + --parameter-overrides "TransferServerEndpoint=\"sftp://$TRANSFER_SERVER_ENDPOINT\"" "UserName=\"$USER_NAME\"" "TransferLoggingRoleArn=\"$TRANSFER_LOGGING_ROLE_ARN\"" "SSHPrivateKey=\"$FORMATTED_PK\"" "TrustedHostKeys=\"$TRUSTED_HOST_KEY\"" \ + --capabilities CAPABILITY_IAM \ + --region $AWS_REGION + +else + echo "Public key file not found. Exiting..." + exit 1 +fi diff --git a/awstransfer-s3-sam/example-pattern.json b/awstransfer-s3-sam/example-pattern.json new file mode 100644 index 000000000..49f88afa6 --- /dev/null +++ b/awstransfer-s3-sam/example-pattern.json @@ -0,0 +1,63 @@ +{ + "title": "Selective file transfer between SFTP server and S3 using AWS Transfer Family", + "description": "This pattern shows how to use AWS Transfer Family to list and transfer specific files between an SFTP server and Amazon S3 bucket.", + "language": "YAML", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remove SFTP server outside of AWS.", + "SFTP Connector is configured to comment the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", + "Amazon S3 bucket file storage on AWS side.", + "User can list files on the remote server and selectively transfer file from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands.", + "User can also transfer files from Amazon S3 to the remote server using the AWS Transfer Family API or CLI commands." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/awstransfer-s3-sam", + "templateURL": "serverless-patterns/awstransfer-s3-sam", + "projectFolder": "awstransfer-s3-sam", + "templateFile": "template1.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "Getting started with AWS Transfer Family server endpoints", + "link": "https://docs.aws.amazon.com/transfer/latest/userguide/getting-started.html" + }, + { + "text": "Configure SFTP connectors", + "link": "https://docs.aws.amazon.com/transfer/latest/userguide/configure-sftp-connector.html" + } + ] + }, + "deploy": { + "text": [ + "See the GitHub repo for detailed deployment instructions.", + "bash deploy.sh" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the Amazon S3 input bucket content: aws s3 rm s3://{MySFTPServerS3Bucket} --recursive --region {my-region}", + "Delete the Amazon S3 output bucket content: aws s3 rm s3://{MyLocalS3Bucket} --recursive --region {my-region}", + "bash undeploy.sh" + ] + }, + "authors": [ + { + "name": "Biswanath Mukherjee", + "image": "https://d1rwvjey2iif32.cloudfront.net", + "bio": "I am a Sr. Solutions Architect working at AWS India.", + "linkedin": "biswanathmukherjee" + } + ] +} diff --git a/awstransfer-s3-sam/images/architecture.png b/awstransfer-s3-sam/images/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..450cf33c6078ed33edd14b1893bfc181c4ea746a GIT binary patch literal 27895 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 izgax6zXa8$Nr`JhM*H Date: Fri, 10 May 2024 11:30:47 +0530 Subject: [PATCH 2/7] fixed review comments --- awstransfer-s3-sam/README.md | 16 ++++++++-------- awstransfer-s3-sam/deploy.sh | 8 ++++---- awstransfer-s3-sam/example-pattern.json | 12 ++++++------ ...mplate2.yaml => template-sftp-connector.yaml} | 8 +------- ...{template1.yaml => template-sftp-server.yaml} | 8 +------- 5 files changed, 20 insertions(+), 32 deletions(-) rename awstransfer-s3-sam/{template2.yaml => template-sftp-connector.yaml} (98%) rename awstransfer-s3-sam/{template1.yaml => template-sftp-server.yaml} (98%) diff --git a/awstransfer-s3-sam/README.md b/awstransfer-s3-sam/README.md index 28b7a5592..1278ffda8 100644 --- a/awstransfer-s3-sam/README.md +++ b/awstransfer-s3-sam/README.md @@ -1,6 +1,6 @@ # Bidirectional selective file transfer between remote SFTP server and Amazon S3 using AWS Transfer Family Connector -This pattern shows how to setup an AWS Transfer Family SFTP connector to list files from the remote server and transfer specific file to Amazon S3 bucket. You can also transfer specific file from Amazon S3 bucket to the remote SFTP Server. +This pattern shows how to setup an AWS Transfer Family SFTP connector to list files from the remote server and transfer specific files to Amazon S3 bucket. You can also transfer specific files from Amazon S3 bucket to the remote SFTP server. Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/awstransfer-s3-sam. @@ -35,9 +35,9 @@ Important: this application uses various AWS services and there are costs associ 4. During the prompts: * Enter a stack name - * Enter the desired AWS Region + * Enter the desired AWS Region (e.g. us-east-1) -5. The deployment script deploys both `template1.yaml` and `template2.yaml`. Please make a note of the output both the deployments as they will be used during testing. +5. The deployment script deploys both `template-sftp-server.yaml` and `template-sftp-connector.yaml`. Please make a note of the output both the deployments as they will be used during testing. ## How it works @@ -47,9 +47,9 @@ Please refer to the architecture diagram below: ![End to End Architecture](images/architecture.png) * The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remove SFTP server outside of AWS. -* SFTP Connector is configured to comment the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake. -* Amazon S3 bucket file storage on AWS side. -* User can list files on the remote server and selectively transfer file from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands. +* SFTP Connector is configured to connect to the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake. +* Amazon S3 bucket is used for file storage on the AWS side. +* User can list files on the remote server and selectively transfer files from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands. * User can also transfer files from Amazon S3 to the remote server using the AWS Transfer Family API or CLI commands. ## Testing @@ -86,7 +86,7 @@ Please refer to the architecture diagram below: aws transfer start-directory-listing --region {your-region} --connector-id {SFTPTransferConnector} --remote-directory-path /Remote --output-directory-path /{MyLocalS3Bucket}/FromRemoteSFTPServer ``` - The command invokes async API. The outpul of the command will be as follows: + The command invokes an asynchronous API. The output of the command will be as follows: ```json { "ListingId": "273e5b33-xxxx-xxxx-xxxx-xxxxx9a507f53", @@ -114,7 +114,7 @@ Please refer to the architecture diagram below: } ``` -7. Transfer one of the files from the remote SFTP server to Amazon S3 bucket using the following command: +7. Transfer one of the files from the remote SFTP server to the Amazon S3 bucket using the following command: ```bash aws transfer start-file-transfer --region {your-region} --connector-id {SFTPTransferConnector} --retrieve-file-paths /Remote/sample1.txt --local-directory-path /{MyLocalS3Bucket}/FromRemoteSFTPServer ``` diff --git a/awstransfer-s3-sam/deploy.sh b/awstransfer-s3-sam/deploy.sh index 0f12ebac1..81d68f13f 100644 --- a/awstransfer-s3-sam/deploy.sh +++ b/awstransfer-s3-sam/deploy.sh @@ -21,9 +21,9 @@ if [ -f "$USER_NAME.pub" ]; then # Store the content of the public key in a variable PUBLIC_KEY=$(cat "$USER_NAME.pub") - # Deploy template1.yaml + # Deploy template-sftp-server.yaml sam deploy \ - --template-file template1.yaml \ + --template-file template-sftp-server.yaml \ --stack-name "$STACK_NAME-1" \ --parameter-overrides "UserName=\"$USER_NAME\"" "SSHPublicKey=\"$PUBLIC_KEY\"" \ --capabilities CAPABILITY_IAM \ @@ -76,9 +76,9 @@ if [ -f "$USER_NAME.pub" ]; then # AWS Documentation: https://docs.aws.amazon.com/transfer/latest/userguide/API_SftpConnectorConfig.html TRUSTED_HOST_KEY=$(ssh-keyscan $TRANSFER_SERVER_ENDPOINT) - # Deploy template2.yaml + # Deploy template-sftp-connector.yaml sam deploy \ - --template-file template2.yaml \ + --template-file template-sftp-connector.yaml \ --stack-name "$STACK_NAME-2" \ --parameter-overrides "TransferServerEndpoint=\"sftp://$TRANSFER_SERVER_ENDPOINT\"" "UserName=\"$USER_NAME\"" "TransferLoggingRoleArn=\"$TRANSFER_LOGGING_ROLE_ARN\"" "SSHPrivateKey=\"$FORMATTED_PK\"" "TrustedHostKeys=\"$TRUSTED_HOST_KEY\"" \ --capabilities CAPABILITY_IAM \ diff --git a/awstransfer-s3-sam/example-pattern.json b/awstransfer-s3-sam/example-pattern.json index 49f88afa6..f942f8321 100644 --- a/awstransfer-s3-sam/example-pattern.json +++ b/awstransfer-s3-sam/example-pattern.json @@ -1,5 +1,5 @@ { - "title": "Selective file transfer between SFTP server and S3 using AWS Transfer Family", + "title": "Selective file transfer between SFTP server & S3 using AWS Transfer Family", "description": "This pattern shows how to use AWS Transfer Family to list and transfer specific files between an SFTP server and Amazon S3 bucket.", "language": "YAML", "level": "200", @@ -7,10 +7,10 @@ "introBox": { "headline": "How it works", "text": [ - "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remove SFTP server outside of AWS.", - "SFTP Connector is configured to comment the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", - "Amazon S3 bucket file storage on AWS side.", - "User can list files on the remote server and selectively transfer file from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands.", + "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remote SFTP server outside of AWS.", + "SFTP Connector is configured to connect the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", + "Amazon S3 bucket is used for file storage on the AWS side.", + "User can list files on the remote server and selectively transfer files from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands.", "User can also transfer files from Amazon S3 to the remote server using the AWS Transfer Family API or CLI commands." ] }, @@ -19,7 +19,7 @@ "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/awstransfer-s3-sam", "templateURL": "serverless-patterns/awstransfer-s3-sam", "projectFolder": "awstransfer-s3-sam", - "templateFile": "template1.yaml" + "templateFile": "template-sftp-server.yaml" } }, "resources": { diff --git a/awstransfer-s3-sam/template2.yaml b/awstransfer-s3-sam/template-sftp-connector.yaml similarity index 98% rename from awstransfer-s3-sam/template2.yaml rename to awstransfer-s3-sam/template-sftp-connector.yaml index 473f823d6..af5f12108 100644 --- a/awstransfer-s3-sam/template2.yaml +++ b/awstransfer-s3-sam/template-sftp-connector.yaml @@ -117,10 +117,4 @@ Outputs: SFTPTransferConnector: Description: The SFTP Transfer Connector - Value: !Ref SFTPTransferConnector - - - - - - + Value: !Ref SFTPTransferConnector \ No newline at end of file diff --git a/awstransfer-s3-sam/template1.yaml b/awstransfer-s3-sam/template-sftp-server.yaml similarity index 98% rename from awstransfer-s3-sam/template1.yaml rename to awstransfer-s3-sam/template-sftp-server.yaml index eb6d887c7..6832d1a3f 100644 --- a/awstransfer-s3-sam/template1.yaml +++ b/awstransfer-s3-sam/template-sftp-server.yaml @@ -156,10 +156,4 @@ Outputs: TransferLoggingRoleArn: Description: The name of the Transfer Logging Role - Value: !GetAtt TransferLoggingRole.Arn - - - - - - + Value: !GetAtt TransferLoggingRole.Arn \ No newline at end of file From 46b9116b16f47697542749ce165d6fc35cad0128 Mon Sep 17 00:00:00 2001 From: Biswanath Mukherjee Date: Fri, 10 May 2024 11:41:46 +0530 Subject: [PATCH 3/7] fixed review comments --- awstransfer-s3-sam/README.md | 2 +- awstransfer-s3-sam/example-pattern.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/awstransfer-s3-sam/README.md b/awstransfer-s3-sam/README.md index 1278ffda8..194cbac47 100644 --- a/awstransfer-s3-sam/README.md +++ b/awstransfer-s3-sam/README.md @@ -46,7 +46,7 @@ Please refer to the architecture diagram below: ![End to End Architecture](images/architecture.png) -* The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remove SFTP server outside of AWS. +* The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In a real use case, this can be any remote SFTP server outside of AWS. * SFTP Connector is configured to connect to the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake. * Amazon S3 bucket is used for file storage on the AWS side. * User can list files on the remote server and selectively transfer files from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands. diff --git a/awstransfer-s3-sam/example-pattern.json b/awstransfer-s3-sam/example-pattern.json index f942f8321..285acfaaf 100644 --- a/awstransfer-s3-sam/example-pattern.json +++ b/awstransfer-s3-sam/example-pattern.json @@ -7,7 +7,7 @@ "introBox": { "headline": "How it works", "text": [ - "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In real use case, this can be any remote SFTP server outside of AWS.", + "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In a real use case, this can be any remote SFTP server outside of AWS.", "SFTP Connector is configured to connect the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", "Amazon S3 bucket is used for file storage on the AWS side.", "User can list files on the remote server and selectively transfer files from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands.", From a49c8fb5a514eb769e0c691a1f0e8c78aae1f0d6 Mon Sep 17 00:00:00 2001 From: Biswanath Mukherjee Date: Fri, 10 May 2024 11:44:41 +0530 Subject: [PATCH 4/7] fixed review comments --- awstransfer-s3-sam/example-pattern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awstransfer-s3-sam/example-pattern.json b/awstransfer-s3-sam/example-pattern.json index 285acfaaf..b58019bde 100644 --- a/awstransfer-s3-sam/example-pattern.json +++ b/awstransfer-s3-sam/example-pattern.json @@ -8,7 +8,7 @@ "headline": "How it works", "text": [ "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In a real use case, this can be any remote SFTP server outside of AWS.", - "SFTP Connector is configured to connect the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", + "SFTP Connector is configured to connect to the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", "Amazon S3 bucket is used for file storage on the AWS side.", "User can list files on the remote server and selectively transfer files from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands.", "User can also transfer files from Amazon S3 to the remote server using the AWS Transfer Family API or CLI commands." From e2850f7a3bf836d67fbd97bdc7f01277fe5b9b57 Mon Sep 17 00:00:00 2001 From: Ben <9841563+bfreiberg@users.noreply.github.com> Date: Tue, 14 May 2024 20:57:37 +0200 Subject: [PATCH 5/7] Add final pattern file --- awstransfer-s3-sam/awstransfer-s3-sam.json | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 awstransfer-s3-sam/awstransfer-s3-sam.json diff --git a/awstransfer-s3-sam/awstransfer-s3-sam.json b/awstransfer-s3-sam/awstransfer-s3-sam.json new file mode 100644 index 000000000..433d0afb4 --- /dev/null +++ b/awstransfer-s3-sam/awstransfer-s3-sam.json @@ -0,0 +1,82 @@ +{ + "title": "Selective file transfer between SFTP server & S3 using AWS Transfer Family", + "description": "This pattern shows how to use AWS Transfer Family to list and transfer specific files between an SFTP server and Amazon S3 bucket.", + "language": "YAML", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "The remote SFTP server is simulated using AWS Transfer Family SFTP Server for this pattern. In a real use case, this can be any remote SFTP server outside of AWS.", + "SFTP Connector is configured to connect to the remote server with Amazon S3 bucket using SFTP protocol. The authentication is done using SSH Key based handshake.", + "Amazon S3 bucket is used for file storage on the AWS side.", + "User can list files on the remote server and selectively transfer files from the remote server to the Amazon S3 bucket using AWS Transfer Family API or CLI commands.", + "User can also transfer files from Amazon S3 to the remote server using the AWS Transfer Family API or CLI commands." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/awstransfer-s3-sam", + "templateURL": "serverless-patterns/awstransfer-s3-sam", + "projectFolder": "awstransfer-s3-sam", + "templateFile": "template-sftp-server.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "Getting started with AWS Transfer Family server endpoints", + "link": "https://docs.aws.amazon.com/transfer/latest/userguide/getting-started.html" + }, + { + "text": "Configure SFTP connectors", + "link": "https://docs.aws.amazon.com/transfer/latest/userguide/configure-sftp-connector.html" + } + ] + }, + "deploy": { + "text": [ + "See the GitHub repo for detailed deployment instructions.", + "bash deploy.sh" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the Amazon S3 input bucket content: aws s3 rm s3://{MySFTPServerS3Bucket} --recursive --region {my-region}", + "Delete the Amazon S3 output bucket content: aws s3 rm s3://{MyLocalS3Bucket} --recursive --region {my-region}", + "bash undeploy.sh" + ] + }, + "authors": [ + { + "name": "Biswanath Mukherjee", + "image": "https://d1rwvjey2iif32.cloudfront.net", + "bio": "I am a Sr. Solutions Architect working at AWS India.", + "linkedin": "biswanathmukherjee" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "transfer", + "label": "Transfer Family server" + }, + "icon2": { + "x": 80, + "y": 50, + "service": "s3", + "label": "S3 bucket" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "" + } + } +} From 9489ab4968d345b371ef20c855231ec14f85d2c6 Mon Sep 17 00:00:00 2001 From: Julian Wood Date: Mon, 20 May 2024 11:42:27 +0100 Subject: [PATCH 6/7] Update awstransfer-s3-sam.json --- awstransfer-s3-sam/awstransfer-s3-sam.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awstransfer-s3-sam/awstransfer-s3-sam.json b/awstransfer-s3-sam/awstransfer-s3-sam.json index 433d0afb4..53e3171c5 100644 --- a/awstransfer-s3-sam/awstransfer-s3-sam.json +++ b/awstransfer-s3-sam/awstransfer-s3-sam.json @@ -1,5 +1,5 @@ { - "title": "Selective file transfer between SFTP server & S3 using AWS Transfer Family", + "title": "Selective file transfer between SFTP server & Amazon S3 using AWS Transfer Family", "description": "This pattern shows how to use AWS Transfer Family to list and transfer specific files between an SFTP server and Amazon S3 bucket.", "language": "YAML", "level": "200", From 299df14237d76f7101188fb310b73a402df95c70 Mon Sep 17 00:00:00 2001 From: Julian Wood Date: Mon, 20 May 2024 11:42:49 +0100 Subject: [PATCH 7/7] Update example-pattern.json --- awstransfer-s3-sam/example-pattern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awstransfer-s3-sam/example-pattern.json b/awstransfer-s3-sam/example-pattern.json index b58019bde..b2b56ab1a 100644 --- a/awstransfer-s3-sam/example-pattern.json +++ b/awstransfer-s3-sam/example-pattern.json @@ -1,5 +1,5 @@ { - "title": "Selective file transfer between SFTP server & S3 using AWS Transfer Family", + "title": "Selective file transfer between SFTP server & Amazon S3 using AWS Transfer Family", "description": "This pattern shows how to use AWS Transfer Family to list and transfer specific files between an SFTP server and Amazon S3 bucket.", "language": "YAML", "level": "200",