Simplest way to setup bucket-per-client in Amazon S3 - amazon-web-services

I want some clients to be able to programmatically upload files for me. Amazon S3 obviously sounds great in terms of availability and durability. But setup seems like such a complicated (and hence, error-prone) step for this: AFAIK I can't avoid creating users, groups, roles, policies...
Is there something simpler that would allow me to create a bucket with a token, so that I can simply give that token to the client w/o wasting time and w/o the risk of clicking something wrong that could lead to problems or security holes?
P.S. I won't need to do that for thousands of client, just a few.

You can make a automatized system for create many s3 buckets you need, you can use Terraform for interact with the API of your cloud provider and make this tasks programatically, so with this you can create many things around this (maybe a frontend/backend for create this buckets from your browser and of course you can make a function for send through a email all info around the access for the bucket by example).
In this repo you can see an example: https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/s3-replication

Your first consideration should be how these clients interact with Amazon S3. This will then impact how you allow them to access Amazon S3.
There are several options:
Option 1: Provide IAM User credentials
Normally, IAM credentials should only be given to staff in your own company. However, if you have a small number of well-known clients, you could create an IAM User for each of them.
You can then assign permissions that allow them to access a specific bucket, or a path within a shared bucket, and they can use the AWS CLI to upload/download files, or programmatically via an AWS SDK.
You would need to give them an Access Key + Secret Key to access their S3 storage.
Rather than using separate buckets, you could grant access to a path within a shared bucket with a relatively simple Bucket Policy that grants access to a path based on their IAM Username. See:IAM policy elements: Variables and tags - AWS Identity and Access Management
Option 2: Provide temporary credentials
If they are programmatically accessing AWS, then the clients could:
Programmatically authenticate against your back-end application
The back-end application uses the AWS Security Token Service (STS) to generate temporary credentials and returns them to the client
The client then uses those credentials in the same way as Option 1
The difference with this option is that the clients authenticate to your own back-end rather than using IAM User credentials.
Option 3: Pre-signed URLs
Instead of providing credentials to your clients, your back-end app can generate Amazon S3 pre-signed URLs, which are time-limited URL that provides temporary access to upload/download private objects in Amazon S3.
This allows the back-end to totally control which objects the users can upload or download. For example, think of a photo-sharing application that keeps photos private. When a user wants to view one of their photos, the app can generate a pre-signed URL that grants access to a private object without having to provide AWS credentials.
Bottom line
The simplest option is to create an IAM user for each client (Option 1) and provide them credentials. They could then use the AWS Command-Line Interface (CLI) or a program you provide to interact with S3.
If you consider this to be too complex, then you might want to use services like box.com or even Microsoft OneDrive, which provide a more friendly interface on top of storage services.

