S3: make a public folder private again?
Asked Answered
E

13

70

How do you make an AWS S3 public folder private again?

I was testing out some staging data, so I made the entire folder public within a bucket. I'd like to restrict its access again. So how do I make the folder private again?

Erskine answered 11/2, 2012 at 7:35 Comment(3)
you can do this witin the managment console or by programmatic APIMirage
Which is what I thought, but I can't seem to find the option within the console. It seems ridiculous to have to use an api to do something so seemingly important.Erskine
Indeed, the console only lets you remove the grant one file by one file. See my detailed answer for how to do this in Python.Mirage
M
41

From what I understand, the 'Make public' option in the managment console recursively adds a public grant for every object 'in' the directory. You can see this by right-clicking on one file, then click on 'Properties'. You then need to click on 'Permissions' and there should be a line:

 Grantee:  Everyone  [x] open/download  [] view permissions   [] edit permission.

If you upload a new file within this directory it won't have this public access set and therefore be private.

You need to remove public read permission one by one, either manually if you only have a few keys or by using a script.

I wrote a small script in Python with the 'boto' module to recursively remove the 'public read' attribute of all keys in a S3 folder:

#!/usr/bin/env python
#remove public read right for all keys within a directory

#usage: remove_public.py bucketName folderName

import sys
import boto3

BUCKET = sys.argv[1]
PATH = sys.argv[2]
s3client = boto3.client("s3")
paginator = s3client.get_paginator('list_objects_v2')
page_iterator = paginator.paginate(Bucket=BUCKET, Prefix=PATH)
for page in page_iterator:
    keys = page['Contents']
    for k in keys:
        response = s3client.put_object_acl(
                        ACL='private',
                        Bucket=BUCKET,
                        Key=k['Key']
                    )

I tested it in a folder with (only) 2 objects and it worked. If you have lots of keys it may take some time to complete and a parallel approach might be necessary.

Mirage answered 11/2, 2012 at 22:14 Comment(2)
You've answered my question, so I've accepted your answer. However, this sucks on Amazon's part. We have to write scripts to make things private again? Just terrible. ascobol, thank you for your helpErskine
aws already provided another solution, please check aws.amazon.com/blogs/aws/…Linders
A
66

The accepted answer works well - seems to set ACLs recursively on a given s3 path too. However, this can also be done more easily by a third-party tool called s3cmd - we use it heavily at my company and it seems to be fairly popular within the AWS community.

For example, suppose you had this kind of s3 bucket and dir structure: s3://mybucket.com/topleveldir/scripts/bootstrap/tmp/. Now suppose you had marked the entire scripts "directory" as public using the Amazon S3 console.

Now to make the entire scripts "directory-tree" recursively (i.e. including subdirectories and their files) private again:

s3cmd setacl --acl-private --recursive s3://mybucket.com/topleveldir/scripts/

It's also easy to make the scripts "directory-tree" recursively public again if you want:

s3cmd setacl --acl-public --recursive s3://mybucket.com/topleveldir/scripts/

You can also choose to set the permission/ACL only on a given s3 "directory" (i.e. non-recursively) by simply omitting --recursive in the above commands.

For s3cmd to work, you first have to provide your AWS access and secret keys to s3cmd via s3cmd --configure (see http://s3tools.org/s3cmd for more details).

Anecdote answered 1/1, 2014 at 4:38 Comment(3)
Am using s3cmd 1.6.1 and this suggestion will not work if you already have 'private' on a folder. In our case we had public and private and setting to private via s3cmd, doesn't remove 'public'. Leaving a note here for other users. Here's the output with --verbose - "already Private, skipping"Sago
how would this look with regexy stuff like s3cmd --access_key $AWS_ACCESS_KEY_ID --secret_key $AWS_SECRET_ACCESS_KEY setacl --acl-private -r s3://$S3_BUCKET_NAME/*.map ?Concessionaire
This tool is amazing. Thanks for sharing your knowledgeKolkhoz
M
41

From what I understand, the 'Make public' option in the managment console recursively adds a public grant for every object 'in' the directory. You can see this by right-clicking on one file, then click on 'Properties'. You then need to click on 'Permissions' and there should be a line:

 Grantee:  Everyone  [x] open/download  [] view permissions   [] edit permission.

If you upload a new file within this directory it won't have this public access set and therefore be private.

You need to remove public read permission one by one, either manually if you only have a few keys or by using a script.

I wrote a small script in Python with the 'boto' module to recursively remove the 'public read' attribute of all keys in a S3 folder:

#!/usr/bin/env python
#remove public read right for all keys within a directory

#usage: remove_public.py bucketName folderName

import sys
import boto3

BUCKET = sys.argv[1]
PATH = sys.argv[2]
s3client = boto3.client("s3")
paginator = s3client.get_paginator('list_objects_v2')
page_iterator = paginator.paginate(Bucket=BUCKET, Prefix=PATH)
for page in page_iterator:
    keys = page['Contents']
    for k in keys:
        response = s3client.put_object_acl(
                        ACL='private',
                        Bucket=BUCKET,
                        Key=k['Key']
                    )

I tested it in a folder with (only) 2 objects and it worked. If you have lots of keys it may take some time to complete and a parallel approach might be necessary.

Mirage answered 11/2, 2012 at 22:14 Comment(2)
You've answered my question, so I've accepted your answer. However, this sucks on Amazon's part. We have to write scripts to make things private again? Just terrible. ascobol, thank you for your helpErskine
aws already provided another solution, please check aws.amazon.com/blogs/aws/…Linders
C
20

For AWS CLI, it is fairly straight forward.

If the object is: s3://<bucket-name>/file.txt

For single object:

aws s3api put-object-acl --acl private --bucket <bucket-name> --key file.txt

For all objects in the bucket (bash one-liner):

aws s3 ls --recursive s3://<bucket-name> | cut -d' ' -f5- | awk '{print $NF}' | while read line; do
    echo "$line"
    aws s3api put-object-acl --acl private --bucket <bucket-name> --key "$line"
done
Cabrilla answered 2/1, 2018 at 12:21 Comment(1)
Your answer is great, but I kinda missed the explanation of what each tool is doing in the script, so that people don't just go blindly executing it. Also, there's an issue with filenames that contain spaces in it. I've posted a new answer with the changes below, but all credit still goes to you :)Iceskate
L
14

From the AWS S3 bucket listing (The AWS S3 UI), you can modify individual file's permissions after making either one file public manually or by making the whole folder content public (To clarify, I'm referring to a folder inside a bucket). To revert the public attribute back to private, you click on the file, then go to permissions and click in the radial button under "EVERYONE" heading. You get a second floating window where you can uncheck the *read object" attribute. Don't forget to save the change. If you try to access the link, you should get the typical "Access Denied" message. I have attached two screenshots. The first one shows the folder listing. Clicking the file and following the aforementioned procedure should show you the second screenshot, which shows the 4 steps. Notice that to modify multiple files, one would need to use the scripts as proposed in previous posts. -Kf

