DynamoDB access control is often thought of as just granting permissions to tables, but its true power lies in the ability to precisely control what operations can be performed on which attributes within those tables.

Imagine a scenario where you have a Users table with user profiles. You want to allow a UserProfileService to read and update most user attributes, but prevent it from touching the isAdmin flag. You also need a ReportingService that can only read specific columns (like lastLogin and email) from the Users table, but not write anything.

Here’s how that might look in action.

First, let’s set up a sample table:

aws dynamodb create-table \
    --table-name Users \
    --attribute-definitions AttributeName=userId,AttributeType=S \
    --key-schema AttributeName=userId,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST

Now, let’s create an IAM user for our UserProfileService:

aws iam create-user --user-name UserProfileServiceUser

And an IAM user for our ReportingService:

aws iam create-user --user-name ReportingServiceUser

We’ll then attach policies to these users.

The policy for UserProfileServiceUser looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowReadWriteAllUserAttributesExceptAdmin",
            "Effect": "Allow",
            "Action": [
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Users",
            "Condition": {
                "ForAllValues:StringNotEquals": {
                    "dynamodb:LeadingKeys": ["admin-user-id-to-block"],
                    "dynamodb:Attributes": ["isAdmin"]
                }
            }
        },
        {
            "Sid": "AllowAdminToReadOwnAdminStatus",
            "Effect": "Allow",
            "Action": "dynamodb:GetItem",
            "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Users",
            "Condition": {
                "ForAllValues:StringEquals": {
                    "dynamodb:Attributes": ["isAdmin", "userId"]
                }
            }
        }
    ]
}

Let’s break down what’s happening here. The UserProfileServiceUser can perform GetItem, PutItem, UpdateItem, and DeleteItem on the Users table. The crucial part is the Condition block. dynamodb:LeadingKeys is a condition key that, when used with ForAllValues:StringNotEquals, prevents the action if the userId (which is the partition key, or "leading key" in DynamoDB terms) matches the specified value. More importantly for this example, dynamodb:Attributes is used with ForAllValues:StringNotEquals to prevent any operation that attempts to read or write the isAdmin attribute. The second statement allows GetItem specifically for isAdmin and userId if the userId is "admin-user-id-to-block", demonstrating how you can make exceptions.

The policy for ReportingServiceUser is simpler:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowReadOnlySpecificUserAttributes",
            "Effect": "Allow",
            "Action": "dynamodb:GetItem",
            "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Users",
            "Condition": {
                "ForAllValues:StringEquals": {
                    "dynamodb:Attributes": ["userId", "email", "lastLogin"]
                }
            }
        }
    ]
}

This policy allows ReportingServiceUser to only perform GetItem operations, and crucially, it can only retrieve the userId, email, and lastLogin attributes. Any attempt to fetch other attributes, or to perform write operations, will be denied.

This level of granularity is achieved through IAM condition keys specific to DynamoDB, such as dynamodb:Attributes and dynamodb:LeadingKeys. dynamodb:Attributes lets you filter operations based on the attributes being accessed in a request. dynamodb:LeadingKeys filters based on the partition key of the item being accessed. You can also use dynamodb:SelectAttributes for Query and Scan operations to restrict which attributes are returned.

When you use dynamodb:Attributes in a Condition block with ForAllValues:StringEquals, you are essentially creating an allowlist for attribute access. If the request attempts to access any attribute not in that list, the condition will evaluate to false, and the IAM policy will deny the action. Conversely, using dynamodb:Attributes with ForAllValues:StringNotEquals creates a denylist.

The true power of these condition keys is often overlooked because many users stop at table-level permissions. However, the ability to restrict access down to individual attributes or even specific items based on their partition key allows for fine-grained security models that are essential for sensitive data. For instance, you could ensure that a user can only update their own profile by using dynamodb:LeadingKeys to match their userId against the item’s userId.

Understanding how ForAllValues:StringEquals and ForAllValues:StringNotEquals interact with dynamodb:Attributes is key to mastering DynamoDB security. Most people grasp the "allow" or "deny" part of the Effect, but the subtle difference between specifying attributes to allow versus attributes to not allow can lead to either overly permissive or overly restrictive policies if not carefully considered.

The next step in securing your DynamoDB access is to explore how to use dynamodb:SelectAttributes to control the projection of attributes in Query and Scan operations, further refining read access.

Want structured learning?

Take the full Dynamodb course →