Amazon DynamoDB:具有特定属性的细粒度访问控制扫描

时间:2017-01-31 05:29:07

标签: android amazon-web-services amazon-dynamodb aws-sdk

我有一张包含一些元素的表格。我试图在unauth上使用细粒度访问控制(限制对表中特定属性的访问)(我想将特定属性返回给尚未经过身份验证的用户)角色,其中用户根据以下URL {{ 3}}

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "LimitAccessToSpecificAttributes",
        "Effect": "Allow",
        "Action": [
            "dynamodb:GetItem",
            "dynamodb:Query",
            "dynamodb:BatchGetItem",
            "dynamodb:Scan"
        ],
        "Resource": [
            "arn:aws:dynamodb:us-west-2:AccountID:table/MyTable"
        ],
        "Condition": {
            "ForAllValues:StringEquals": {
                "dynamodb:Attributes": [
                    "startDate",
                    "endDate"
                ]
            },
            "StringEqualsIfExists": {
                "dynamodb:Select": "SPECIFIC_ATTRIBUTES",
                "dynamodb:ReturnValues": [
                    "NONE",
                    "UPDATED_OLD",
                    "UPDATED_NEW"
                ]
            }
        }
    }
]
}

当我删除以下角色时,它可以工作:

 "Condition": {
            "ForAllValues:StringEquals": {
                "dynamodb:Attributes": [
                    "startDate",
                    "endDate"
                ]
            },
            "StringEqualsIfExists": {
                "dynamodb:Select": "SPECIFIC_ATTRIBUTES",
                "dynamodb:ReturnValues": [
                    "NONE",
                    "UPDATED_OLD",
                    "UPDATED_NEW"
                ]
            }

问题是,当我运行我的代码(android)时,我得到以下异常:

  

用户:arn:aws:sts :: AccountID:assume-role / Cognito_XXXUnauth_Role / CognitoIdentityCredentials无权执行:dynamodb:扫描资源:arn:aws:dynamodb:us-east-1:AccountID:table / MyTable (服务:AmazonDynamoDB;状态代码:400;错误代码:AccessDeniedException;

我想知道我做错了什么导致异常。 有没有其他方法来获取特定属性?

我正在使用以下android代码:

CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(getApplicationContext(),
                        "identityPoolId",
                        Regions.US_EAST_1
                );

AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(credentialsProvider);

ScanRequest scanRequest = new ScanRequest();
scanRequest = scanRequest.withProjectionExpression("startDate, endDate");
scanRequest.setTableName("MyTable");

try {
    ScanResult scanResult = ddb.scan(scanRequest);
} catch (Exception ex) {
    log(ex.getMessage());
}

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

查看您的IAM策略,看起来资源上允许扫描操作:arn:aws:dynamodb:us-west-2:AccountID:table / MyTable。

请注意,该资源适用于us-west-2。 但是您正在尝试对us-east-1中的资源执行操作。

答案 1 :(得分:0)

确保标识池具有足够的DynamoDB权限(在本例中为执行扫描)。 以下是通过创建未经身份验证的角色并授予其DynamoDB访问权限来使用Cognito的示例: http://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/GettingStarted.Js.Summary.html

然后,正如另一个人所说,请确保您指向您授予权限的同一区域。在这种情况下,请确保US_EAST_1具有足够的Cognito和DDB访问权限。

答案 2 :(得分:0)

我找到了原因。角色中的属性应包括hashkey和range键。当用hashkey和range键替换属性时,我得到了它,也改变了Lisa回答的区域。

我会在这里发布政策和Android代码,以防将来有人想看看它应该如何完成:

{
"Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "dynamodb:DeleteItem",
            "dynamodb:GetItem",
            "dynamodb:PutItem",
            "dynamodb:Scan",
            "dynamodb:Query",
            "dynamodb:UpdateItem",
            "dynamodb:BatchWriteItem"
        ],
        "Resource": [
            "arn:aws:dynamodb:us-east-1:AcountID:table/MyTable",
            "arn:aws:dynamodb:us-east-1:AcountID:table/MyTable/index/*"
        ]
    }
]}

未经身份验证的用户政策:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "LimitAccessToSpecificAttributes",
        "Effect": "Allow",
        "Action": [
            "dynamodb:GetItem",
            "dynamodb:Query",
            "dynamodb:BatchGetItem",
            "dynamodb:Scan"
        ],
        "Resource": [
            "arn:aws:dynamodb:us-east-1:AcountID:table/MyTable"
        ],
        "Condition": {
            "ForAllValues:StringEquals": {
                "dynamodb:Attributes": [
                    "userId",
                    "startDate",
                    "endDate",
                    "Price"
                ]
            },
            "StringEqualsIfExists": {
                "dynamodb:Select": "SPECIFIC_ATTRIBUTES"
            }
        }
    }
]}

android代码包含经过身份验证和未经身份验证的用户(杂乱)的代码。

public PaginatedScanList<Book> scan() {

    PaginatedScanList<Book> result = null;
    AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(_cognito.getCredentialsProvider());

    if (_cognito.getJWTToken() != null) {
        //Authenticated (SignedIn) user flow
        _cognito.credentialsProviderSetLogIn();
        mapper = new DynamoDBMapper(ddb);

        DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
        result = mapper.scan(Book.class, scanExpression);

        if (result != null) {
            for (int i = 0; i < result.size(); i++) {
                log("UserId: " + result.get(i).getUserId());
                log("Price: " + result.get(i).getPrice());
                log("startDate: " + result.get(i).getPrice());
                log("endDate: " + result.get(i).getPrice());
            }
        }
    } else {
        //UnAuthenticated user flow
        ScanRequest scanRequest = new ScanRequest();
        //Write attributes to be retreived. if Price is not exsits, items.get(i).get("Price").getS() will be null
        //If Price is not exists in the policy, policy is null
        scanRequest = scanRequest.withProjectionExpression("UserId, Price, startDate, endDate");//setter for projectionExpression
        //scanRequest.setProjectionExpression("UserId, Price, startDate, endDate"); //not sure why this API exists. It does the same as withProjectionExpression. this is setter for projectionExpression
        scanRequest.setSelect(Select.SPECIFIC_ATTRIBUTES); //Not usre this is needed. works well without it.
        scanRequest.setTableName("MyTable");

        try {
            ScanResult scanResult = ddb.scan(scanRequest);
            final List<Map<String, AttributeValue>> items = scanResult.getItems();

            for (int i = 0; i < items.size(); i++) {
                log("UserId: " + items.get(i).get("UserId").getS());
                log("Price: " + items.get(i).get("Price").getS());
                log("startDate: " + items.get(i).get("startDate").getS());
                log("endDate: " + items.get(i).get("endDate").getS());
            }
        } catch (Exception ex) {
            log(ex.getMessage());
        }
    }

    return result;
}