Thanks to John Rotenstein's great detailed answer with various options, I think I found the simplest available option for my case. It is based on IAM policy elements: Variables and tags and involves creating a single bucket with separate "home folders" in it (one per client). No need for user groups or roles.
Here is a step-by-step guide:
Create a common bucket (let's call it bucket-shared-with-clients).
Create a single (universal) policy like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["s3:ListBucket"],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::bucket-shared-with-clients"],
"Condition": {"StringLike": {"s3:prefix": ["${aws:username}/*"]}}
},
{
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::bucket-shared-with-clients/${aws:username}/*"]
}
]
}
Create IAM user accounts - one per client. The users need to be with Programmatic access enabled and in the Permission view simply go for the Attach existing policies directly option.
Here is an example Python client that uploads a file:
import boto3
ACCESS_KEY = 'YourAccessKeyComesHere'
SECRET_KEY = 'YourSecterKeyComesHere'
USERNAME = 'client-a' # The username is also used as a "home folder", as can be seen below
FILE_TO_UPLOAD = 'some-file.json'
session = boto3.Session(aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY)
s3 = session.resource('s3')
bucket = s3.Bucket('bucket-shared-with-clients')
key = f'{USERNAME}/{FILE_TO_UPLOAD}' # If USERNAME didn't match the client's IAM User, we would get an AccessDenied error
bucket.upload_file(FILE_TO_UPLOAD, key)

Related

How to give access of s3 bucket residing in Account A to different iam users from multiple aws accounts?

I am working on aws SAM project and i have a requirement of giving access to my S3 bucket to multiple iam users from unknown aws accounts but i can't make bucket publicly accessible. I want to secure my bucket as well as i want any iam user from any aws account to access the contents of my S3 bucket. Is this possible?
Below is the policy i tried and worked perfectly.
{
"Version": "2012-10-17",
"Id": "Policy1616828964582",
"Statement": [
{
"Sid": "Stmt1616828940658",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/STS_Role_demo"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::new-demo-bkt/*"
}
]
}
Above policy is for one user but i want any user from other AWS account to access my contents without making the bucket and objects public so how can i achieve this?
This might be possible using a set of Conditions on the incoming requests.
I can think of two options:
You create an IAM role that your SAM application uses even when running in other accounts
You create S3 bucket policies that allow unknown users access
If you decide to look into S3 bucket policies, I suggest using an S3 Access Point to better manage access policies.
Access points are named network endpoints that are attached to buckets
that you can use to perform S3 object operations, such as GetObject
and PutObject. Each access point has distinct permissions and network
controls that S3 applies for any request that is made through that
access point. Each access point enforces a customized access point
policy that works in conjunction with the bucket policy that is
attached to the underlying bucket.
You can use a combination of S3 Conditions to restrict access. For example, your SAM application could include specific condition keys when making S3 requests, and the bucket policy then allows access based on those conditions.
You can also apply global IAM conditions to S3 policies.
This isn't great security though, malicious actors might be able to figure out the headers and spoof requests to your bucket. As noted on some conditions such as aws:UserAgent:
This key should be used carefully. Since the aws:UserAgent value is
provided by the caller in an HTTP header, unauthorized parties can use
modified or custom browsers to provide any aws:UserAgent value that
they choose. As a result, aws:UserAgent should not be used to
prevent unauthorized parties from making direct AWS requests. You can
use it to allow only specific client applications, and only after
testing your policy.

Disable AWS S3 Management Console

Is it possible to disable AWS S3 management console for the security reasons?
We don't want anyone including root/admin users to access customer files directly from the AWS S3. We should just have programmatic access to the files stored in S3.
If this is not possible, is it possible to stop listing the directories inside the bucket for all users ?
This is a tricky one to implement, however the following should be able to fulfill the requirements.
Programmatic Access Only
You need to define exactly which actions should be denied you would not want to block access completely otherwise you might lose the ability to do anything.
If you're in AWS you should use IAM roles, and a VPC endpoint to connect to the S3 service. Both of these support the ability to control access within your S3 buckets Bucket Policy.
You would use this to deny List* actions where the source is not the VPC endpoint. You could also deny where its not a specific subset of roles.
This works for all programmatic use cases and for people who login as an IAM user from the console, however this does not deny access to the root user.
Also bear in mind for any IAM user/IAM role that they do not have access unless you explicitly give it to them via an IAM policy.
Denying Access To The Root User
There is currently only one way to deny access to the root user of an AWS account (although you should share these credentials with anyone, even within your company) as that is using a Service Control Policy.
To do this the account would need to be part of an AWS organisation (as an organisational unit). If/once it is you would create a SCP that denies access to the root principal for the specific actions that you want.
An example of this policy for you would be
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictS3ForRoot",
"Effect": "Deny",
"Action": [
"s3:List*"
],
"Resource": [
"*"
],
"Condition": {
"StringLike": {
"aws:PrincipalArn": [
"arn:aws:iam::*:root"
]
}
}
}
]
}
Yes, it is possible to disable the Management Console: Don't give users a password.
When creating IAM Users, there are two ways to provide credentials:
Sign-in Credentials (for the Console)
Access Key (for API calls)
Only give users an Access Key and they won't be able to login to the console.
However, please note that when when using the Management Console, users have exactly the same permissions as using an Access Key. Thus, if they can do it in the console, then they can do it via an API call (if they have an Access Key).
If your goal is to prevent anyone from accessing customer files, then you can add a Bucket Policy with a Deny on s3:* for the bucket, where the Principal is not the customer.
Please note, however, that the Root login can remove such a policy.
If the customers really want to keep their own data private, then they would need to create their own AWS account and keep their files within it, without granting you access.

What is the access control model for DynamoDB?

In a traditional MySql Server situation, as the owner of a database, I create a User and from the database I grant certain access rights to the User object. An application can then (and only) access the database by supplying the password for the User.
I am confused and don't see a parallel when it comes to giving access to a DynamoDB table. From the DynamoDB Tables page, I can't find a means to grant permission for an IAM user to access a table. There is an Access Control tab, but that appears to be for Facebook/Google users.
I read about attaching policies but am confused further. How is access controlled if anyone can create a policy that can access all tables?
What am I missing? I just want to create a "login" for a Node application to access my DynamoDB table.
If anyone in your AWS account can create IAM policies you have a real security issue.
Only a few accounts should do that (Create IAM policies).
DynamoDB accesses work along with IAM user like you said, so, you need to do the following:
Create IAM groups to classify your IAM users, for example, DBAGroup for dbas, DEVGroup for developers and so on.
Create IAM policies to grant specific access to your DynamoDB tables for each group.
Apply the policies to the specific groups for granting accesses.
For login purposes, you need to develop a module that will verify the credentials with IAM service, so you need to execute IAM API calls. This module could be deployed within an EC2, could be a Javascript call to an API Gateway's endpoint along with a Lambda function, Etc.
What you need to do:
Create an account on IAM service that will be able to execute API calls to the IAM service for verifying credentials (Login and password).
This account should have only permissions for doing that (Verify user login and password).
Use the API credentials to be able to execute API calls.
If you don't want to create your own module for login purposes, take a look at Amazon Cognito
Amazon Cognito lets you add user sign-up/sign-in and access control to your web and mobile apps quickly and easily. Cognito scales to millions of users and supports sign-in with social identity providers such as Facebook, Google, and Amazon, and enterprise identity providers via SAML 2.0.
The last step is how your module execute API calls to IAM service? As you may know, we need API Credentials. So, using the logged user's credentials you will be able to execute API calls to read data from tables, execute CRUD operations, Etc.
To set specific permissions for certain tables as in SQL Server you must do this:
In Identity and Access Management (IAM) create a new security policy on the JSON tab:
Use the following JSON as an example to allow a full CRUD or remove the items within the "Action" section to allow only the desired items:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListAndDescribe",
"Effect": "Allow",
"Action": [
"dynamodb:List*",
"dynamodb:DescribeReservedCapacity*",
"dynamodb:DescribeLimits",
"dynamodb:DescribeTimeToLive"
],
"Resource": "*"
},
{
"Sid": "SpecificTable",
"Effect": "Allow",
"Action": [
"dynamodb:BatchGet*",
"dynamodb:DescribeStream",
"dynamodb:DescribeTable",
"dynamodb:Get*",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchWrite*",
"dynamodb:CreateTable",
"dynamodb:Delete*",
"dynamodb:Update*",
"dynamodb:PutItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/MyTable"
}
]
}
Give the policy a name and save it.
After that, go to the Identity and Access Management (IAM) Users screen and create a new user as shown below.
Remember to set the field ** Access type ** as * Programmatic access *, it is not necessary to add the user to a group, click on "Atach existing policies directly" and add the policy previously created.
Finished! You already have everything you need to connect your application to Dynamodb.

S3 giving someone permission to read and write

I've created a s3 server which contain a large number of images. I'm now trying to create a bucket policy, which fits my needs. First of all i want everybody to have read permission, so they can see the images. However i also want to give a specific website the permission to upload and delete images. this website is not stored on a amazon server? how can i achieve this? so far i've created an bucket policy which enables everybody to see the images
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::examplebucket/*"
}
]
}
You can delegate access to your bucket. To do this, the other server will need AWS credentials.
If the other server were an EC2 instance that you owned then you could do this easily by launching it with an IAM role. If the other server were an EC2 instance that someone else owned, then you could delegate access to them by allowing them to assume an appropriate IAM role in your account. But for a non-EC2 server, as seems to be the case here, you will have to provide AWS credentials in some other fashion.
One way to do this is by adding an IAM user with a policy allowing s3:PutObject and s3:DeleteObject on resource "arn:aws:s3:::examplebucket/*", and then give the other server those credentials.
A better way would be to create an IAM role that has the same policy and then have the other server assume that role. The upside is that the credentials must be rotated periodically so if they are leaked then the window of exposure is smaller. To assume a role, however, the other server will still need to authenticate so will need some base IAM user credentials (unless you have some way to get credentials via identity federation). You could add a base IAM user who has permissions to assume the aforementioned role (but has no other permissions) and supply the base IAM user credentials to the other server. When using AssumeRole in this fashion you should require an external ID. You may also be able to restrict the entity assuming this role to the specific IP address(es) of the other server using a policy condition (not 100% sure if this is possible).
The Bucket Policy will work nicely to give everybody read-only access.
To give specific permissions to an application:
Create an IAM User for the application (this also creates access credentials)
Assign a policy to the IAM User that gives the desired permissions (very similar to a Bucket Policy)
The application then makes API calls to Amazon S3 using the supplied access credentials
See also: Amazon S3 Developer Guide

IAM access to EC2 REST API?

I'm new to AWS. My client uses AWS to host his EC2 instances. Right now, we are trying to get me API access. Obviously, I need my authentication details to do this.
He set me up an IAM identity under his account, so I can login to the AWS web console and configure EC2 instances. I cannot, however, for the life of me, figure out where my API access keys are displayed. I don't have permissions to view 'My Account', which is where I imagine they'd be displayed.
So, what I'm asking, is how can he grant me API access through his account? How can I access the AWS API using my IAM identity?
Michael - sqlbot's answer is correct (+1), but not entirely complete given the comparatively recent but highly useful addition of Variables in AWS Access Control Policies:
Today we’re extending the AWS access policy language to include
support for variables. Policy variables make it easier to create
and manage general policies that include individualized access
control.
This enables implementation of an 'IAM Credentials Self Management' group policy, which would usually be assigned to the most basic IAM group like the common 'Users'.
Please note that the following solution still needs to be implemented by the AWS account owner (or an IAM user with permissions to manage IAM itself), but this needs to be done once only to enable credentials self management by other users going forward.
Official Solution
A respective example is included in the introductory blog post (and meanwhile has been available at Allow a user to manage his or her own security credentials in the IAM documentation too - Update: this example vanished again, presumably due to being applicable via custom solutions using the API only and thus confusing):
Variable substitution also simplifies allowing users to manage their
own credentials. If you have many users, you may find it impractical
to create individual policies that allow users to create and rotate
their own credentials. With variable substitution, this becomes
trivial to implement as a group policy. The following policy permits
any IAM user to perform any of the key and certificate related actions
on their own credentials. [emphasis mine]
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action":["iam:*AccessKey*","iam:*SigningCertificate*"],
"Resource":["arn:aws:iam::123456789012:user/${aws:username}"]
}
]
}
The resource scope arn:aws:iam::123456789012:user/${aws:username} ensures that every user is effectively only granted access to his own credentials.
Please note that this solution still has usability flaws depending on how AWS resources are accessed by your users, i.e. via API, CLI, or the AWS Management Console (the latter requires additional permissions for example).
Also, the various * characters are a wildcard, so iam:*AccessKey* addresses all IAM actions containing AccessKey (see IAM Policy Elements Reference for details).
Extended Variation
Disclaimer: The correct configuration of IAM policies affecting IAM access in particular is obviously delicate, so please make your own judgement concerning the security impact of the following solution!
Here's a more explicit and slightly extended variation, which includes AWS Multi-Factor Authentication (MFA) device self management and a few usability enhancements to ease using the AWS Management Console:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"iam:CreateAccessKey",
"iam:DeactivateMFADevice",
"iam:DeleteAccessKey",
"iam:DeleteSigningCertificate",
"iam:EnableMFADevice",
"iam:GetLoginProfile",
"iam:GetUser",
"iam:ListAccessKeys",
"iam:ListGroupsForUser",
"iam:ListMFADevices",
"iam:ListSigningCertificates",
"iam:ListUsers",
"iam:ResyncMFADevice",
"iam:UpdateAccessKey",
"iam:UpdateLoginProfile",
"iam:UpdateSigningCertificate",
"iam:UploadSigningCertificate"
],
"Effect": "Allow",
"Resource": [
"arn:aws:iam::123456789012:user/${aws:username}"
]
},
{
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:ListVirtualMFADevices"
],
"Effect": "Allow",
"Resource": "arn:aws:iam::123456789012:mfa/${aws:username}"
}
]
}
"You" can't, but:
In IAM, under Users, after he selects your user, he needs to click Security Credentials > Manage Access Keys, and then choose "Create Access Key" to create an API Key and its associated Secret, associated with your IAM user. On the next screen, there's a message:
Your access key has been created successfully.
This is the last time these User security credentials will be available for download.
You can manage and recreate these credentials any time.
Where "manage" means "deactivate or delete," and "recreate" means "start over with a new one." The IAM admin can subsequently see the keys, but not the associated secrets.
From that screen, and only from that screen, and only right then, is where the IAM admin can view the both key and the secret associated with the key or download them to a CSV file. Subsequently, one with appropriate privileges can see the keys for a user within IAM but you can never view the secret again after this one chance (and it would be pretty preposterous if you could).
So, your client needs to go into IAM, under the user he created for you, and create an API key/secret pair, save the key and secret, and forward that information to you via an appropriately-secure channel... if he created it but didn't save the associated secret, he should delete the key and create a new one associated with your username.
If you don't have your own AWS account, you should sign up for one so you can go into the console with full permissions as yourself and understand the flow... it might make more sense than my description.