---
title: Dynamodb VPC endpoint without route table association
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: >-
  Docs > Datadog Security > Code Security > Infrastructure as Code (IaC)
  Security > IaC Security Rules > Dynamodb VPC endpoint without route table
  association
---

> For the complete documentation index, see [llms.txt](https://docs.datadoghq.com/llms.txt).

# Dynamodb VPC endpoint without route table association

{% callout %}
# Important note for users on the following Datadog sites: app.ddog-gov.com, us2.ddog-gov.com

{% alert level="danger" %}
This product is not supported for your selected [Datadog site](https://docs.datadoghq.com/getting_started/site.md). ({% placeholder "user-datadog-site-name" /%}).
{% /alert %}

{% /callout %}

## Metadata{% #metadata %}

**Id:** `terraform-aws-dynamodb-vpc-endpoint-without-route-table-association` 

**Provider:** AWS

**Platform:** Terraform

**Severity:** Low

**Category:** Networking and Firewall

#### Learn More{% #learn-more %}

- [Provider Reference](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint#vpc_id)

### Description{% #description %}

AWS VPC endpoints for DynamoDB provide secure and private connectivity between VPC resources and DynamoDB without traversing the public internet. For a VPC endpoint to function correctly, it must be associated with one or more route tables, either by setting `route_table_ids` directly on the `aws_vpc_endpoint` resource or via a standalone `aws_vpc_endpoint_route_table_association` resource whose `vpc_endpoint_id` names the endpoint. If this association is missing, instances within the VPC will not be able to route requests to DynamoDB over the VPC endpoint, potentially forcing traffic through the public internet or causing connectivity failures. This misconfiguration can expose sensitive data to unnecessary network risk and violates best practices for securing internal AWS service communications.

## Compliant Code Examples{% #compliant-code-examples %}

```terraform
provider "aws" {
  region = "us-east-1"
}

locals {
  s3_prefix_list_cidr_block = "3.218.183.128/25"
}
resource "aws_vpc" "main2" {
  cidr_block = "192.168.100.0/24"
  enable_dns_support = true
}

resource "aws_subnet" "private-subnet2" {
  vpc_id     = aws_vpc.main2.id
  cidr_block = "192.168.100.128/25"

  tags = {
    Name = "private-subnet"
  }
}

resource "aws_route_table" "private-rtb2" {
  vpc_id = aws_vpc.main2.id

  tags = {
    Name = "private-rtb"
  }
}

resource "aws_vpc_endpoint" "dynamodb-vpce-gw2" {
  vpc_id       = aws_vpc.main2.id
  service_name = "com.amazonaws.us-east-1.dynamodb"
}

resource "aws_vpc_endpoint_route_table_association" "private-rtb-assoc2" {
  vpc_endpoint_id = aws_vpc_endpoint.dynamodb-vpce-gw2.id
  route_table_id  = aws_route_table.private-rtb2.id
}

resource "aws_network_acl" "allow-public-outbound-nacl2" {
  vpc_id = aws_vpc.main.id
  subnet_ids = [aws_subnet.private-subnet2.id]

  egress {
    protocol   = "tcp"
    rule_no    = 200
    action     = "allow"
    cidr_block = local.s3_prefix_list_cidr_block
    from_port  = 443
    to_port    = 443
  }

  tags = {
    Name = "allow-public-outbound-nacl"
  }
}

resource "aws_security_group" "allow-public-outbound-sg2" {
  name        = "allow-public-outbound-sg"
  description = "Allow HTTPS outbound traffic"
  vpc_id      = aws_vpc.main.id

  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [local.s3_prefix_list_cidr_block]
  }

}

data "aws_ami" "ubuntu2" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "test2" {
  ami = data.aws_ami.ubuntu2.id
  instance_type = "t2.micro"
  vpc_security_group_ids = [aws_security_group.allow-public-outbound-sg2.id]
  subnet_id = aws_subnet.private-subnet2.id
}

resource "aws_dynamodb_table" "basic-dynamodb-table2" {
  name           = "GameScores"
  billing_mode   = "PROVISIONED"
  read_capacity  = 5
  write_capacity = 5
  hash_key       = "UserId"
  range_key      = "GameTitle"

  attribute {
    name = "UserId"
    type = "S"
  }

  attribute {
    name = "GameTitle"
    type = "S"
  }
}
```

## Non-Compliant Code Examples{% #non-compliant-code-examples %}

```terraform
provider "aws" {
  region = "us-east-1"
}

locals {
  s3_prefix_list_cidr_block = "3.218.183.128/25"
}
resource "aws_vpc" "main" {
  cidr_block = "192.168.100.0/24"
  enable_dns_support = true
}

resource "aws_subnet" "private-subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "192.168.100.128/25"

  tags = {
    Name = "private-subnet"
  }
}

resource "aws_route_table" "private-rtb" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "private-rtb"
  }
}

resource "aws_vpc_endpoint" "dynamodb-vpce-gw" {
  vpc_id       = aws_vpc.main.id
  service_name = "com.amazonaws.us-east-1.dynamodb"
}

resource "aws_network_acl" "allow-public-outbound-nacl" {
  vpc_id = aws_vpc.main.id
  subnet_ids = [aws_subnet.private-subnet.id]

  egress {
    protocol   = "tcp"
    rule_no    = 200
    action     = "allow"
    cidr_block = local.s3_prefix_list_cidr_block
    from_port  = 443
    to_port    = 443
  }

  tags = {
    Name = "allow-public-outbound-nacl"
  }
}

resource "aws_security_group" "allow-public-outbound-sg" {
  name        = "allow-public-outbound-sg"
  description = "Allow HTTPS outbound traffic"
  vpc_id      = aws_vpc.main.id

  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [local.s3_prefix_list_cidr_block]
  }

}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "test" {
  ami = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
  vpc_security_group_ids = [aws_security_group.allow-public-outbound-sg.id]
  subnet_id = aws_subnet.private-subnet.id
}

resource "aws_dynamodb_table" "basic-dynamodb-table" {
  name           = "GameScores"
  billing_mode   = "PROVISIONED"
  read_capacity  = 5
  write_capacity = 5
  hash_key       = "UserId"
  range_key      = "GameTitle"

  attribute {
    name = "UserId"
    type = "S"
  }

  attribute {
    name = "GameTitle"
    type = "S"
  }
}
```

```terraform
# Regression fixture: vpc_endpoint_id references an unrelated resource
# (aws_route_table) whose local name happens to collide with the real,
# unassociated aws_vpc_endpoint below. Without checking that the
# reference's own type segment is "aws_vpc_endpoint",
# standalone_association_endpoint_names incorrectly treats this as proof
# that "dynamodb-vpce-real" has a standalone association, suppressing
# the finding for the real, unassociated endpoint.
resource "aws_vpc" "main12" {
  cidr_block         = "10.12.0.0/16"
  enable_dns_support = true
}

resource "aws_route_table" "dynamodb-vpce-real" {
  vpc_id = aws_vpc.main12.id
}

resource "aws_vpc_endpoint" "dynamodb-vpce-real" {
  vpc_id       = aws_vpc.main12.id
  service_name = "com.amazonaws.us-east-1.dynamodb"
}

resource "aws_vpc_endpoint_route_table_association" "fake" {
  vpc_endpoint_id = aws_route_table.dynamodb-vpce-real.id
  route_table_id  = aws_route_table.dynamodb-vpce-real.id
}
```

```terraform
# This endpoint has no route table association at all (no route_table_ids,
# no standalone aws_vpc_endpoint_route_table_association), so it must be
# flagged.
resource "aws_vpc" "stack_a" {
  cidr_block         = "10.50.0.0/16"
  enable_dns_support = true
}

resource "aws_route_table" "shared" {
  vpc_id = aws_vpc.stack_a.id
}

resource "aws_vpc_endpoint" "dynamodb-vpce-stack-a" {
  vpc_id       = aws_vpc.stack_a.id
  service_name = "com.amazonaws.us-east-1.dynamodb"
}
```
