Last active
July 3, 2020 08:19
-
-
Save markilott/d4f6fc2614748c078794781b39eb8319 to your computer and use it in GitHub Desktop.
AWS Transfer CloundFormation Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: '2010-09-09' | |
Description: >- | |
AWS Transfer SFTP with EIP and Security Group | |
You can choose a fully automated and self-contained demo by creating a new VPC. | |
Or you can select an existing VPC. The VPC must have 2 public subnets with internet access. | |
There is one manual step in the Console required for an existing VPC after the CloudFormation script- | |
- Open the VPC Service page | |
- Go to Endpoints | |
- Select the new transfer Endpoint | |
- Select Security Groups tab, and Edit | |
- Attach the new SFTP Security Group | |
Optionally create a DNS CNAME - requires a Route53 hosted domain. | |
Metadata: | |
AWS::CloudFormation::Interface: | |
ParameterGroups: | |
- | |
Label: | |
default: Select Options | |
Parameters: | |
- CreateDnsFlag | |
- CreateVpcFlag | |
- | |
Label: | |
default: DNS Settings (skip if not required) | |
Parameters: | |
- Hostname | |
- Route53Domain | |
- | |
Label: | |
default: New VPC Options (skip if using existing) | |
Parameters: | |
- VpcCidr | |
- SubCidr1 | |
- SubCidr2 | |
- | |
Label: | |
default: Existing VPC Options (you must select here, they will be ignored if you are creating a new VPC) | |
Parameters: | |
- ExistingVpc | |
- Subnet1 | |
- Subnet2 | |
- | |
Label: | |
default: Test User and Network | |
Parameters: | |
- TestUserName | |
- TestUserKey | |
- TestCidr | |
ParameterLabels: | |
CreateDnsFlag: | |
default: Create CNAME for the SFTP server (requires Route53 Domain) | |
CreateVpcFlag: | |
default: Create a new VPC for the server (recommended for a demo) | |
Hostname: | |
default: DNS Hostname (FQDN) | |
Route53Domain: | |
default: Route53 Domain Id | |
VpcCidr: | |
default: CIDR Range for the new VPC | |
SubCidr1: | |
default: CIDR Range for new Subnet1 | |
SubCidr2: | |
default: CIDR Range for new Subnet2 | |
ExistingVpc: | |
default: Existing VPC Id | |
Subnet1: | |
default: Existing Subnet1 Id | |
Subnet2: | |
default: Existing Subnet2 Id | |
TestUserName: | |
default: Test Username | |
TestUserKey: | |
default: Test User SSH Public Key | |
TestCidr: | |
default: IP Range for SFTP Whitelist | |
Parameters: | |
CreateVpcFlag: | |
Description: Create new isolated VPC for SFTP | |
Default: 'Yes' | |
Type: String | |
AllowedValues: | |
- 'Yes' | |
- 'No' | |
ConstraintDescription: Must specify Yes or No | |
ExistingVpc: | |
Description: Select the VPC | |
Type: AWS::EC2::VPC::Id | |
Default: Select... | |
Subnet1: | |
Description: Select a subnet from the VPC | |
Type: AWS::EC2::Subnet::Id | |
Default: Select... | |
Subnet2: | |
Description: Select a second subnet from the VPC | |
Type: AWS::EC2::Subnet::Id | |
Default: Select... | |
VpcCidr: | |
Description: CIDR Block for VPC | |
Type: String | |
Default: 192.168.0.0/16 | |
SubCidr1: | |
Description: CIDR Block for Subnet1 | |
Type: String | |
Default: 192.168.100.0/24 | |
SubCidr2: | |
Description: CIDR Block for Subnet2 | |
Type: String | |
Default: 192.168.101.0/24 | |
CreateDnsFlag: | |
Description: Create DNS alias (requires Route53 Domain) | |
Default: 'No' | |
Type: String | |
AllowedValues: | |
- 'Yes' | |
- 'No' | |
ConstraintDescription: Must specify Yes or No | |
Hostname: | |
Type: String | |
Default: sftp-public.mydomain.com | |
Description: Enter a FQDN for the SFTP server (optional) | |
Route53Domain: | |
# using String rather than AWS::Route53::HostedZone::Id so that it can be left blank | |
Type: String | |
Description: Enter the Route53 Domain ID (optional) | |
Default: Hosted Zone ID | |
TestUserName: | |
Type: String | |
Description: Username for the test user | |
Default: test-user | |
TestUserKey: | |
Type: String | |
Description: SSH public key for the test user | |
Default: ssh-rsa - copy your key here | |
TestCidr: | |
Type: String | |
Description: CIDR Range | |
Default: 0.0.0.0/0 | |
Conditions: | |
CreateDns: | |
!Equals [ !Ref CreateDnsFlag, 'Yes' ] | |
NoDns: | |
!Equals [ !Ref CreateDnsFlag, 'No' ] | |
CreateVpc: | |
!Equals [ !Ref CreateVpcFlag, 'Yes' ] | |
ExistingVpc: | |
!Equals [ !Ref CreateVpcFlag, 'No' ] | |
Resources: | |
# New VPC ---------------------------------------------------------- | |
NewVpc: | |
Condition: CreateVpc | |
Type: 'AWS::EC2::VPC' | |
Properties: | |
CidrBlock: !Ref VpcCidr | |
Tags: | |
- Key: Name | |
Value: SFTPVPC | |
NewSubnet1: | |
Condition: CreateVpc | |
Type: 'AWS::EC2::Subnet' | |
Properties: | |
AvailabilityZone: | |
Fn::Select: | |
- 0 | |
- Fn::GetAZs: "" | |
CidrBlock: !Ref SubCidr1 | |
MapPublicIpOnLaunch: false | |
VpcId: !Ref NewVpc | |
Tags: | |
- Key: Name | |
Value: SFTP-1 | |
NewSubnet2: | |
Condition: CreateVpc | |
Type: 'AWS::EC2::Subnet' | |
Properties: | |
AvailabilityZone: | |
Fn::Select: | |
- 1 | |
- Fn::GetAZs: "" | |
CidrBlock: !Ref SubCidr2 | |
MapPublicIpOnLaunch: false | |
VpcId: !Ref NewVpc | |
Tags: | |
- Key: Name | |
Value: SFTP-2 | |
SftpInternetGateway: | |
Condition: CreateVpc | |
Type: AWS::EC2::InternetGateway | |
SftpGatewayAttach: | |
Condition: CreateVpc | |
Type: AWS::EC2::VPCGatewayAttachment | |
Properties: | |
InternetGatewayId: !Ref SftpInternetGateway | |
VpcId: !Ref NewVpc | |
PublicRouteTable: | |
Condition: CreateVpc | |
Type: 'AWS::EC2::RouteTable' | |
Properties: | |
VpcId: | |
Ref: NewVpc | |
Tags: | |
- Key: Name | |
Value: Public | |
PublicDefaultRoute: | |
Condition: CreateVpc | |
Type: 'AWS::EC2::Route' | |
Properties: | |
RouteTableId: | |
Ref: PublicRouteTable | |
DestinationCidrBlock: 0.0.0.0/0 | |
GatewayId: | |
Ref: SftpInternetGateway | |
PublicRouteTableAssociation1: | |
Condition: CreateVpc | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
SubnetId: | |
Ref: NewSubnet1 | |
RouteTableId: | |
Ref: PublicRouteTable | |
PublicRouteTableAssociation2: | |
Condition: CreateVpc | |
Type: AWS::EC2::SubnetRouteTableAssociation | |
Properties: | |
SubnetId: | |
Ref: NewSubnet2 | |
RouteTableId: | |
Ref: PublicRouteTable | |
SftpIngress: | |
# added to default VPC SG => allows public SSH to all resources in the new VPC | |
Condition: CreateVpc | |
Type: AWS::EC2::SecurityGroupIngress | |
DependsOn: NewVpc | |
Properties: | |
CidrIp: !Ref TestCidr | |
Description: Inbound to SFTP | |
FromPort: 22 | |
GroupId: !GetAtt NewVpc.DefaultSecurityGroup | |
IpProtocol: tcp | |
ToPort: 22 | |
# Existing VPC ---------------------------------------------------------- | |
# The security group must be manually attached to the SFTP Network interface | |
# after the creation of the server. | |
SftpSg: | |
Condition: ExistingVpc | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupName: SFTPGroup | |
GroupDescription: SFTP Access | |
VpcId: !Ref ExistingVpc | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: 22 | |
ToPort: 22 | |
CidrIp: !Ref TestCidr | |
# Wait Handles ----------------------------------------------------------- | |
# Cannot use !If in DependsOn, so using this hack instead | |
# SftpServer is dependent on SftpGatewayAttach when we create a new VPC | |
NewWaitHandle: | |
Condition: CreateVpc | |
DependsOn: SftpGatewayAttach | |
Type: AWS::CloudFormation::WaitConditionHandle | |
ExistingWaitHandle: | |
Type: AWS::CloudFormation::WaitConditionHandle | |
WaitCondition: | |
Type: AWS::CloudFormation::WaitCondition | |
Properties: | |
Handle: !If [CreateVpc, !Ref NewWaitHandle, !Ref ExistingWaitHandle] | |
Timeout: '1' | |
Count: 0 | |
# Server ----------------------------------------------------------------- | |
SftpServer: | |
Type: AWS::Transfer::Server | |
DependsOn: WaitCondition | |
Properties: | |
EndpointDetails: | |
AddressAllocationIds: | |
- !GetAtt EIP1.AllocationId | |
- !GetAtt EIP2.AllocationId | |
SubnetIds: | |
- !If [CreateVpc, !Ref NewSubnet1, !Ref Subnet1] | |
- !If [CreateVpc, !Ref NewSubnet2, !Ref Subnet2] | |
VpcId: !If [CreateVpc, !Ref NewVpc, !Ref ExistingVpc] | |
EndpointType: VPC | |
IdentityProviderType: SERVICE_MANAGED | |
LoggingRole: !GetAtt LoggingRole.Arn | |
Protocols: | |
- SFTP | |
EIP1: | |
Type: 'AWS::EC2::EIP' | |
Properties: | |
Domain: vpc | |
EIP2: | |
Type: 'AWS::EC2::EIP' | |
Properties: | |
Domain: vpc | |
Dns: | |
Condition: CreateDns | |
Type: AWS::Route53::RecordSet | |
Properties: | |
HostedZoneId : !Ref Route53Domain | |
Name: !Sub '${Hostname}' | |
ResourceRecords: | |
- !Sub ${SftpServer.ServerId}.server.transfer.${AWS::Region}.amazonaws.com | |
Type: CNAME | |
TTL: 300 | |
# IAM ---------------------------------------------------------- | |
LoggingRole: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- | |
Effect: Allow | |
Principal: | |
Service: | |
- transfer.amazonaws.com | |
Action: | |
- sts:AssumeRole | |
Path: '/' | |
# ManagedPolicyArns: | |
# - | |
LoggingPolicy: | |
Type: AWS::IAM::ManagedPolicy | |
Properties: | |
Description: CloudWatch logs for SFTP | |
Path: '/' | |
PolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- | |
Effect: Allow | |
Action: | |
- logs:CreateLogStream | |
- logs:DescribeLogStreams | |
- logs:CreateLogGroup | |
- logs:PutLogEvents | |
Resource: | |
- '*' | |
Roles: | |
- Ref: LoggingRole | |
UserRole: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: | |
- transfer.amazonaws.com | |
Action: | |
- sts:AssumeRole | |
Path: / | |
UserPolicy: | |
Type: AWS::IAM::ManagedPolicy | |
Properties: | |
Description: CloudWatch logs for SFTP | |
Path: '/' | |
PolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- | |
Effect: Allow | |
Action: | |
- s3:ListBucket | |
Resource: | |
- !GetAtt SftpBucket.Arn | |
- | |
Effect: Allow | |
Action: | |
- s3:PutObject | |
- s3:GetObject | |
- s3:GetObjectVersion | |
Resource: | |
- !Sub '${SftpBucket.Arn}/*' | |
Roles: | |
- Ref: UserRole | |
# S3 ---------------------------------------------------------- | |
SftpBucket: | |
Type: AWS::S3::Bucket | |
Properties: | |
PublicAccessBlockConfiguration: | |
BlockPublicAcls: true | |
BlockPublicPolicy: true | |
IgnorePublicAcls: true | |
# Users --------------------------------------------------------- | |
TestUser: | |
Type: AWS::Transfer::User | |
DependsOn: SftpServer | |
Properties: | |
ServerId: !GetAtt SftpServer.ServerId | |
UserName: !Ref TestUserName | |
HomeDirectory: !Sub "/${SftpBucket}/home/${TestUserName}" | |
Policy: > | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Sid": "AllowListingOfUserFolder", | |
"Effect": "Allow", | |
"Action": "s3:ListBucket", | |
"Resource": "arn:aws:s3:::${transfer:HomeBucket}", | |
"Condition": { | |
"StringLike": { | |
"s3:prefix": [ | |
"home/${transfer:UserName}/*", | |
"home/${transfer:UserName}" | |
] | |
} | |
} | |
}, | |
{ | |
"Sid": "HomeDirObjectAccess", | |
"Effect": "Allow", | |
"Action": [ | |
"s3:PutObject", | |
"s3:GetObject", | |
"s3:GetObjectVersion" | |
], | |
"Resource": "arn:aws:s3:::${transfer:HomeDirectory}*" | |
} | |
] | |
} | |
Role: !GetAtt UserRole.Arn | |
SshPublicKeys: | |
- !Ref TestUserKey | |
# Outputs ----------------------------------------------------------------------------- | |
Outputs: | |
EIP1: | |
Description: SFTP Server EIP1 | |
Value: !Ref EIP1 | |
Export: | |
Name: !Sub '${AWS::StackName}-EIP1' | |
EIP2: | |
Description: SFTP Server EIP1 | |
Value: !Ref EIP2 | |
Export: | |
Name: !Sub '${AWS::StackName}-EIP2' | |
SftpHostName: | |
Description: DNS hostname for the server | |
Condition: NoDns | |
Value: !Sub ${SftpServer.ServerId}.server.transfer.${AWS::Region}.amazonaws.com | |
Export: | |
Name: !Sub '${AWS::StackName}-ServerDNS' | |
SftpCustomHostName: | |
Description: DNS hostname for the server | |
Condition: CreateDns | |
Value: !Sub ${Hostname} | |
Export: | |
Name: !Sub '${AWS::StackName}-ServerDNS' | |
S3Bucket: | |
Description: the SFTP home S3 bucket | |
Value: !Ref SftpBucket | |
Export: | |
Name: !Sub '${AWS::StackName}-S3Bucket' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment