AWS Transfer Family ( SFTP ) で接続元のIPアドレスを制限する 

# 参考 - AWS公式ブログ

Use IP whitelisting to secure your AWS Transfer for SFTP servers
https://aws.amazon.com/jp/blogs/storage/use-ip-whitelisting-to-secure-your-aws-transfer-for-sftp-servers/

# Cloud Formation

- Cloud Formation で SFTP用のテンプレートを利用してスタック ( 各種リソース ) を作成する
  - VPCとかElastic IP とか Route Table とか Gateway へのアタッチとか、色々とやってくれる
  - 各リソース名に `Demo` などという言葉が入っているので、気に入らなければ、YAMLを直接編集し直してからアップロードする
  - S3を自分で作成・設定するのであれば、YAMLからはS3の記述箇所は削除して利用する
- YAML はこちら https://awsstorageblogresources.s3.us-west-2.amazonaws.com/russboyertransferfamilyblog/sftp-workshop-endpoint.yaml

![Image](https://github.com/user-attachments/assets/f9516c0f-dc09-4082-952b-4c50dfa90e2d)


# SFTP 

- SFTPサーバーを作成する時に、「VPCでホスト」「インターネット向け」を選ぶ
- Cloud Formation で作成した VPC を選択する
- 「Cloud Formation で作成した VPC」に紐づくセキュリティグループを作成しておいて、それを紐づける
  - 何故かサーバーの編集画面には「セキュリティグループ」の設定が見当たらないので、作成時に紐づける必要がありそう(？) ( 2025/05/07 現在 )

![Image](https://github.com/user-attachments/assets/8b1d8500-f081-4806-a007-8f0852ad53e5)

# セキュリティグループ

- 紐づけたセキュリティグループのインバウンドの設定で、特定のIPアドレスだけを許可する
- PORT 22 を許可すればいけるはず

# その他の設定

その他は以下を参考に

[AWS Transfer Family で SFTPサーバーを起動してコンソールから接続する例](https://github.com/YumaInaura/YumaInaura/issues/3660)

# 参考 - YAMLの内容

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS Transfer Workshop - October 2020
Metadata:
  License:
    Description: |
      Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.

      Permission is hereby granted, free of charge, to any person obtaining a copy of this
      software and associated documentation files (the "Software"), to deal in the Software
      without restriction, including without limitation the rights to use, copy, modify,
      merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
      permit persons to whom the Software is furnished to do so.

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
      INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
      PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Resources:

  # Create a dedicated VPC with internet connectivity
  sftpVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.11.12.0/24
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      InstanceTenancy: default
      Tags:
      - Key: Name
        Value: TransferSFTPDemoVPC
  sftpSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref 'sftpVPC'
      CidrBlock: 10.11.12.0/25
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: 'True'
      Tags:
      - Key: Name
        Value: TransferSFTPDemoSubnet1
  sftpSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref 'sftpVPC'
      CidrBlock: 10.11.12.128/25
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
      MapPublicIpOnLaunch: 'True'
      Tags:
      - Key: Name
        Value: TransferSFTPDemoSubnet2
  sftpInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: TransferSFTPDemoIGW
  sftpAttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref 'sftpVPC'
      InternetGatewayId: !Ref 'sftpInternetGateway'
  sftpRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'sftpVPC'
      Tags:
      - Key: Name
        Value: TransferSFTPDemoRouteTable
  sftpSubnet1RouteAssociaton:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref 'sftpSubnet1'
      RouteTableId: !Ref 'sftpRouteTable'
  sftpSubnet2RouteAssociaton:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref 'sftpSubnet2'
      RouteTableId: !Ref 'sftpRouteTable'
  sftpRoutetoInternet:
    Type: AWS::EC2::Route
    DependsOn: sftpInternetGateway
    Properties:
      RouteTableId: !Ref 'sftpRouteTable'
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref 'sftpInternetGateway'
  sftpEIP1:
    Type: AWS::EC2::EIP
    DependsOn: sftpVPC
    Properties:
      Domain: sftpVPC
  sftpEIP2:
    Type: AWS::EC2::EIP
    DependsOn: sftpVPC
    Properties:
      Domain: sftpVPC
  s3Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
      BucketName: !Join
      - "-"
      - - "awstransferworkshopbucket1"
        - !Select
          - 2
          - !Split
            - "/"
            - !Ref "AWS::StackId"
  s3Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
      BucketName: !Join
      - "-"
      - - "awstransferworkshopbucket2"
        - !Select
          - 2
          - !Split
            - "/"
            - !Ref "AWS::StackId"
  s3Bucket1IamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action:
              - sts:AssumeRole
            Effect: Allow
            Principal:
              Service:
                - transfer.amazonaws.com
        Version: '2012-10-17'
  s3Bucket1RolePolicy:
    Type: AWS::IAM::Policy
    DependsOn: s3Bucket1
    Properties:
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
            - s3:ListBucket
            Resource:
              - !GetAtt s3Bucket1.Arn
          - Effect: Allow
            Resource:
              - !Join [ "/", [ !GetAtt s3Bucket1.Arn, "*" ] ]
            Action:
              - s3:PutObject
              - s3:GetObject
              - s3:DeleteObject
              - s3:DeleteObjectVersion
              - s3:GetObjectVersion
        Version: '2012-10-17'
      PolicyName: policy
      Roles:
        - !Ref 's3Bucket1IamRole'
  s3Bucket2IamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action:
              - sts:AssumeRole
            Effect: Allow
            Principal:
              Service:
                - transfer.amazonaws.com
        Version: '2012-10-17'
  s3Bucket2RolePolicy:
    Type: AWS::IAM::Policy
    DependsOn: s3Bucket2
    Properties:
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
            - s3:ListBucket
            Resource:
              - !GetAtt s3Bucket2.Arn
          - Effect: Allow
            Resource:
              - !Join [ "/", [ !GetAtt s3Bucket2.Arn, "*" ] ]
            Action:
              - s3:PutObject
              - s3:GetObject
              - s3:DeleteObject
              - s3:DeleteObjectVersion
              - s3:GetObjectVersion
        Version: '2012-10-17'
      PolicyName: policy
      Roles:
        - !Ref 's3Bucket2IamRole'
  s3BucketallIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action:
              - sts:AssumeRole
            Effect: Allow
            Principal:
              Service:
                - transfer.amazonaws.com
        Version: '2012-10-17'
  s3BucketallRolePolicy:
    Type: AWS::IAM::Policy
    DependsOn: s3Bucket2
    Properties:
      PolicyDocument:
        Statement:
          - Effect: Allow
            Action:
            - s3:ListBucket
            Resource:
              - !GetAtt s3Bucket1.Arn
              - !GetAtt s3Bucket2.Arn
          - Effect: Allow
            Resource:
              - !Join [ "/", [ !GetAtt s3Bucket1.Arn, "*" ] ]
              - !Join [ "/", [ !GetAtt s3Bucket2.Arn, "*" ] ]
            Action:
              - s3:PutObject
              - s3:GetObject
              - s3:DeleteObject
              - s3:DeleteObjectVersion
              - s3:GetObjectVersion
        Version: '2012-10-17'
      PolicyName: policy
      Roles:
        - !Ref 's3BucketallIamRole'

Outputs:
  bucket1Name:
    Description: S3 Bucket 1 Name
    Value: !Ref s3Bucket1
  iamRole1ForS3Access:
    Description: S3 IAM Role for Transfer and File Gateway
    Value: !GetAtt s3Bucket1IamRole.Arn
  bucket2Name:
    Description: S3 Bucket 2 Name
    Value: !Ref s3Bucket2
  iamRole2ForS3Access:
    Description: S3 IAM Role for Transfer and File Gateway
    Value: !GetAtt s3Bucket2IamRole.Arn
  iamRoleallForS3Access:
    Description: S3 IAM Role for Transfer and File Gateway
    Value: !GetAtt s3BucketallIamRole.Arn
  vpcID:
    Description: ID of VPC
    Value: !Ref sftpVPC
  elasticIP1:
    Description: Elastic IP 1
    Value: !Ref sftpEIP1
  elasticIP2:
    Description: Elastic IP 2
    Value: !Ref sftpEIP2
  subnet1VPC:
    Description: AZ of subnet 1
    Value: !GetAtt sftpSubnet1.AvailabilityZone
  subnet1ID:
    Description: ID of Subnet 1
    Value: !Ref sftpSubnet1
  subnet2VPC:
    Description: AZ of subnet 2
    Value: !GetAtt sftpSubnet2.AvailabilityZone
  subnet2ID:
    Description: ID of Subnet 2
    Value: !Ref sftpSubnet2

```