SFTP User Lock Down in AWS Transfer Service

First things first. 

I know SFTP topics aren’t sexy.  I can hear you right now, SFTP is an archaic protocol only used by people with archaic systems.  And generally speaking, you’re probably not wrong.  However, many of us still work in those environments and are making progress towards cloud services one piece at a time.

That said, one of our road-blocks to moving into an AWS environment was secure file transfer.  Certainly you could argue that we should have our customers send files to us via S3.  And again, you’re probably not wrong – however convincing hundreds of customers on the other side of this equation to redesign their file transfer method isn’t an easy task.

Thankfully, AWS has listened to it’s customers and now provides a service allowing customers to talk directly to S3 via SFTP .

You can read about AWS’ Transfer Service launch here.

I was fortunate enough to play with this a little during AWS re:Invent 2018 and after doing so, I have to admit: for the simplicity of what it is, it’s quite nice.

What I want to share with you today is locking down individual user access.  While your environment may be different and not require tight user controls, ours does.  With that in mind, we allow users to see their ‘root’ folder, but not modify it.  This is primarily so files aren’t dropped off in places we’re not expecting, but it does provide some value

Now, let’s get started…

I won’t re-write (or plagiarize like I’ve seen other places) the existing tutorials as, I think, the fine people at AWS have done a sufficient job walking you through it.  The official tutorial can be found here

When you follow those steps, at a minimum, you should have a SFTP server in the running state.  You should have created the logging policy to send logs to Cloudwatch (and applied that policy to the server) tracking user activity and you should have created the the first user.

Your console should look something like the following

And with this, your use should be able to connect to the SFTP server and write to their home directory.  However, the stock config also allows the user to move around and potentially upload/download files outside of their home directory.  This is bad.

Once logged in, I appear to have full access to the bucket. That’s no good.

Let’s take a closer look at the stock IAM role applied to the user

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListingOfUserFolder",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::bucket_name"
            ]
        },
        {
            "Sid": "HomeDirObjectAccess",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObjectVersion",
                "s3:DeleteObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::bucket_name/*"
        }
    ]
}

What you’ll notice is that the user has full access to the bucket. We definitely do not want that. AWS provides the ability to lock down access by applying policy to the individual and offers some SFTP specific variables to be used in that policy. For specifics, reference the tutorial here.

Those variables are

  • ${transfer:HomeBucket}
  • ${transfer:HomeDirectory}
  • ${transfer:HomeFolder}
  • ${transfer:UserName}

TAKE NOTE – These variables are Transfer Service specific and cannot be used in the role itself.

In order to lock down the user, we need to make some changes to the role and to the individual policy applied to the user. First let’s modify the policy attached to the role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListingOfUserFolder",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::bucket_name"
        },
        {
            "Sid": "HomeDirObjectAccess",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObjectVersion",
                "s3:GetObject",
                "s3:DeleteObjectVersion",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::bucket_name/*"
        }
    ]
}

Very specifically, we’re removing the action of s3:GetBucketLocation.

Now, we want to restrict the user within their own home directory. You’ll need to create a new policy within IAM, and then apply that policy to the specific user on the edit user screen inside the Transfer Service console. My locked down policy is as follows:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListingOfUserFolder",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${transfer:HomeBucket}",
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "sftp/${transfer:UserName}/*",
                        "sftp/${transfer:UserName}"
                    ]
                }
            }
        },
        {
            "Sid": "NoWriteHomeDirObjectAccess",
            "Effect": "Deny",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::${transfer:HomeDirectory}/"
            ]
        },
        {
            "Sid": "WriteSubDirObject",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObjectVersion",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::${transfer:HomeDirectory}/inbound/*",
                "arn:aws:s3:::${transfer:HomeDirectory}/outbound/*",
                "arn:aws:s3:::${transfer:HomeDirectory}/inbound/",
                "arn:aws:s3:::${transfer:HomeDirectory}/outbound/"
            ]
        }
    ]
}

You’ll notice now that I’m not referencing any hard-coded values (aside from the target directories). Instead, I’m able to use the Transfer Service specific variables to expand the path that I want to lock the user into.

From here, the user is able to sign in and view the inbound and outbound directories, but can no longer create new top level objects.

I’m able to login, but not create new top level objects. I must first move into an appropriate target folder. My user is sufficiently locked to folders I intend.

As you can see, the user is now locked to the preferred set of folders and cannot write objects outside of the folder structure I intend.

I hope this brief article has been informative. I don’t think I skipped over any important note.

Leave a Reply

Your email address will not be published. Required fields are marked *