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 Professional version 3.6.0
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-03fba503e0f395265"
us-east-2 = "ami-058c754451c08c838"
us-west-1 = "ami-048b561dc65ce6270"
us-gov-east-1 = "ami-0425d69392ab68063"
us-gov-west-1 = "ami-09d22af40ecbd6681"
us-west-2 = "ami-0707fa61413163e84"
eu-central-1 = "ami-0f634793a0c19b6ba"
eu-west-1 = "ami-0c26ae99ca4706c65"
eu-west-2 = "ami-05076b778b56ccac7"
eu-west-3 = "ami-00268706eaf4563c4"
ca-central-1 = "ami-0f7304892d3a003cf"
eu-central-2 = "ami-0c501356c7a81fbda"
ap-southeast-1 = "ami-03ef111581b4b5ac3"
ap-southeast-2 = "ami-0feb483004f1336ea"
ap-southeast-4 = "ami-01ff6c9475157f016"
ap-southeast-3 = "ami-05b9ee18d34a47c84"
ap-south-1 = "ami-01317057573239afb"
ap-south-2 = "ami-0af74e0b5539a359c"
ap-northeast-1 = "ami-0695b4c117de3f042"
ap-northeast-2 = "ami-06f101aae42bdd40d"
ap-northeast-3 = "ami-07843e4b125df3a34"
eu-north-1 = "ami-09622032675fb4e74"
ap-east-1 = "ami-00bcbe7d27a01e932"
me-south-1 = "ami-0d3ec3d540291ea9d"
me-central-1 = "ami-088c83242e436829f"
eu-south-1 = "ami-044cec828d93f7c0b"
eu-south-2 = "ami-053262e7babee7daa"
sa-east-1 = "ami-0ceec7356a1a41e7c"
il-central-1 = "ami-0e3d88e35133bf2c2"
af-south-1 = "ami-0fb6b71fe1cae6760"
}
}
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