DynamoDB Security Best Practices: IAM, KMS, PITR & VPC Endpoints

DynamoDB is encrypted at rest, only reachable via HTTPS, and requires valid AWS credentials for every request. AWS handles the managed database layer. What you still control (and what matters in production) is who can access which tables, how tightly permissions are scoped, how data is recovered, and how access is monitored.

This page covers the controls that matter most: least-privilege IAM, fine-grained access conditions, KMS encryption options, VPC endpoints, PITR, Streams, and monitoring. Most security problems in DynamoDB come not from platform weaknesses but from over-broad IAM roles and controls that were never enabled.

DynamoDB security in plain English

Simple explanation

Think of DynamoDB like a secure document vault that AWS maintains for you. The building is locked, alarmed, and encrypted. That is AWS’s job. What you control is who has a key card, which rooms they can enter, whether you keep a visitor log, and how you restore the vault contents if something goes wrong. AWS secures the managed platform. You control who can access data, how tightly access is restricted, how it is monitored, and how it is recovered.

The practical goals when securing a DynamoDB table are:

  1. Restrict access to the minimum actions and tables each application needs
  2. Choose the right encryption key model for your compliance requirements
  3. Enable recovery mechanisms before you need them
  4. Ensure you can detect unexpected access after the fact

What DynamoDB handles vs what you configure

Understanding the shared responsibility model for DynamoDB tells you what you can rely on and what you must configure yourself.

AWS handles by defaultYou still need to configure
Encryption at rest using AWS-owned keysKey model: switch to KMS if you need audit trails or revocation
HTTPS for all API callsIAM policies scoped to specific tables and actions
No open TCP port to manageFine-grained conditions (LeadingKeys, attribute restrictions)
Physical security of hardware and data centresVPC endpoint to keep traffic off the public internet
IAM authentication enforcement on every API callPoint-in-time recovery (off by default, per table)
Multi-AZ durability and replicationCloudTrail and monitoring configuration
Service-level patching and availabilityDynamoDB Streams for audit or event-driven workflows
Where to start

Focus on the right-hand column. The left column is AWS’s responsibility and requires nothing from you. Every item on the right is a gap that can cause a real incident if skipped.

How access control works in DynamoDB

DynamoDB has no built-in user system. Every API call must be signed with AWS credentials, and IAM decides whether the call is permitted. There are two ways to apply access control to a DynamoDB table.

Identity-based policies

These are policies attached to IAM users, roles, or groups. They define what that identity can do across any DynamoDB table it interacts with. This is the most common pattern. A Lambda function or EC2 instance assumes an IAM role that grants exactly the actions it needs on exactly the tables it needs.

Common DynamoDB actions:

ActionWhat it allows
dynamodb:GetItemRead a single item by primary key
dynamodb:PutItemCreate or replace an item
dynamodb:UpdateItemModify attributes of an existing item
dynamodb:DeleteItemDelete an item by primary key
dynamodb:QueryQuery items in a table or index
dynamodb:ScanScan the entire table
dynamodb:BatchGetItemRetrieve multiple items in one request
dynamodb:BatchWriteItemWrite or delete multiple items in one request

A read-only application role scoped to a specific table and its indexes:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:Query",
        "dynamodb:BatchGetItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:eu-west-2:123456789012:table/Orders",
        "arn:aws:dynamodb:eu-west-2:123456789012:table/Orders/index/*"
      ]
    }
  ]
}

