VPC エンドポイントタイプの Transfer for SFTP を Terraform で作ってみた

Terraform を使って VPC エンドポイントタイプの Transfer for SFTP を作ってみました。
2019.05.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

先日、CloudFormation で Transfer for SFTP を作成できるようになりましたが、今回は Terraform で作成してみました。

[新機能] Transfer for SFTP が CloudFormation で作成可能になりました

ちなみに Terraform AWS プロバイダの CHANGELOG を参照すると、2018年12月13日リリースの 1.52.0aws_transfer_server が追加されていました。Transfer for SFTP がリリースされたのは2018年11月26日ですので、3週間弱で使えるようになってたってことですね。早いですねー。すごいですねー。

という Terraform 好きの白々しいポジトークをしつつ、さっそく試していきます。

今回の環境

今回はパブリックエンドポイントではなく、VPC エンドポイントの Transfer for SFTP を作成します。検証した際の、バージョンは下記のとおりです。(まだ v0.12 あげてません。。)

$ terraform -v
Terraform v0.11.11
+ provider.aws v2.12.0

今回は VPC エンドポイントタイプになりますので、provider.aws v2.6.0 以上が必要となります。

tf ファイル

作成した tf ファイルは以下のとおりです。VPC やサブネット、S3 など割愛してている Terraform リソースは xxxx にしていますので、ご自身の環境に読み替えてください。

security-group.tf

VPC エンドポイントに割り当てるセキュリティグループを作成します。今回は VPC の CIDR 内から 22 番を許可しました。

security-group.tf

resource "aws_security_group" "sftp-vpce-sg" {
  name        = "sftp-vpce-sg"
  description = "Security Group for SFTP VPC Endpoint"
  vpc_id      = "${aws_vpc.xxxx.id}"

  # VPC 内からの接続を許可
  ingress {
    from_port = 22
    to_port   = 22
    protocol  = "tcp"

    cidr_blocks = [
      "${aws_vpc.xxxx.cidr_block}",
    ]
  }
}

VPC エンドポイントの作成

Transfer for SFTP と VPC をつなぐ VPC エンドポイントを作成します。service_namecom.amazonaws.ap-northeast-1.transfer.server を指定します。

vpc-endpoint.tf

#--------------------------------------
# VPC Endpoint
#--------------------------------------
resource "aws_vpc_endpoint" "sftp-vpce" {
  vpc_id            = "${aws_vpc.xxxx.id}"
  service_name      = "com.amazonaws.ap-northeast-1.transfer.server"
  vpc_endpoint_type = "Interface"

  # 先ほど作成した VPC エンドポイント用の SG を指定
  security_group_ids = [
    "${aws_security_group.sftp-vpce-sg.id}",
  ]
  
  # VPC エンドポイントを作成するサブネットを指定
  subnet_ids = [
    "${aws_subnet.xxxx.id}",
    "${aws_subnet.xxxx.id}",
  ]

  private_dns_enabled = true
}

IAM ロールおよびポリシーの作成

作成するロールは以下の2つです。

  • ログ出力用
  • SFTP ユーザ 用

まずはポリシードキュメントを用意しておきます。

iam-policy-document.tf

#--------------------------------------
# IAM Policy Document
#--------------------------------------
# Transfer for SFTP の assume policy
data "aws_iam_policy_document" "assume-sftp" {
  statement {
    sid = "AssumeTransferforSFTP"
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"

      identifiers = [
        "transfer.amazonaws.com",
      ]
    }
  }
}

# ログ出力用のポリシー
data "aws_iam_policy_document" "cwl-full" {
  statement {
    sid = "AllowFullAccesstoCloudWatchLogs"
    actions = [
      "logs:*",
    ]

    resources = [
      "*",
    ]
  }
}

# SFTP ユーザ用のポリシー
data "aws_iam_policy_document" "sftpuser" {
  statement {
    sid = "AllowBucket"
    effect = "Allow"

    actions = [
      "s3:GetBucketLocation",
      "s3:ListBucket",
    ]
    
    # ホームディレクトリの S3 バケット
    resources = [
      "${aws_s3_bucket.xxxx.arn}",
    ]
  }

  statement {
    sid = "AllowObject"
    effect = "Allow"

    actions = [
      "s3:PutObject",
      "s3:GetObject",
      "s3:DeleteObject",
      "s3:DeleteObjectVersion",
      "s3:GetObjectVersion",
    ]

    # ホームディレクトリの S3 バケット
    resources = [
      "${aws_s3_bucket.xxxx.arn}/*",
    ]
  }
}

先ほどのポリシードキュメントを使って、IAM ポリシーを定義します。SFTP ユーザ用のポリシーは、今回はインラインポリシーにしたいので、ここではポリシー定義していません。(利用頻度が高いのであれば、定義すると良いかと思います)

