DynamoDB Детальный контроль доступа GetItem для определенных атрибутов не работает должным образом - PullRequest
0 голосов
/ 29 октября 2019

У меня есть роль, которую я могу взять на себя, и к этой роли прикреплены две политики. Моя цель - разрешить доступ только к 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"
      }
  ]
}

access-specific-attributes.json

{
  "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)

Я предполагаю, что атрибут "цена" будет скрыт, поскольку он отсутствует в разделе "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"
}

Что я делаю не так?

1 Ответ

0 голосов
/ 30 октября 2019

Решение требует использования 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"},
    )
...