Rishabh
Rishabh

Reputation: 473

Amazon AWS S3 Uploads from iOS Device

I have been trying to upload images/videos to s3 by following their docs. But, after alot of tries I just keep getting Access Denied error.

I have setup a cognito pool for s3:* access in its UnAuth role. But the problem is I cant get it to work from iOS device. I use AWSTransferManager to create upload function but this is the response i get:

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message> 
<RequestId>DEE11EF134B50C8D</RequestId><HostId>/+qV8CLvPZHi4lIAHrVnKf1sDmWFcFS1dcfMX5XG0yfPG/TIASBfo/T5aGZRZg77wdn7siOrRVc=</HostId></Error>
Upload failed with error: (The operation couldn’t be completed. (com.amazonaws.AWSServiceErrorDomain error 11.))

Bucket Policy-:

{
    "Version": "2012-10-17",
    "Id": "Policy1460611228663",
    "Statement": [
        {
            "Sid": "Stmt1460611220793",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::MY_ACCOUNT_ID:root"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::MY_BUCKET_NAME/*"
        }
    ]
}

IAM UnAuth Role Policy-:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*",
                "mobileanalytics:PutEvents",
                "cognito-sync:*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

I am stuck at this. Please suggest what am I doing wrong?

let accK = "myaccesskey"
let secretK = "mysecretkey"
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: accK, secretKey: secretK)
let configuration = AWSServiceConfiguration(region: AwsRegion, credentialsProvider: credentialsProvider)
AWSS3TransferManager.register(with: configuration!, forKey: "mys3")

Upvotes: 2

Views: 3628

Answers (2)

Bommas
Bommas

Reputation: 238

With an identity pool and IAM policy configured such that the bucket is accessible by the identity pool's unauth role, the following code should work

//Setup credentials
let credentialProvider = AWSCognitoCredentialsProvider(regionType: YOUR-IDENTITY-POOL-REGION, identityPoolId: "YOUR-IDENTITY-POOL-ID")

//Setup the service configuration
let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialProvider)

//Setup the transfer utility configuration
let tuConf = AWSS3TransferUtilityConfiguration()

//Register a transfer utility object
AWSS3TransferUtility.register(
with: configuration!,
transferUtilityConfiguration: tuConf,
forKey: "transfer-utility-with-advanced-options"
)

//Look up the transfer utility object from the registry to use for your transfers.
let transferUtility = AWSS3TransferUtility.s3TransferUtility(forKey: "transfer-utility-with-advanced-options")


transferUtility.uploadData(
        testData,
        bucket: "BUCKET",
        key: "KEY",
        contentType: "video/mp4",
        expression: uploadExpression,
        completionHandler: uploadCompletionHandler
        ).continueWith (block: { (task) -> AnyObject? in
            XCTAssertNil(task.error)

            return nil
    })

Please look at the link I'd posted earlier for further information.

Upvotes: 1

Bommas
Bommas

Reputation: 238

Using the access key and secret key is one way to go about it. Another way is to setup a Cognito Identity pool and get temporary, short lived, credentials from it to access the bucket. This would be a more secure way and what we recommend as the best practice.

When you create a Cognito Identity pool, it automatically creates 2 roles i.e., the "auth" and the "unauth" role. This is a convenience mechanism as many mobile apps have the notion of a signed-in user and anonymous user ( someone who hasn't yet signed in). At typical example would an ecommerce app that you can use to search and browse and only have to sign in to add to cart/make a purchase.

You can setup either the "auth" or the "unauth" or both roles (depending on your scenario) to have permissions on the bucket and that will enable you to access the buckets via the app. See https://docs.aws.amazon.com/aws-mobile/latest/developerguide/how-to-integrate-an-existing-bucket.html for more information.

Also, I'd recommend that you use the TransferUtility and not the TransferManager for the S3 uploads/downloads.

Upvotes: 0

Related Questions