← Back to DevBytes

DynamoDB Security: IAM Policies and Network Security

Understanding DynamoDB Security

Amazon DynamoDB is a fully managed NoSQL database service that provides fast, predictable performance with seamless scalability. Security in DynamoDB operates on two critical layers: authentication and authorization (who can access what, enforced via IAM policies) and network security (how traffic reaches your tables, enforced via network controls like VPC endpoints). Together, these layers form a defense-in-depth strategy that protects your data against unauthorized access, data exfiltration, and network-based threats.

This tutorial walks you through the complete security model for DynamoDB. You will learn how to craft IAM policies that enforce least-privilege access at the table, item, and attribute level, and how to lock down network paths so that DynamoDB traffic never traverses the public internet. Every concept is reinforced with practical, ready-to-use code examples.

IAM Policies for DynamoDB

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

What Are IAM Policies?

IAM (Identity and Access Management) policies are JSON documents that define permissions for actions on AWS resources. When attached to users, groups, or roles, they grant or deny the ability to perform DynamoDB API operations such as GetItem, PutItem, Query, Scan, UpdateItem, DeleteItem, and table management operations like CreateTable or DescribeTable. Without an explicit allow policy, every DynamoDB action is implicitly denied by default.

Why IAM Policies Matter for DynamoDB

DynamoDB does not have its own built-in authentication system — it relies entirely on IAM. This means every call to DynamoDB, whether from the AWS CLI, SDKs, Lambda functions, or the console, must be signed with credentials that have been granted appropriate IAM permissions. A misconfigured policy can expose entire tables to unintended read/write access, leading to data breaches, accidental data corruption, or costly resource manipulation. Proper IAM policies ensure:

  • Applications can only access the specific tables they need
  • Sensitive attributes (like personally identifiable information) remain hidden from unauthorized roles
  • Read-only consumers cannot modify data
  • Developers in production accounts are restricted to read-only operations on critical tables

Policy Structure and Syntax

A DynamoDB IAM policy follows the standard IAM policy structure with five key components: Effect, Action, Resource, optional Condition, and optional Principal. Here is the anatomy of a DynamoDB permission statement:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:Query"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Orders",
      "Condition": {
        "ForAllValues:StringEquals": {
          "dynamodb:Attributes": ["OrderID", "CustomerName", "OrderStatus"]
        }
      }
    }
  ]
}

Key elements explained:

  • EffectAllow or Deny. Explicit deny always overrides any allow.
  • Action — DynamoDB API actions prefixed with dynamodb:. You can use wildcards like dynamodb:Get* but it's discouraged for production.
  • Resource — The ARN of the table, index, or stream. For a specific table: arn:aws:dynamodb:region:account-id:table/TableName. For all tables: use a wildcard *.
  • Condition — Optional filters that restrict access based on attributes, time, source IP, VPC endpoint, etc.

Common IAM Policy Patterns for DynamoDB

Pattern 1: Read-Only Access to a Specific Table

Use this pattern for reporting services, dashboards, or data analysts who should never modify data.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:BatchGetItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:DescribeTable"
      ],
      "Resource": "arn:aws:dynamodb:eu-west-1:111122223333:table/SalesData"
    }
  ]
}

Pattern 2: Read and Write Access with Attribute-Level Restrictions

This pattern allows full CRUD on the table but prevents reading or writing to specific sensitive attributes (e.g., salary, social security number).

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem",
        "dynamodb:Query",
        "dynamodb:Scan"
      ],
      "Resource": "arn:aws:dynamodb:us-west-2:555566667777:table/EmployeeData"
    },
    {
      "Effect": "Deny",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:us-west-2:555566667777:table/EmployeeData",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "dynamodb:Attributes": ["Salary", "SSN"]
        }
      }
    }
  ]
}

Note: The explicit Deny statement with the condition on attributes Salary and SSN ensures that even if the first statement allows access, any operation targeting those attributes is denied. The order of statements doesn't matter — explicit deny always wins.

Pattern 3: Role-Based Access with Leading Key Condition

When using session-based authentication or partition-key-level isolation, you can enforce that users can only access items where the partition key matches their identity. This is powerful for multi-tenant applications.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem",
        "dynamodb:Query"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/TenantData",
      "Condition": {
        "ForAllValues:StringEquals": {
          "dynamodb:LeadingKeys": ["${www.amazon.com:user_id}"]
        }
      }
    }
  ]
}

The dynamodb:LeadingKeys condition restricts operations to items whose partition key matches the session variable www.amazon.com:user_id. This is often used with Amazon Cognito or web identity federation.

Fine-Grained Access Control with DynamoDB Conditions