The resource must include both the table ARN and index/* if the application queries Global Secondary Indexes. A policy scoped to the table ARN alone will return AccessDenied on GSI queries. See Fixing IAM AccessDenied Errors for how to diagnose and fix this.

Tip

Always use IAM roles with temporary credentials rather than long-lived access keys for application authentication. Role credentials expire automatically, limit blast radius if leaked, and leave a clear trail in CloudTrail. Long-lived access keys sit in environment variables or config files for months without anyone noticing. See Why Long-Lived Access Keys Are Dangerous.

Resource-based policies

DynamoDB supports resource-based policies attached directly to a table. These let you grant access to principals from other AWS accounts without requiring changes on the caller’s side. They are useful for cross-account data sharing but less common than identity-based policies for single-account applications. See the comparison table further down the page.

Fine-grained access with LeadingKeys

dynamodb:LeadingKeys is a condition that restricts access to items where the partition key matches a specific value. Combined with the aws:userid policy variable, you can write a single policy that enforces per-user data isolation automatically.

In practice: imagine a UserData table where each item’s partition key is the user’s ID. You want each user to read and write only their own items. One policy handles this for every user:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem",
        "dynamodb:Query"
      ],
      "Resource": "arn:aws:dynamodb:eu-west-2:123456789012:table/UserData",
      "Condition": {
        "ForAllValues:StringEquals": {
          "dynamodb:LeadingKeys": ["${aws:userid}"]
        }
      }
    }
  ]
}

${aws:userid} resolves to the caller’s IAM user or role ID at evaluation time. Each principal can only touch items matching their own identity. No application-level filtering required.

See IAM Policy Conditions for a full reference on condition keys and operators including ForAllValues:StringEquals and other useful DynamoDB condition keys.

Note

For IAM roles assumed by Cognito-authenticated users, aws:userid includes the role session name, which you can configure to match your application’s user identifier. This pattern is standard in mobile and web applications where each end user receives temporary credentials via Cognito Identity Pools.

Encryption at rest

All DynamoDB data is encrypted at rest. You choose which key model to use. See Encryption in AWS for a broader overview of how encryption works across AWS services.

Key typeWho controls itAudit visibilityCostBest forMain risk
AWS-owned key (default)AWS manages entirelyNone; no key usage logsFreeMost workloads without compliance audit requirementsNo audit trail, cannot revoke access via key
AWS-managed KMS keyAWS manages; key lives in your accountCloudTrail logs every key usage eventKMS API call chargesWhen you need a key usage audit trailCannot customise the key policy directly
Customer-managed KMS keyYou create, configure, and rotate itFull CloudTrail audit trail$1/key/month + API callsStrict compliance, cross-account access, instant revocationDisabling the key makes the table immediately inaccessible
Risk: customer-managed keys

If you disable a customer-managed KMS key, DynamoDB cannot decrypt data and the table goes offline immediately. Deleting the key (after the mandatory 7 to 30 day waiting period) makes the table permanently unreadable. Before using customer-managed keys in production, make sure your team understands this and has procedures for key management. Do not delete a key without verifying every resource that depends on it. See Customer-Managed Keys.

To create a table with a customer-managed KMS key:

# Create a table with customer-managed KMS encryption
aws dynamodb create-table \
  --table-name SensitiveData \
  --attribute-definitions AttributeName=userId,AttributeType=S \
  --key-schema AttributeName=userId,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST \
  --sse-specification '{
    "Enabled": true,
    "SSEType": "KMS",
    "KMSMasterKeyId": "arn:aws:kms:eu-west-2:123456789012:key/your-key-id"
  }'

For key management details including rotation schedules, key policies, and how to share keys across accounts, see AWS KMS Overview and Customer-Managed Keys.

Network access and private connectivity

DynamoDB is API-based. There is no TCP port to open and no security group to configure on the database itself. All traffic uses HTTPS on port 443. By default, traffic from your VPC resources to DynamoDB routes through the public internet (always HTTPS-encrypted, but traversing public network paths).

A VPC endpoint for DynamoDB keeps all traffic inside the AWS network. It never crosses the public internet and does not require a NAT gateway or internet gateway to reach DynamoDB.

Gateway endpointInterface endpoint (PrivateLink)
CostFreeHourly charge per AZ + data processing fees
How traffic routesVia route table entries in your VPCVia an elastic network interface (ENI) in your subnet
DNS resolutionUses public DynamoDB DNS names, routed internallyResolves to private IP addresses in your VPC
Works from on-premises (Direct Connect / VPN)NoYes
Security group on the endpointNoYes; attach a security group to the ENI
Supports endpoint policiesYesYes
Best forMost VPC-based production workloadsHybrid or on-premises environments, strict isolation
# Create a Gateway VPC endpoint for DynamoDB
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0abc12345 \
  --service-name com.amazonaws.eu-west-2.dynamodb \
  --route-table-ids rtb-0abc12345

After creating the endpoint, add an endpoint policy to restrict which DynamoDB tables the endpoint can reach. Use aws:sourceVpce as a condition key in IAM policies to ensure DynamoDB access only comes through the endpoint.

See VPC Endpoint Policies for how to write these restrictions and AWS PrivateLink Overview for when an interface endpoint is the right choice.

Common misunderstanding

A gateway endpoint does not isolate your VPC from the public internet. Resources in your VPC can still reach DynamoDB via an internet or NAT gateway if those routes exist. To enforce endpoint-only access, add an explicit Deny condition using aws:sourceVpce. Any request that does not arrive through the endpoint is then denied, regardless of other routing.

Backup, recovery, and data protection

Point-in-time recovery

PITR must be explicitly enabled per table. It is off by default. Once on, DynamoDB captures a continuous backup stream that lets you restore to any second within the last 35 days.

When PITR saves you

A bug silently corrupts 10,000 items over a weekend. An operator runs a batch delete against the wrong table. An automated job writes bad data for two hours before anyone notices. Without PITR, each of these is a multi-day recovery involving manual reconstruction. With PITR, you restore to the second before the problem started.

# Enable PITR on a table
aws dynamodb update-continuous-backups \
  --table-name Orders \
  --point-in-time-recovery-specification PointInTimeRecoveryEnabled=true

# Restore to a specific point in time (creates a new table)
aws dynamodb restore-table-to-point-in-time \
  --source-table-name Orders \
  --target-table-name Orders-restored-20260315 \
  --restore-date-time 2026-03-15T14:00:00Z

The restore creates a new table. The original is unaffected and continues serving traffic. You verify the restored data, then cut the application over when ready. This is the same pattern as RDS point-in-time recovery.

On-demand backups

On-demand backups are manual full-table snapshots retained until you delete them. They complement PITR for cases where you need to keep a snapshot beyond the 35-day PITR window, want a pre-deployment baseline before a risky migration, or need to archive a historical state of a table.

Tip

Enable PITR on every production table before traffic arrives. It cannot recover data from before it was enabled. If you wait until an incident happens, it is already too late.

Monitoring, logging, and compliance

Preventative controls stop bad access. Detective controls tell you when something unexpected happened. Both matter in production. An over-privileged role that was never used for malicious activity today may be exploited tomorrow, and without logging you will not know it happened.

AWS CloudTrail

CloudTrail records every DynamoDB API call: who made it, from where, with what parameters, and whether it succeeded. This is your primary audit trail.

  • Management events are logged by default and free. These cover table create and delete, backup and restore operations, PITR changes, capacity updates, and Streams configuration.
  • Data events (individual item reads and writes: GetItem, PutItem, etc.) are not logged by default and have an additional cost. Enable them for sensitive tables where you need to know which items were accessed and by whom.
Tip

Not sure whether to enable data events? Ask: if someone read every item in this table, would you need to know about it? If yes, enable data events. If the table contains non-sensitive operational data, management events alone are usually sufficient.

See AWS CloudTrail Overview and CloudTrail Log Types for configuration details and event format.

KMS key usage visibility

If you use AWS-managed or customer-managed KMS keys, every Decrypt call DynamoDB makes is logged in CloudTrail under kms.amazonaws.com events. This provides indirect visibility into data access; each item read corresponds to a KMS Decrypt event. This is one of the primary reasons to choose KMS over AWS-owned keys when a compliance audit trail is required.

AWS Security Hub

AWS Security Hub includes DynamoDB checks that assess whether PITR is enabled, whether tables are encrypted with customer-managed keys, and whether tables have at least one backup configured. These automated findings catch controls that were skipped during provisioning or silently disabled over time.

What to watch for

Useful signals to monitor in a production DynamoDB environment:

  • Unexpected spikes in ConsumedWriteCapacityUnits from unfamiliar principals
  • CloudTrail events from unexpected IAM roles, regions, or IP addresses
  • KMS kms:Decrypt events from roles that should not be accessing a table
  • ThrottledRequests that suggest unintended table scans
  • PITR disabled events on production tables

For broader detection patterns and alert configuration, see Detecting Suspicious Activity in AWS.

DynamoDB Streams for audit and event-driven workflows

DynamoDB Streams capture every item-level change as an ordered sequence of records. Each record includes the item’s keys, the change type (INSERT, MODIFY, REMOVE), and optionally the item’s state before the change, after the change, or both.

Audit and compliance use cases:

  • Retain a change history of every item modification for compliance records
  • Build an immutable audit log by streaming changes to S3 or a data warehouse
  • Detect and alert on unexpected item deletions by routing Stream records through Lambda

Application and event-driven use cases:

  • Trigger a Lambda function when an order is placed to send a confirmation notification
  • Keep a search index (OpenSearch, Elasticsearch) synchronised with table changes in near-real-time
  • Invalidate downstream caches when underlying data is updated
  • Fan out changes to multiple consumers without modifying the write path
# Enable Streams with both old and new item images
aws dynamodb update-table \
  --table-name Orders \
  --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES

# Get the Stream ARN to configure a Lambda trigger
aws dynamodb describe-table \
  --table-name Orders \
  --query 'Table.LatestStreamArn' \
  --output text
Streams vs CloudTrail

Streams are useful for building audit trails and event-driven workflows, but they are not a monitoring replacement. Stream records are retained for 24 hours only and require a consumer (Lambda or Kinesis) to persist them. For security investigations and compliance auditing, CloudTrail is the primary source of truth. Use Streams for application event logic; use CloudTrail for access control and API activity.

Minimum production hardening checklist

Apply these before a DynamoDB table receives production traffic:

  1. Use least-privilege IAM roles. Grant only the actions each application actually needs. See Least-Privilege Access in AWS.
  2. Scope permissions to specific tables and indexes. Never use Resource: "*". Always include table/TableName/index/* if GSIs are queried.
  3. Use dynamodb:LeadingKeys conditions when multiple users share a table and should only see their own items.
  4. Choose the right KMS key model. AWS-owned keys for most workloads. KMS when audit trails, key revocation, or compliance requirements apply.
  5. Enable PITR on every production table. It is off by default and cannot recover data from before it was enabled.
  6. Add a gateway VPC endpoint (free) to keep DynamoDB traffic within the AWS network. Attach an endpoint policy.
  7. Enable CloudTrail monitoring. Management events are on by default. Enable data events for sensitive tables that require item-level access auditing.
  8. Test the restore path. Run a PITR restore to a non-production table at least once before you need it under pressure.

When to use which controls

Not every table needs every control. Here is a practical decision guide.

When AWS-owned keys are enough: Internal application data with no external compliance requirement, where a key usage audit trail is not needed and key revocation is not part of your security posture. This is the right default for the majority of workloads.

When customer-managed KMS keys are justified: You need to demonstrate an audit trail of data access (HIPAA, PCI-DSS, ISO 27001), your policy requires customer-controlled key material, you need to revoke table access instantly by disabling the key, or the key must be shared across AWS accounts. Understand the consequence: disabling the key locks the table immediately.

When a VPC endpoint is worth adding: Any production workload running in a VPC where you want to keep DynamoDB traffic within the AWS network. Gateway endpoints are free and take minutes to set up. There is almost no reason to skip this for production tables.

When fine-grained IAM conditions are worth the complexity: A single DynamoDB table stores data belonging to multiple users or tenants and application-level row filtering is not sufficient for your threat model. dynamodb:LeadingKeys gives you database-level enforcement without separate tables per user.

When Streams should be enabled: Your application needs to react to data changes in near-real-time, you need an immutable change history, or you are replicating data to a downstream system. Do not enable Streams solely for security monitoring. Use CloudTrail for that.

Comparisons

Identity-based policies vs resource-based policies

Identity-based policyResource-based policy
Attached toIAM user, role, or groupThe DynamoDB table itself
Cross-account accessRequires trust relationship and policies on both sidesCan grant access directly to principals in other accounts
Most common useApplication roles, Lambda, EC2, ECS task rolesCross-account data sharing patterns
AuditabilityHigh; policies visible in IAMHigh; policy visible on the table resource
Recommended defaultYes, for most single-account use casesUse when cross-account access is required

Gateway endpoint vs interface endpoint for DynamoDB

Gateway endpointInterface endpoint (PrivateLink)
CostFree~$0.01/hour per AZ + data processing charges
Works from on-premisesNoYes, via Direct Connect or Site-to-Site VPN
DNSRequires route table entry; uses public DNS namesPrivate DNS resolves to ENI private IP addresses
Security group on the endpointNoYes; apply a security group to the ENI
Endpoint policy supportYesYes
Best forMost VPC-based workloads; use this by defaultHybrid networks and strict isolation requirements

Common mistakes

  1. Not enabling PITR on production tables. PITR is off by default and must be explicitly enabled per table. It cannot recover data from before it was turned on. A bug that silently corrupts data over two weeks is unrecoverable without it. Enable PITR immediately after table creation, before production traffic arrives.
  2. Granting access to all tables with a single over-broad IAM role. An application role with dynamodb:* on Resource: "*" means a leaked credential exposes every table in the account. Scope each role to specific tables and specific actions. See Least-Privilege Access in AWS.
  3. Forgetting to include index ARNs in IAM policy resources. A policy allowing dynamodb:Query on a table ARN silently fails when the application queries a GSI. Always include table/TableName/index/* alongside the table ARN. See Fixing IAM AccessDenied Errors for how to diagnose this quickly.
  4. Not auditing DynamoDB access. The default configuration logs table management events in CloudTrail, but not individual item reads and writes. For sensitive tables, enable CloudTrail data events. Assuming you will only see problems you caused (not problems from over-privileged access) is a posture that fails silently.
  5. Assuming a VPC endpoint means full network isolation. A gateway endpoint routes DynamoDB traffic through the AWS network, but it does not prevent resources in your VPC from reaching DynamoDB via an internet gateway or NAT gateway if those routes exist. To enforce endpoint-only access, add an explicit Deny using aws:sourceVpce.
  6. Using customer-managed KMS keys without understanding the blast radius. Disabling the key makes the table immediately inaccessible for both reads and writes. Deleting it (with the mandatory 7 to 30 day waiting period) makes it permanently unreadable. Have strict procedures in place: never delete a key without verifying all dependent resources, and test key disabling in a non-production environment first. See Customer-Managed Keys.

Frequently asked questions

Is DynamoDB encrypted at rest by default?

Yes. DynamoDB encrypts all data at rest using AWS-owned keys automatically, at no extra cost. You do not need to configure anything. If you need an audit trail of key usage or the ability to revoke access by disabling a key, switch to AWS-managed or customer-managed KMS keys.

Do I need a VPC endpoint for DynamoDB?

DynamoDB is API-based and all traffic is HTTPS-encrypted whether or not you use a VPC endpoint. A gateway endpoint keeps traffic within the AWS network and avoids public internet routing. It is free, low-effort, and recommended for any production workload. Add an endpoint policy to restrict which tables can be accessed from within the VPC.

What is the difference between PITR and on-demand backups in DynamoDB?

PITR lets you restore a table to any second in the past 35 days; it is continuous and automatic once enabled. On-demand backups are manual snapshots you take at a specific point in time and retain until you delete them. PITR is best for accidental corruption or deletion recovery. On-demand backups are better for long-term archiving or pre-deployment snapshots.

Can IAM restrict users to only their own DynamoDB items?

Yes. The dynamodb:LeadingKeys condition restricts access to items where the partition key matches a specified value. Combined with the aws:userid policy variable, a single policy lets each caller access only items that belong to them. This is commonly used with Amazon Cognito to enforce per-user data isolation in mobile and web applications.

What happens if I disable a customer-managed KMS key used by DynamoDB?

Disabling the key makes the DynamoDB table inaccessible immediately. Reads and writes fail until the key is re-enabled. The table data is not deleted. Deleting the key permanently (with the mandatory 7 to 30 day waiting period) would make the table permanently unreadable. Never delete a key without confirming no resources depend on it.

Last verified: 5 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.