iam-policy.tf

#--------------------------------------
# IAM Policy
#--------------------------------------
resource "aws_iam_policy" "cwl-full" {
  name   = "cloudwatch-logs-full-policy"
  policy = "${data.aws_iam_policy_document.cwl-full.json}"
}

そして IAM ロールを作成およびポリシーをアタッチします。

iam-role.tf

#--------------------------------------
# IAM Role
#--------------------------------------
# ログ出力用 IAM ロール
resource "aws_iam_role" "sftp-log-role" {
  name               = "sftp-log-role"
  assume_role_policy = "${data.aws_iam_policy_document.assume-sftp.json}"
}

# SFTP ユーザ用 IAM ロール
resource "aws_iam_role" "sftpuser-role" {
  name               = "sftpuser-role"
  assume_role_policy = "${data.aws_iam_policy_document.assume-sftp.json}"
}

#--------------------------------------
# IAM Policy Attachment
#--------------------------------------
# ログ出力用 IAM ロールにポリシーをアタッチ
resource "aws_iam_policy_attachment" "sftp-log-role" {
  name = "sftp-log-role"
  
  roles = [
    "${aws_iam_role.sftp-log-role.id}",
  ]
  policy_arn = "${aws_iam_policy.cwl-full.arn}"
} 

#--------------------------------------
# IAM Role Policy
#--------------------------------------
# SFTP ユーザ用 インラインポリシーをアタッチ
resource "aws_iam_role_policy" "sftpuser-role" {
  name   = "sftpuser-role-policy"
  role   = "${aws_iam_role.sftpuser-role.id}"
  policy = "${data.aws_iam_policy_document.sftpuser.json}"
}

そして Transfer for SFTP

前置きがながくなりましたが、ようやく Transfer for SFTP のリソース定義です。

transfer-sftp.tf

#--------------------------------------
# Transfer Server
#--------------------------------------
resource "aws_transfer_server" "sftp-server" {
  identity_provider_type = "SERVICE_MANAGED"
  # ログ出力用の IAM ロール
  logging_role           = "${aws_iam_role.sftp-log-role.arn}"

  endpoint_details {
    vpc_endpoint_id = "${aws_vpc_endpoint.sftp-vpce.id}"
  }

  # VPC エンドポイントタイプを指定
  endpoint_type = "VPC_ENDPOINT"
}

#--------------------------------------
# Transfer user
#--------------------------------------
resource "aws_transfer_user" "sftp-user" {
  server_id      = "${aws_transfer_server.sftp-server.id}"
  user_name      = "sftpuser"
  
  # ホームディレクトリに使用する S3 バケット名を指定
  home_directory = "/${aws_s3_bucket.xxxx.id}"
  
  # SFTP ユーザ用の IAM ロールを指定
  role           = "${aws_iam_role.sftpuser-role.arn}"
}

#--------------------------------------
# Transfer ssh key
#--------------------------------------
resource "aws_transfer_ssh_key" "sftp-ssh-key" {
  server_id = "${aws_transfer_server.sftp-server.id}"
  user_name = "${aws_transfer_user.sftp-ssnb.user_name}"
  
  # SSH 公開鍵を指定
  body      = "ssh-rsa AAAABBBBBBCCCCCCC・・・・・"
}

接続に使用する SSH 公開鍵 を body に指定します。以下のコマンドでキーペアファイルを利用することも可能です。

$ chmod 400 key-pair.pem
$ ssh-keygen -y -f key-pair.pem
ssh-rsa AAAABBBBBBCCCCCCC・・・・(省略)

tf ファイルが作成できましたら、terraform plan して terraform apply で構築しましょう!

接続してみる

今回、VPC エンドポイントタイプとして作成しましたので、sftp クライアントからの接続先は VPC エンドポイントの FQDN になります。先ほどの SSH キーの秘密鍵を使って接続します。

$ sftp -i key-pair.pem sftpuser@vpce-05xxxxxxxxx-xxxxxxxx.server.transfer.ap-northeast-1.vpce.amazonaws.com
sftp>

ログインできたので putget が正しくできるか確認します。

# PUT
sftp> put test.txt
Uploading test.txt to /<home_directory>/test.txt
text.txt                                                    100%    5     0.7KB/s   00:00

# GET
sftp> get test.txt
Fetching /<home_directory>/test.txt to test.txt
/<home_directory>/test.txt                                  100%    5     0.1KB/s   00:00

問題なく SFTP できることが確認できました!

さいごに

今回は1ユーザでの利用想定でしたが、次は複数ユーザを想定したスコープダウンポリシーも Terraform で作成してみたいと思います。

以上!大阪オフィスの丸毛(@marumo1981)でした!