Amazon dynamodb 特定属性上的DynamoDB细粒度访问控制GetItem未按预期工作

Amazon dynamodb 特定属性上的DynamoDB细粒度访问控制GetItem未按预期工作,amazon-dynamodb,boto3,amazon-iam,dynamodb-queries,Amazon Dynamodb,Boto3,Amazon Iam,Dynamodb Queries,我有一个角色,我可以承担,这个角色有两个附加的政策。我的目标是只允许访问MyTable,然后访问除price之外的所有属性(从策略中省略): access-specific table.json { "Version": "2012-10-17", "Statement": [ { "Sid": "ListAndDescribe", "Effect": "Allow", "Action": [

我有一个角色,我可以承担,这个角色有两个附加的政策。我的目标是只允许访问
MyTable
,然后访问除
price
之外的所有属性(从策略中省略):

access-specific table.json

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "ListAndDescribe",
          "Effect": "Allow",
          "Action": [
              "dynamodb:List*",
              "dynamodb:DescribeReservedCapacity*",
              "dynamodb:DescribeLimits",
              "dynamodb:DescribeTimeToLive"
          ],
          "Resource": "*"
      },
      {
        "Sid": "LimitAccessToSpecificTable",
          "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"
      }
  ]
}
{
  "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:123456789012:table/MyTable"
    ],
    "Condition": {
      "ForAllValues:StringEquals": {
        "dynamodb:Attributes": [
          "type",
          "id",
          "album_art",
          "artist_id",
          "format",
          "name_title",
          "sku",
          "year"
        ]
      },
      "StringEqualsIfExists": {
        "dynamodb:Select": "SPECIFIC_ATTRIBUTES"
      }
    }
  }]
}
access-specific-attributes.json

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "ListAndDescribe",
          "Effect": "Allow",
          "Action": [
              "dynamodb:List*",
              "dynamodb:DescribeReservedCapacity*",
              "dynamodb:DescribeLimits",
              "dynamodb:DescribeTimeToLive"
          ],
          "Resource": "*"
      },
      {
        "Sid": "LimitAccessToSpecificTable",
          "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"
      }
  ]
}
{
  "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:123456789012:table/MyTable"
    ],
    "Condition": {
      "ForAllValues:StringEquals": {
        "dynamodb:Attributes": [
          "type",
          "id",
          "album_art",
          "artist_id",
          "format",
          "name_title",
          "sku",
          "year"
        ]
      },
      "StringEqualsIfExists": {
        "dynamodb:Select": "SPECIFIC_ATTRIBUTES"
      }
    }
  }]
}
我的测试如下:

#!/usr/bin/env python3

import decimal
import json

import boto3
from botocore.exceptions import ClientError


# Helper class to convert a DynamoDB item to JSON.
class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        return super(DecimalEncoder, self).default(o)


sts = boto3.client("sts")

print("Default Provider Identity: : " + sts.get_caller_identity()["Arn"])

role_to_assume_arn = "arn:aws:iam::123456789012:role/LimitedDynamoDBRole"
role_session_name = "test_session"

response = sts.assume_role(
    RoleArn=role_to_assume_arn, RoleSessionName=role_session_name
)

creds = response["Credentials"]

sts_assumed_role = boto3.client(
    "sts",
    aws_access_key_id=creds["AccessKeyId"],
    aws_secret_access_key=creds["SecretAccessKey"],
    aws_session_token=creds["SessionToken"],
)

print("AssumedRole Identity: " + sts_assumed_role.get_caller_identity()["Arn"])

# Create boto3 session with assumed role

session = boto3.Session(
    aws_access_key_id=creds["AccessKeyId"],
    aws_secret_access_key=creds["SecretAccessKey"],
    aws_session_token=creds["SessionToken"],
)

# Attempt scanning "user" table, which is *not* allowed by policy

try:
    dynamodb = session.resource("dynamodb")
    table = dynamodb.Table("user")
    response = table.scan()
except ClientError as e:
    print("Error: %s" % e)

# Attempt GetItem on "MyTable" table, which does *not* allow
# the "price" attribute

try:
    dynamodb = session.resource("dynamodb")
    table = dynamodb.Table("pinehead_records_s3")
    response = table.get_item(Key={"type": "album", "id": 15})
    print(json.dumps(response["Item"], cls=DecimalEncoder, indent=4))
except ClientError as e:
    print("Error: %s" % e)
我的假设是“price”属性将被隐藏,因为它不在策略的
“dynamodb:Attributes”
部分

但是,当我执行
get_item
时,该属性会明确返回:

{
    "name_title": "Album title",
    "artist_id": 20211,
    "year": 1995,
    "price": 4.91,
    "id": 15,
    "album_art": "/albumart/5/1/15.jpg",
    "format": "7\" Vinyl",
    "sku": "20211-15",
    "type": "album"
}

我做错了什么?

解决方案需要使用
ProjectionExpression
将返回的属性限制为策略允许的属性:

response = table.query(
        KeyConditionExpression=Key("type").eq("album") & Key("id").eq(15),
        ProjectionExpression="#T, id, name_title",
        # ProjectionExpression="#T, id, name_title, price",  # AccessDeniedException
        ExpressionAttributeNames={"#T": "type"},
    )