DynamoDB supports several condition keys that go beyond basic resource-level permissions:

  • dynamodb:LeadingKeys — Restricts access based on the partition key value
  • dynamodb:Attributes — Restricts which attributes can be accessed or modified
  • dynamodb:ReturnValues — Controls whether ReturnValues parameter is allowed (prevents data leakage via update responses)
  • dynamodb:Select — Controls projection expressions in queries and scans
  • dynamodb:EnclosingOperation — Limits access to specific enclosing API operations (useful with transactions)

Here is a comprehensive policy that combines multiple condition keys for a highly restricted Lambda execution role:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:Query"
      ],
      "Resource": "arn:aws:dynamodb:ap-southeast-1:999988887777:table/CustomerOrders"
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:PutItem",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:ap-southeast-1:999988887777:table/CustomerOrders",
      "Condition": {
        "ForAllValues:StringEqualsIfExists": {
          "dynamodb:Attributes": ["OrderStatus", "ShippingAddress", "PaymentConfirmation"]
        },
        "StringEqualsIfExists": {
          "dynamodb:ReturnValues": "NONE"
        }
      }
    },
    {
      "Effect": "Deny",
      "Action": [
        "dynamodb:DeleteItem",
        "dynamodb:DeleteTable",
        "dynamodb:CreateTable"
      ],
      "Resource": "arn:aws:dynamodb:ap-southeast-1:999988887777:table/CustomerOrders"
    }
  ]
}

This policy allows GetItem and Query unconditionally on the CustomerOrders table. It allows PutItem and UpdateItem only when the affected attributes are limited to OrderStatus, ShippingAddress, and PaymentConfirmation, and it ensures ReturnValues is set to NONE to prevent leaking old item data. Finally, destructive actions like DeleteItem and table management operations are explicitly denied.

Network Security for DynamoDB

Why Network Security Matters

By default, DynamoDB is accessible over the public internet via HTTPS. While IAM authentication ensures only signed requests succeed, the traffic still traverses public networks, which exposes it to potential interception, metadata leakage, and unauthorized access attempts from outside your VPC. Network security controls allow you to:

  • Force all DynamoDB traffic through your private VPC network
  • Apply network ACLs and security group rules to control egress and ingress
  • Prevent data exfiltration via public endpoints
  • Meet compliance requirements (PCI DSS, HIPAA) that mandate private connectivity

VPC Endpoints for DynamoDB

A VPC endpoint is a network construct that creates a private, direct connection between your VPC and DynamoDB without requiring an internet gateway, NAT device, VPN connection, or AWS Direct Connect. DynamoDB supports two types of VPC endpoints:

  • Gateway Endpoint — A free, highly available gateway that routes traffic from your VPC to DynamoDB (and S3) via a private path. This is the recommended approach for DynamoDB.
  • Interface Endpoint (AWS PrivateLink) — An elastic network interface (ENI) with a private IP address in your subnet. Costs apply per endpoint and per GB processed, but it provides additional features like private DNS and endpoint policies.

Creating a Gateway Endpoint for DynamoDB (AWS CLI)

Gateway endpoints are simple to set up and do not incur additional charges. Here is how to create one using the AWS CLI:

aws ec2 create-vpc-endpoint \
    --vpc-id vpc-0abcd1234efgh5678 \
    --service-name com.amazonaws.us-east-1.dynamodb \
    --route-table-ids rtb-0abcd1234efgh5678 rtb-1abcd1234efgh5678 \
    --policy-document file://dynamodb-endpoint-policy.json

The --service-name follows the format com.amazonaws.region.dynamodb. Replace us-east-1 with your region. The --route-table-ids specify which route tables will have a route added that directs DynamoDB traffic through the endpoint instead of the internet gateway. The optional --policy-document lets you attach an endpoint policy that further restricts what can be done through this endpoint.

Example endpoint policy document (dynamodb-endpoint-policy.json):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:Query",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/AppTable"
    },
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "dynamodb:DeleteTable",
        "dynamodb:CreateTable"
      ],
      "Resource": "*"
    }
  ]
}

This endpoint policy ensures that even if an IAM policy grants broader permissions, any traffic through this VPC endpoint is restricted to the specified actions and table. The explicit deny on table management operations provides an additional safety net.

Creating a VPC Endpoint with CloudFormation

For infrastructure-as-code deployments, here is a complete CloudFormation snippet that creates a VPC gateway endpoint for DynamoDB with an associated endpoint policy:

Resources:
  DynamoDBVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.dynamodb"
      VpcId: !Ref AppVPC
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal: "*"
            Action:
              - "dynamodb:GetItem"
              - "dynamodb:Query"
              - "dynamodb:PutItem"
              - "dynamodb:UpdateItem"
              - "dynamodb:BatchGetItem"
              - "dynamodb:BatchWriteItem"
            Resource:
              - !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/Orders"
              - !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/Inventory"
          - Effect: Deny
            Principal: "*"
            Action:
              - "dynamodb:DeleteTable"
              - "dynamodb:Scan"
            Resource: "*"
      RouteTableIds:
        - !Ref PrivateRouteTable1
        - !Ref PrivateRouteTable2
      VpcEndpointType: Gateway

