Restrict S3 bucket access by STS token age? - amazon-web-services

I have an S3 bucket that I want to restrict access to on the basis of how old the credentials used to access it are. For example if the token used to access the bucket is greater than X days old, I want to deny access. How can I achieve this? Something like this policy -
{
"Version": "2012-10-17",
"Statement": {
"Sid": "RejectLongTermCredentials",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::${bucket}“,
"arn:aws:s3:::${bucket}/*”
],
"Condition": {
aws:TokenIssueTime > 90 days
}
}
}
Is there a way to calculate the age of a token? Any help would be appreciated!

What you are describing sounds very similar to Amazon S3 pre-signed URLs.
A pre-signed URL provides time-limited access to a private object.
Imagine a photo-sharing app. It would work like this:
All photos are kept in private Amazon S3 buckets
A user authenticates to the app
When a user wishes to view a private photo (or the app generates an HTML page that links to a photo, using <img> tags), the app will:
Verify that the user is entitled to view that photo
If they are, the app generates a pre-signed URL, which includes an expiry period (eg 5 minutes)
When the user's browser access the pre-signed URL, Amazon S3 verifies the URL and checks that it is within the expiry period:
If it is, then the private object is private object is returned
If it is not, then the user receives an Access Denied error
It only takes a couple of lines of code to generate a pre-signed URL and it does not require an API call to S3.
In difference to your question, the above process does not require the use of Security Token Service (STS) tokens (which need to be linked to IAM Users or IAM Roles). It is designed to be used for applications rather than IAM Users.

Related

S3 Security regarding Restrict S3 object access

I use S3 to stock static files for my website. Since my website has a login password, I would like to limit access to the static files on S3.
I successfully set the access permission like below.
{
"Version": "2012-10-17",
"Id": "http referer policy example",
"Statement": [
{
"Sid": "Allow get requests originating from www.example.com and example.com.",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"https://mywebsite.com/*",
"http://127.0.0.1:8000/*"
]
}
}
}
]
}
And then, I tried to access the image directly by inputting the URL. I got the result(please see the attached).
My question:
Do you think it is safe to expose RequestID and HostID from a security perspective?
XML image. This is what I got
The Request ID and Host ID are identifiers within Amazon S3 that can be used for debugging and support purposes. There is no harm in S3 exposing that information, and you cannot prevent that information from appearing.
Also, please note that using aws:referer is a rather insecure method of protecting your content, since it can be easily spoofed (faked) when making a request to S3.
If you wish to protect valuable/confidential information in Amazon S3, then you should:
Keep all content in S3 as private (no bucket policy)
Users authenticate to your back-end app
When a user wants to access some private content from S3, your back-end app checks that they are entitled to access the content. If so, the back-end generates an Amazon S3 pre-signed URL, which is a time-limited URL that provides temporary access to a private object.
This can be provided as a direct link, or included in an HTML page (eg <img src="...">)
When S3 receives the pre-signed URL, it verifies the signature and checks the expiry time. If they are valid, it then returns the private object from the S3 bucket.
This way, you can use S3 to serve static content, but your application has full control over who is permitted to access the content. It cannot be faked like referer since each request is signed with a hash of the Secret Key.

Restrict read-write access from my S3 bucket

I am hosting a website where users can write and read files, which are stored into another S3 Bucket. However, I want to restrict the access of these files only to my website.
For example, loading a picture.
If the request comes from my website (example.com), I want the read (or write if I upload a picture) request to be allowed by the AWS S3 storing bucket.
If the request comes from the user who directly writes the Object URL in his browser, I want the storing bucket to block it.
Right now, even with all I have tried, people can access ressources from the Object URL.
Here is my Bucket Policy:
{
"Version": "2012-10-17",
"Id": "Id",
"Statement": [
{
"Sid": "Sid",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectAcl"
],
"Resource": "arn:aws:s3:::storage-bucket/*",
"Condition": {
"StringLike": {
"aws:Referer": "http://example.com/*"
}
}
}
]
}
Additionnal informations:
All my "Block public access" are unchecked as you can see here. (I think that the problem comes from here. When I check the two boxes about ACL, my main problem is fixed, but I got a 403 error - Forbidden - when it comes to upload files to the Bucket, another problem);
My ACL looks like this;
My website is statically hosted on another S3 Bucket.
If you need more informations or details, ask me.
Thank you in advance for your answers.
This message has been written by a French speaking guy. Sorry for the mistakes
"aws:Referer": "http://example.com/*
The referer is an http header passed by the browser and any client could just freely set the value. It provides no real security
However, I want to restrict the access of these files only to my website
Default way restrict access to S3 resources for a website is using the pre-signed url. Basically your website backend can create an S3 url to download or upload an s3 object and pass the url only to authenticated /allowed client. Then your resource bucket can restrict the public access. Allowing upload without authentication is usually a very bad idea.
Yes, in this case your website is not static anymore and you need some backend logic to do so.
If your website clients are authenticated, you may use the AWS API Gateway and Lambda to create this pre-signed url for the clients.

