Terraform Template
Overview
You can deploy SFTP Gateway version 3.x using Terraform, as an alternative to CloudFormation.
This article covers deploying a single EC2 instance of SFTP Gateway version 3.4.6
on AWS. The Terraform template is provided as an example, so feel free to further customize it for your business case.
Note: Make sure you are subscribed to SFTP Gateway in the AWS Marketplace. Otherwise, your AWS account will not be authorized to deploy any product AMIs without a subscription.
Running the template
This article contains two files:
sftpgw-single-instance-default-vpc.tf
terraform.tfvars
Create these two files on your workstation, using the file contents at the bottom of this page. Make adjustments to the terraform.tfvars
file. Then, run the following commands:
terraform init
terraform plan
When you are ready to deploy the template, run:
terraform apply
How does it work
This article contains a main Terraform template named:
sftpgw-single-instance-default-vpc.tf
This template provisions the following resources:
EC2 instance
: This server is based on the SFTP Gateway marketplace AMIEC2 Security Group
: Allows TCP22
from anywhere, but locks down admin ports80
,443
,2222
to a single IPElastic IP
: Static IP that retains the IP after a rebootIAM role
: Grants the EC2 instance access to S3
There's also another file that contains variables:
terraform.tfvars
Since this file is named terraform.tfvars
, it will be automatically used without having to run:
terraform -var-file terraform.tfvars
You can configure the following variables:
key_name
: Specify the name of your EC2 key pairregion
: Specify your current regionadmin_ip
: Get your workstation's public IP fromcheckip.dyndns.org
. Append/32
to specify a single IP rangeopen_s3_permissions
: Set this totrue
for full S3 permissions. Usefalse
to restrict permissions to buckets with the naming conventionsftpgw-i-*
aws_profile
: Optional. Specify an AWS CLI profile if not using the default profile.ec2_instance_size
: Optional. Defaults tot3.medium
. Use this to override the EC2 instance size.disk_volume_size
: Optional. Defaults to32
. Use this to override the EC2 disk size, in GB.
Terraform file contents
sftpgw-single-instance-default-vpc.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.27"
}
}
required_version = ">= 0.14.9"
}
provider "aws" {
region = var.region
profile = var.aws_profile != "" ? var.aws_profile : null
}
data "aws_partition" "current" {}
variable "open_s3_permissions" {
type = bool
description = "Set this to true to allow full S3 access to support multiple buckets. Otherwise, S3 permissions are limited to our default bucket naming convention: sftpgw-<instance-id>."
default = false
}
variable "region" {
type = string
description = "This is the AWS region"
}
variable "ami_map" {
type = map
default = {
us-east-1 = "ami-05423b9bf8ec631fc"
us-east-2 = "ami-0e869fdba7337203f"
us-west-1 = "ami-01a3669f67c2d0d8a"
us-gov-east-1 = "ami-06bdd58dd4c48adcf"
us-gov-west-1 = "ami-05bece0ffbb9c049a"
us-west-2 = "ami-0109be966a0118f94"
eu-central-1 = "ami-0d69b5eb9feca7bf9"
eu-west-1 = "ami-0e9cd42841ae758bd"
eu-west-2 = "ami-09ed82f57c303abcf"
eu-west-3 = "ami-0551b7ff645633185"
ca-central-1 = "ami-0e8eb0d0ef32e5e96"
eu-central-2 = "ami-0e4dcf7ea1b3c150c"
ap-southeast-1 = "ami-000cf8c1d8aaba2b8"
ap-southeast-2 = "ami-0872ada1f0fae54f7"
ap-south-1 = "ami-0c66c0e69776d60f4"
ap-northeast-1 = "ami-064ece5429a7c17cd"
ap-northeast-2 = "ami-006a63e591f76cc8c"
eu-north-1 = "ami-03451562f32341591"
ap-east-1 = "ami-004129c6348c1b3f0"
me-south-1 = "ami-011ec244dbbeafcb3"
me-central-1 = "ami-0253c954e71ce06fc"
eu-south-1 = "ami-0d2389b193d2164c1"
}
}
variable "aws_profile" {
type = string
default = "default"
description = "Optional: specify an AWS profile"
}
variable "key_name" {
type = string
description = "Make sure you have access to this EC2 key pair. Otherwise, create a new key pair before proceeding."
}
variable "ec2_instance_size" {
type = string
description = "EC2 instance size. Recommended: t3.medium for testing, m5.large for production."
default = "t3.medium"
}
variable "disk_volume_size" {
type = number
description = "Disk volume size in GB. Must be at least 8."
default = 32
}
variable "admin_ip" {
type = string
description = "Public IP address range for SSH and web access. Use a CIDR range to restrict access. To get your local machine's IP, see http://checkip.dyndns.org/. (Remember to append /32 for a single IP e.g. 12.34.56.78/32) For security reasons, do not use 0.0.0.0/0."
validation {
condition = can(regex("([1-9]\\d{0,2})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/([1-9]\\d{0,1})",var.admin_ip))
error_message = "Must be a valid IP CIDR range in the form of x.x.x.x/x. Do not use 0.0.0.0/0."
}
}
resource "aws_eip" "eip" {
instance = aws_instance.sftpgateway.id
vpc = true
}
resource "aws_instance" "sftpgateway" {
ami = lookup(var.ami_map, var.region)
instance_type = var.ec2_instance_size
key_name = var.key_name
security_groups = ["EC2-Security-group"]
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name
root_block_device {
volume_size = var.disk_volume_size
volume_type = "gp2"
encrypted = true
}
tags = {
Name = "SFTPGateway"
}
}
resource "aws_iam_role" "iam_role" {
name = "iam_role"
managed_policy_arns = var.open_s3_permissions ? ["arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonS3FullAccess"] : []
assume_role_policy = jsonencode({
Version: "2012-10-17",
Statement: [
{
Action: "sts:AssumeRole",
Principal: {
Service: "ec2.amazonaws.com"
},
Effect: "Allow"
}
]
})
}
resource "aws_iam_instance_profile" "ec2_profile" {
name = "ec2_profile"
role = aws_iam_role.iam_role.name
}
resource "aws_iam_role_policy" "ec2_policy" {
name = "ec2_policy"
role = aws_iam_role.iam_role.id
policy = jsonencode({
"Version": "2012-10-17",
"Statement": [{
Action: "s3:*",
Effect: "Allow",
Resource: "arn:${data.aws_partition.current.partition}:s3:::sftpgw-i-*"
}, {
Action: [
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams",
"logs:CreateLogGroup",
"ec2:DescribeAvailabilityZones",
"ec2:DescribeInstances",
"ec2:DescribeTags",
"s3:ListAllMyBuckets",
"cloudformation:DescribeStacks",
"cloudformation:ListStackResources"
],
Effect: "Allow",
Resource: "*"
}]
})
}
resource "aws_security_group" "sg" {
name = "EC2-Security-group"
description = "EC2 Security Group"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 2222
to_port = 2222
protocol = "tcp"
cidr_blocks = [var.admin_ip]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [var.admin_ip]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [var.admin_ip]
}
egress {
from_port = 0
protocol = "tcp"
to_port = 65535
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
protocol = "udp"
to_port = 65535
cidr_blocks = ["0.0.0.0/0"]
}
}
output "hostname" {
value = aws_instance.sftpgateway.public_ip
}
output "default_bucket" {
value = format("%s/%s","sftpgw-",aws_instance.sftpgateway.id)
description = "Default S3 bucket"
}
terraform.tfvars
key_name = "Rob"
region = "us-east-1"
admin_ip = "3.222.237.17/32"
open_s3_permissions = false