Interface Endpoints with AWS PrivateLink

If you need to connect to DynamoDB from on-premises networks via AWS Direct Connect or VPN, or if you require private DNS resolution, use an interface endpoint (PrivateLink). Interface endpoints appear as ENIs with private IPs in your subnets and support security groups for granular network filtering.

aws ec2 create-vpc-endpoint \
    --vpc-id vpc-0abcd1234efgh5678 \
    --service-name com.amazonaws.vpce.us-east-1.vpce-svc-0abcd1234efgh5678 \
    --vpc-endpoint-type Interface \
    --subnet-ids subnet-0abcd1234 subnet-1abcd1234 \
    --security-group-ids sg-0abcd1234efgh5678 \
    --private-dns-enabled

The --private-dns-enabled flag ensures that DNS resolution for dynamodb.us-east-1.amazonaws.com resolves to the private IPs of the endpoint within the VPC, making the transition seamless for applications.

Network ACLs and Security Groups for DynamoDB Endpoints

With gateway endpoints, you don't directly attach security groups because the gateway operates at the route table level. However, you can control which instances can use the endpoint by managing route table associations and using instance-level security group egress rules. For interface endpoints, you attach security groups directly:

aws ec2 authorize-security-group-ingress \
    --group-id sg-0abcd1234efgh5678 \
    --protocol tcp \
    --port 443 \
    --source-group sg-0xyz9876zyxw3210

This command allows HTTPS traffic (port 443) from a specific source security group (e.g., your application tier) to reach the interface endpoint's ENI. You should also configure the source security group's egress rules to allow outbound traffic to the endpoint's security group on port 443.

IP-Based Access Control with IAM Condition Keys

You can combine network security with IAM policies by using the aws:SourceIp condition key. This denies DynamoDB API calls unless they originate from an approved IP range, adding another layer of defense even if credentials are compromised.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "dynamodb:*",
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/HighlySensitiveData",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "10.0.0.0/8",
            "172.16.0.0/12"
          ]
        }
      }
    }
  ]
}

This policy denies all DynamoDB actions on the HighlySensitiveData table if the source IP is not within the private network ranges. Combine this with VPC endpoints to ensure traffic both originates from and travels through private network paths.

How to Implement DynamoDB Security End-to-End

Step-by-Step: Creating and Attaching IAM Policies

Follow these steps to secure a DynamoDB table used by a microservice running on AWS Lambda:

Step 1: Identify the exact DynamoDB actions your application needs. Audit your codebase for all DynamoDB API calls — typically GetItem, PutItem, UpdateItem, Query. Avoid granting Scan unless absolutely necessary due to its high cost and potential for full table exposure.

Step 2: Write the IAM policy as a JSON file. Create a file named lambda-dynamodb-policy.json:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:Query",
        "dynamodb:BatchGetItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/UserProfiles",
        "arn:aws:dynamodb:us-east-1:123456789012:table/UserProfiles/index/*"
      ]
    }
  ]
}

Note the inclusion of index ARNs — queries against secondary indexes require permissions on the index resource as well as the base table.

Step 3: Create the IAM policy in AWS.

aws iam create-policy \
    --policy-name DynamoDB-UserProfiles-Access \
    --policy-document file://lambda-dynamodb-policy.json

Step 4: Attach the policy to the Lambda execution role.

aws iam attach-role-policy \
    --role-name MyLambdaExecutionRole \
    --policy-arn arn:aws:iam::123456789012:policy/DynamoDB-UserProfiles-Access

Step 5: Test the permissions. Use the AWS CLI with the role's credentials (or simulate with --profile) to verify allowed and denied actions:

# This should succeed
aws dynamodb get-item \
    --table-name UserProfiles \
    --key '{"UserID": {"S": "user123"}}' \
    --projection-expression "UserID, Email, FullName"

# This should fail with AccessDeniedException
aws dynamodb delete-item \
    --table-name UserProfiles \
    --key '{"UserID": {"S": "user123"}}'

Step-by-Step: Setting Up VPC Endpoints for DynamoDB

Step 1: Verify your VPC configuration. Ensure your application subnets have a route table that currently routes 0.0.0.0/0 through a NAT gateway or internet gateway. You will add a more specific route for DynamoDB.

Step 2: Create the gateway endpoint.

aws ec2 create-vpc-endpoint \
    --vpc-id vpc-0a1b2c3d4e5f6g7h8 \
    --service-name com.amazonaws.us-east-1.dynamodb \
    --route-table-ids rtb-0private01 rtb-0private02 \
    --policy-document file://endpoint-policy.json