Amazon s3 Pre-signed URL restricted by IP address

The client app requests a presigned URL for S3. Currently we limit the time the URL is valid but would like to also restrict it to the client's IP address.
Is it possible to create a S3 presigned URL that is restricted to a specific IP address?
From what I can tell only CloudFront will let me do this.
Yes!
First, it is worth explaining the concept of a Pre-Signed URL.
Objects in Amazon S3 are private by default. Therefore, if somebody tries to access it without providing credentials, access will be denied.
For example, this would not work for a private object:
https://my-bucket.s3.amazonaws.com/foo.json
To grant temporary access to the object, a Pre-signed URL can be generated. It looks similar to:
https://my-bucket.s3.amazonaws.com/x.json?AWSAccessKeyId=AKIAIVJQM12345CY3A3Q&Expires=1531965074&Signature=g7Jz%2B%2FYyqc%2FDeL1rzo7WM61RusM%3D
The URL says "I am *this* particular Access Key and I authorize temporary access until *this* time and here is my calculated signature to prove it is me".
When the Pre-Signed URL is used, it temporarily uses the permissions of the signing entity to gain access to the object. This means that I can generate a valid pre-signed URL for an object that I am permitted to access, but the pre-signed URL will not work if I am not normally permitted to access the object.
Therefore, to "create a S3 presigned URL that is restricted to a specific IP address", you should:
Create an IAM entity (eg IAM User) that has access to the object (or the whole bucket) with a IP address restriction, and
Use that entity to generate the pre-signed URL
Here is a sample policy for the IAM User:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "54.22.33.44/32"
}
}
}
]
}
The result will be a pre-signed URL that works successfully to access the object, but is then rejected by S3 because the IP address restriction is not met. The user will receive an Access Denied message.

Can't download objects from S3 using the URL link

I have a policy like below which I've attached to several users:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::foo-bar",
"arn:aws:s3:::foo-bar/*"
]
}
]
}
The intent of this policy is that these users would have full control over the bucket foo-bar. However, I'm noticing that even though the users can download the objects in these buckets using Accesskey and Secretkey. They can not download the objects via a URL e.g. https://s3.amazonaws.com/foo-bar/test.docx
I am currently logged in as a IAMManager user and also have AmazonS3FullAccess. I can see the list of objects in this bucket but when I click the URL I can't download them. I can, however, download them via clicking the Download button.
Question
Is there anything I need to change in my policy OR the objects can only be downloaded via the URL when they are publicly available?
By using your IAM policy on your users, you are granting S3 API access to the bucket for those users only. However, when accessing the bucket via the URL, you are not using the S3 APIs and no authentication information is being sent.
In order to download objects from an S3 bucket directly via the URL, the bucket needs to be made public, which you may or may not want to do.

AWS S3 - How to restrict an IAM user to just a single bucket?

I've been struggling with this for hours and cannot figure it out.
I've created a new user, duplicity, and I made a new bucket called bobs-house, and generated the following policy: (any numbers I'm not sure I should share are xxx'd out)
{
"Version": "2012-10-17",
"Id": "Policyxxx",
"Statement": [
{
"Sid": "Stmtxxx",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxx:user/duplicity"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::bobs-house/*"
}
]
}
I go to the policy simulator, and run some tests. Sure enough, it says I can do whatever I want as user duplicity, but only on bobs-house. If duplicity tries to do anything involving other buckets, it's denied. Great!
Now I fire up my FTP client and connect to s3.amazonaws.com (using Transmit's S3 protocol of course, not FTP protocol), using duplicity's IAM access key and secret key. I get "access denied." I can't figure out what I'm doing wrong. Any help would be appreciated!
EDIT:
Got it, thanks to John's answer below. I can use Transmit to connect and view only that bucket's contents, add files, etc. But duplicity (backup software) is complaining:
PermanentRedirect. The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint. bobs-house.s3.amazonaws.com
So I switch the formatting in duplicity's config to:
s3://bops-house.s3.amazonaws.com/test
And then I get this error:
The request signature we calculated does not match the signature you provided. Check your key and signing method.
My access key & secret key are definitely correct.
If you wish to give Amazon S3 permissions to a specific user, it is better to create the policy against the IAM User themselves, rather than the bucket policy.
A bucket policy is good for assigning universal permissions, while a policy in IAM is good for giving permissions to specific Users or Groups of users.
See: User Policy Examples