First: Bucket listing in AWS-S3


Second:steps to change access permission

Liaoyang answered 8/7, 2018 at 4:56 Comment(0)
T
8

I actually used Amazon's UI following this guide http://aws.amazon.com/articles/5050/

although it looks somewhat different than that guide

Tilton answered 16/11, 2013 at 21:55 Comment(2)
The instructions @ aws.amazon.com/articles/5050 appear to be out-of-date...from 2011. I do not have an option for going into "Properties" on my Bucket. The Python script mights be the only way now :(Socialization
I was able to get to the Permissions in a non-intuitive way. I browsed to the folder containing the object I cared about and selected the check box next to its name. This caused a pop-up box to slide in from the right. On this page there is a section called Permissions. I noticed that name was a link, and when I clicked it I got to the Permissions tab for the object.Wine
I
6

While @Varun Chandak's answer works great, it's worth mentioning that, due to the awk part, the script only accounts for the last part of the ls results. If the filename has spaces in it, awk will get only the last segment of the filename split by spaces, not the entire filename.

Example: A file with a path like folder1/subfolder1/this is my file.txt would result in an entry called just file.txt.

In order to prevent that while still using his script, you'd have to replace $NF in awk {print $NF} by a sequence of variable placeholders that accounts for the number of segments that the 'split by space' operation would result in. Since filenames might have a quite large number of spaces in their names, I've gone with an exaggeration, but to be honest, I think a completely new approach would probably be better to deal with these cases. Here's the updated code:

#!/bin/sh
aws s3 ls --recursive s3://my-bucket-name | awk '{print $4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25}' | while read line; do
    echo "$line"
    aws s3api put-object-acl --acl private --bucket my-bucket-name --key "$line"
done

I should also mention that using cut didn't have any results for me, so I removed it. Credits still go to @Varun Chandak, since he built the script.

Iceskate answered 30/8, 2018 at 18:17 Comment(0)
N
3

As of now, according to the boto docs you can do it this way

#!/usr/bin/env python
#remove public read right for all keys within a directory

#usage: remove_public.py bucketName folderName

import sys
import boto

bucketname = sys.argv[1]
dirname = sys.argv[2]
s3 = boto.connect_s3()
bucket = s3.get_bucket(bucketname)

keys = bucket.list(dirname)

for k in keys:
    # options are 'private', 'public-read'
    # 'public-read-write', 'authenticated-read'
    k.set_acl('private') 

Also, you may consider to remove any bucket policies under permissions tab of s3 bucket.

Nucleotidase answered 12/7, 2016 at 8:2 Comment(0)
A
1

I did this today. My situation was I had certain top level directories whose files needed to be made private. I did have some folders that needed to be left public.

I decided to use the s3cmd like many other people have already shown. But given the massive number of files, I wanted to run parallel s3cmd jobs for each directory. And since it was going to take a day or so, I wanted to run them as background processes on an EC2 machine.

I set up an Ubuntu machine using the t2.xlarge type. I chose the xlarge after s3cmd failed with out of memory messages on a micro instance. xlarge is probably overkill but this server will only be up for a day.

After logging into the server, I installed and configured s3cmd:

sudo apt-get install python-setuptools wget https://sourceforge.net/projects/s3tools/files/s3cmd/2.0.2/s3cmd-2.0.2.tar.gz/download mv download s3cmd.tar.gz tar xvfz s3cmd.tar.gz cd s3cmd-2.0.2/ python setup.py install sudo python setup.py install cd ~ s3cmd --configure

I originally tried using screen but had some problems, mainly processes were dropping from screen -r despite running the proper screen command like screen -S directory_1 -d -m s3cmd setacl --acl-private --recursive --verbose s3://my_bucket/directory_1. So I did some searching and found the nohup command. Here's what I ended up with:

nohup s3cmd setacl --acl-private --recursive --verbose s3://my_bucket/directory_1 > directory_1.out & nohup s3cmd setacl --acl-private --recursive --verbose s3://my_bucket/directory_2 > directory_2.out & nohup s3cmd setacl --acl-private --recursive --verbose s3://my_bucket/directory_3 > directory_3.out &

With a multi-cursor error this becomes pretty easy (I used aws s3 ls s3//my_bucket to list the directories).

Doing that you can logout as you want, and log back in and tail any of your logs. You can tail multiple files like: tail -f directory_1.out -f directory_2.out -f directory_3.out

So set up s3cmd then use nohup as I demonstrated and you're good to go. Have fun!

Astra answered 1/11, 2018 at 20:27 Comment(0)
W
1

It looks like that this is now addressed by Amazon:

Selecting the following checkbox makes the bucket and its contents private again:

Block public and cross-account access if bucket has public policies

https://aws.amazon.com/blogs/aws/amazon-s3-block-public-access-another-layer-of-protection-for-your-accounts-and-buckets/

enter image description here

UPDATE: The above link was updated August 2019. The options in the image above no longer exist. The new options are in the image below.

enter image description here

Wisniewski answered 5/4, 2019 at 11:0 Comment(1)
OP's question was regarding making a single folder private again, not the entire bucketHenshaw
P
0

enter image description here

If you have S3 Browser, you will be having an option to make it public or private.

Pros answered 11/10, 2018 at 6:29 Comment(0)
C
0

If you want a delightfully simple one-liner, you can use the AWS Powershell Tools. The reference for the AWS Powershell Tools can be found here. We'll be using the Get-S3Object and Set-S3ACL commandlets.

$TargetS3Bucket = "myPrivateBucket"
$TargetDirectory = "accidentallyPublicDir"
$TargetRegion = "us-west-2"

Set-DefaultAWSRegion $TargetRegion

Get-S3Object -BucketName $TargetS3Bucket -KeyPrefix $TargetDirectory | Set-S3ACL -CannedACLName private
Chimera answered 29/11, 2019 at 19:51 Comment(0)
V
0

There are two ways to manage this:

  1. Block all the bucket (simplier but does not applies to all use cases like a s3 bucket with static website and a sub folder for CDN) - https://aws.amazon.com/blogs/aws/amazon-s3-block-public-access-another-layer-of-protection-for-your-accounts-and-buckets/
  2. Block access to a directory from the s3 bucket that was granted Make Public option where you can execute the script from ascobol (I just rewrite it with boto3)
#!/usr/bin/env python
#remove public read right for all keys within a directory

#usage: remove_public.py bucketName folderName

import sys
import boto3

BUCKET = sys.argv[1]
PATH = sys.argv[2]
s3client = boto3.client("s3")
paginator = s3client.get_paginator('list_objects_v2')
page_iterator = paginator.paginate(Bucket=BUCKET, Prefix=PATH)
for page in page_iterator:
    keys = page['Contents']
    for k in keys:
        response = s3client.put_object_acl(
                        ACL='private',
                        Bucket=BUCKET,
                        Key=k['Key']
                    )

cheers

Vaios answered 4/2, 2020 at 0:45 Comment(0)
D
0

Use @ascobol's script, above. Tested with ~2300 items in 1250 subfolders and appears to have worked (lifesaver, thanks!).

I'll provide some additional steps for less experienced folks, but if anyone with more reputation would like to delete this answer and comment on his post stating that it works with 2000+ folders, that'd be fine with me.

  1. Install AWS CLI
  2. Install Python 3 if not present (on mac/linux, check with python3 --version
  3. Install BOTO package for Python 3 with pip install boto3
  4. Create a text file named remove_public.py, and paste in the contents of @ascobol's script
  5. run python3 remove_public.py bucketName folderName

Script contents from ascobol's answer, above

#!/usr/bin/env python
#remove public read right for all keys within a directory

#usage: remove_public.py bucketName folderName

import sys
import boto3

BUCKET = sys.argv[1]
PATH = sys.argv[2]
s3client = boto3.client("s3")
paginator = s3client.get_paginator('list_objects_v2')
page_iterator = paginator.paginate(Bucket=BUCKET, Prefix=PATH)
for page in page_iterator:
    keys = page['Contents']
    for k in keys:
        response = s3client.put_object_acl(
                        ACL='private',
                        Bucket=BUCKET,
                        Key=k['Key']
                    )
Derk answered 17/9, 2022 at 19:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.