Step 3: Verify the route was added. After creation, check the route tables:

aws ec2 describe-route-tables \
    --route-table-ids rtb-0private01 \
    --query 'RouteTables[*].Routes[?DestinationPrefixListId!=null]'

You should see a route with a DestinationPrefixListId pointing to the DynamoDB prefix list (e.g., pl-0abcd1234efgh5678) and a VpcEndpointId target.

Step 4: Update instance security groups. For gateway endpoints, instances need egress rules allowing HTTPS to the DynamoDB service. Add an egress rule to your application security group:

aws ec2 authorize-security-group-egress \
    --group-id sg-0appsecuritygroup \
    --protocol tcp \
    --port 443 \
    --cidr 0.0.0.0/0

Although traffic flows through the private gateway, the destination CIDR for DynamoDB's public service still needs to be allowed. Alternatively, use the prefix list ID as the destination:

aws ec2 authorize-security-group-egress \
    --group-id sg-0appsecuritygroup \
    --protocol tcp \
    --port 443 \
    --prefix-list-id pl-0abcd1234efgh5678

Step 5: Test private connectivity. From an instance in the VPC, run a DynamoDB CLI command and capture network traces to confirm the traffic does not traverse the internet gateway:

aws dynamodb list-tables --region us-east-1 --output json

If the command succeeds and network monitoring shows traffic routed through the VPC endpoint, your network security configuration is working correctly.

Best Practices for DynamoDB Security

1. Apply Least-Privilege IAM Policies Rigorously

Start with an empty policy and add only the exact actions required. Use the AWS IAM Policy Simulator to test policies before deployment. Never use dynamodb:* in production policies — explicitly list each action. For Lambda functions, create one execution role per function rather than sharing a monolithic role across multiple functions.

2. Use Attribute-Level and Key-Level Conditions

Go beyond table-level access control. Restrict access to specific attributes containing sensitive data. For multi-tenant tables, use dynamodb:LeadingKeys to enforce partition key isolation so that tenants can only access their own data, even within the same table.

3. Combine IAM Policies with VPC Endpoint Policies

Create a dual-permission boundary: IAM policies control what actions a principal can perform, while VPC endpoint policies control what actions are allowed through a specific network path. Even if an IAM policy is overly permissive, the endpoint policy can block dangerous operations at the network level.

4. Enable CloudTrail Logging for DynamoDB API Calls

Turn on AWS CloudTrail in all regions and configure it to log DynamoDB data-plane events (GetItem, PutItem, etc.) as well as control-plane events. This provides an audit trail for security investigations. Use CloudTrail Insights to detect unusual patterns like sudden spikes in Scan operations.

5. Monitor and Alert on Security Anomalies

Set up Amazon CloudWatch Alarms or AWS Config rules to detect:

  • Changes to DynamoDB table policies or IAM policies
  • Deletion or modification of VPC endpoints
  • Calls from unexpected IP addresses (via CloudTrail + Lambda)
  • Excessive Scan or misused permissions

6. Use VPC Endpoints Even for Public-Facing Applications

If your application runs within a VPC (EC2, ECS, Lambda in VPC mode), always route DynamoDB traffic through a VPC gateway endpoint. This is free, improves latency slightly by keeping traffic within the AWS backbone, and eliminates exposure to the public internet. Only applications running outside AWS (e.g., on-premises servers or developer laptops) should use the public endpoint, and even then, consider PrivateLink with Direct Connect.

7. Regularly Review and Rotate Credentials

For applications using IAM roles (recommended), credential rotation is automatic. For applications still using long-lived IAM user access keys, rotate them every 90 days and avoid embedding them in code — use environment variables or AWS Secrets Manager. Never commit IAM credentials to source control repositories.

8. Implement Deny Statements for Destructive Actions

Always include explicit Deny statements for dynamodb:DeleteTable, dynamodb:DeleteBackup, and dynamodb:DeleteItem on production tables for roles that shouldn't need these actions. This protects against accidental deletions even if an allow statement is inadvertently added later.

Conclusion

Securing DynamoDB requires a layered approach that combines precise IAM policies with robust network controls. IAM policies define who can access which tables, items, and attributes, while VPC endpoints, endpoint policies, and network ACLs ensure that access occurs only through trusted, private network paths. By implementing the patterns and practices outlined in this tutorial — least-privilege IAM roles, fine-grained attribute and key conditions, VPC gateway endpoints, explicit deny statements, and continuous monitoring — you create a security posture that protects your DynamoDB data against both internal misconfigurations and external threats. Start with a thorough audit of your current DynamoDB permissions, migrate public endpoint traffic to VPC endpoints, and enforce attribute-level restrictions where sensitive data is stored. Security is not a one-time setup; it is an ongoing practice of review, refinement, and defense-in-depth.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles