---
title: VPC subnet assigns public IP
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: >-
  Docs > Datadog Security > Code Security > Infrastructure as Code (IaC)
  Security > IaC Security Rules > VPC subnet assigns public IP
---

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

# VPC subnet assigns public IP

{% 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-vpc-subnet-assigns-public-ip` 

**Provider:** AWS

**Platform:** Terraform

**Severity:** Medium

**Category:** Networking and Firewall

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

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

### Description{% #description %}

This check ensures that AWS VPC subnets do not automatically assign public IP addresses by verifying the value of the `map_public_ip_on_launch` attribute. If this attribute is set to `true`, as shown in `map_public_ip_on_launch = true`, instances launched in the subnet will receive public IPs by default, potentially exposing them to the public internet. Leaving this misconfiguration unaddressed increases the risk of unauthorized access, data breaches, and external attacks.

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

```terraform
resource "aws_vpc" "main2" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "negative1" {
  vpc_id     = aws_vpc.main2.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "Negative1"
  }
}
```

```terraform
resource "aws_vpc" "main3" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "negative2" {
  vpc_id     = aws_vpc.main3.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "Negative2"
  }

  map_public_ip_on_launch = false
}
```

```terraform
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.7.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]

  map_public_ip_on_launch = false
  enable_nat_gateway      = true
  enable_vpn_gateway      = true

  tags = {
    Terraform   = "true"
    Environment = "dev"
  }
}
```

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

```terraform
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "positive" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "Positive"
  }

  map_public_ip_on_launch = true
}
```

```terraform
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.7.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]

  map_public_ip_on_launch = true
  enable_nat_gateway      = true
  enable_vpn_gateway      = true

  tags = {
    Terraform   = "true"
    Environment = "dev"
  }
}
```

```terraform
# This fixture demonstrates a check that only works for HCL-parsed .tf
# documents: the module's `map_public_ip_on_launch` input is left unset,
# which the third DatadogPolicy body in query.rego flags via
# `input.document[i].module[name]`.
#
# Known limitation: in a Terraform plan-JSON, the module abstraction is
# fully resolved away -- planned_values only contains the flattened
# child-module resources, never an `input.document[i].module[name]` entry --
# so there is no signal here to detect "the module's map_public_ip_on_launch
# input was left unset" in plan-JSON. The flattened aws_subnet resources
# only expose whatever resolved boolean value was planned, indistinguishable
# from an explicit `map_public_ip_on_launch = false`.
#
# ../test/false_negative_positive3.json is the plan-JSON equivalent of this
# fixture: it is a documented, deliberately-unasserted fixture illustrating
# this gap (the module here compiles to the same flattened subnets, but the
# plan-JSON form gives the rule nothing to key on).
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.7.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = true

  tags = {
    Terraform   = "true"
    Environment = "dev"
  }
}
```
