Terraform AWS DB Subnet Group Deep Dive for RDS and Managed Database Networking

Database subnet groups are a core networking primitive in AWS for placing managed database instances inside a Virtual Private Cloud. Terraform codifies this primitive through the aws_db_subnet_group resource for RDS and analogous resources for DocumentDB, Neptune, ElastiCache and other services. Correct subnet group definition determines placement across Availability Zones, controls Multi-AZ high availability, and gates connectivity through security groups and private routing.

This article covers the resource definition, arguments and attributes, data source usage with Jsonnet tooling, integration with RDS instances, and patterns for other AWS database services. All specifics are drawn from the reference implementations.

What a Database Subnet Group Represents

A database subnet group is a collection of subnets, typically private, that you designate for your database instances. When you create a database instance, AWS uses the subnet group to determine which subnets and availability zones the instance can be launched in. For Multi-AZ deployments, the primary and standby instances are placed in different availability zones within the subnet group.

Database subnet groups define which subnets your database instances can be placed in within your VPC. They are a fundamental networking requirement for many AWS managed database services that run inside a VPC. RDS DB subnet groups generally require subnets in at least two availability zones, and subnet groups that span multiple availability zones enable high availability features like Multi-AZ deployments.

Each AWS database service has its own subnet group resource type.

Resource Definition for RDS

aws_db_subnet_group provides an RDS DB subnet group resource.

Example Usage

resource "aws_db_subnet_group" "default" { name = "main" subnet_ids = ["${aws_subnet.frontend.id}", "${aws_subnet.backend.id}"] tags { Name = "My DB subnet group" } }

Argument Reference

The following arguments are supported:

  • name - Optional, Forces new resource. The name of the DB subnet group. If omitted, Terraform will assign a random, unique name.
  • name_prefix - Optional, Forces new resource. Creates a unique name beginning with the specified prefix. Conflicts with name.
  • description - Optional. The description of the DB subnet group. Defaults to "Managed by Terraform".
  • subnet_ids - Required. A list of VPC subnet IDs.
  • tags - Optional. A mapping of tags to assign to the resource.

Attributes Reference

In addition to all arguments above, the following attributes are exported.

Import

DB Subnet groups can be imported using the name, e.g.

$ terraform import aws_db_subnet_group.default production-subnet-group

Data Source Representation with Jsonnet

The db_subnet_group data source represents the aws_db_subnet_group Terraform data source.

This package contains functions and utilities for setting up the data source using Jsonnet code.

new()

aws.data.db_subnet_group.new

injects a new data_aws_db_subnet_group Terraform data source block into the root module document. Additionally, this inserts a private function into the _ref attribute that generates references to attributes of the resource. For example, if you added a new instance to the root using:

```

arguments omitted for brevity

aws.data.dbsubnetgroup.new('some_id')
```

You can get the reference to the id field of the created aws.data.db_subnet_group using the reference:

$._ref.data_aws_db_subnet_group.some_id.get('id')

This is the same as directly entering "${ data_aws_db_subnet_group.some_id.id }" as the value.

NOTE: if you are chaining multiple resources together in a merge operation, you may not be able to use super, self, or $ to refer to the root object.

VPC and Subnet Foundation for RDS

The tutorial configuration begins with a VPC module.

module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "6.6.0" name = "education" cidr = "10.0.0.0/16" azs = data.aws_availability_zones.available.names public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"] enable_dns_hostnames = true enable_dns_support = true }

The next resource is an aws_db_subnet_group, which designates a collection of subnets that your RDS instance can be provisioned in. This subnet group uses the subnets created by the VPC module.

resource "aws_db_subnet_group" "education" { name = "education" subnet_ids = module.vpc.public_subnets tags = { Name = "Education" } }

This subnet group resource is an optional parameter in your aws_db_instance block below. Without it, Terraform creates your RDS instances in the default VPC.

Linking Subnet Group to an RDS Instance

Review the aws_db_instance configuration.

resource "aws_db_instance" "education" { identifier = "education" instance_class = "db.t3.micro" allocated_storage = 5 engine = "postgres" engine_version = "18.3" username = "edu" password = var.db_password db_subnet_group_name = aws_db_subnet_group.education.name vpc_security_group_ids = [aws_security_group.rds.id] parameter_group_name = aws_db_parameter_group.education.name publicly_accessible = true skip_final_snapshot = true }

Note the following arguments.

username and password: The credentials for the root user.

publicly_accessible: Set to true for this tutorial's configuration.

If you are new to Terraform, complete the Get Started tutorials first.

For this tutorial, you will need:

  • Clone the sample repository for this tutorial, which contains Terraform configuration for an RDS instance, parameter group, security group, and subnet group.
    $ git clone https://github.com/hashicorp-education/learn-terraform-rds
  • Change into the repository directory.
    $ cd learn-terraform-rds
  • Open the main.tf file in your editor to review the sample configuration.

The first resources defined are the VPC and subnets, using the terraform-aws-vpc module.

Cross Service Subnet Group Patterns

The same conceptual model repeats across AWS database services with service-specific resource names.

Creating a DocumentDB Subnet Group

```

Subnet group for DocumentDB

resource "awsdocdbsubnetgroup" "docdb" {
name = "docdb-subnet-group"
description = "Subnet group for DocumentDB clusters"
subnet
ids = local.privatesubnetids
tags = {
Name = "docdb-subnet-group"
Environment = "production"
ManagedBy = "terraform"
}
}
```

```

Use it in a DocumentDB cluster

resource "awsdocdbcluster" "docdb" {
clusteridentifier = "app-docdb"
engine = "docdb"
master
username = "docdbadmin"
masterpassword = var.dbpassword
dbsubnetgroupname = awsdocdbsubnetgroup.docdb.name
vpcsecuritygroupids = [awssecuritygroup.docdbsg.id]
storageencrypted = true
skip
final_snapshot = true
tags = {
Environment = "production"
}
}
```

Creating a Neptune Subnet Group

```

Subnet group for Neptune

resource "awsneptunesubnetgroup" "neptune" {
name = "neptune-subnet-group"
description = "Subnet group for Neptune graph database"
subnet
ids = local.privatesubnetids
tags = {
Name = "neptune-subnet-group"
Environment = "production"
ManagedBy = "terraform"
}
}
```

```

Use it in a Neptune cluster

resource "awsneptunecluster" "neptune" {
clusteridentifier = "app-neptune"
engine = "neptune"
neptune
subnetgroupname = awsneptunesubnetgroup.neptune.name
vpc
securitygroupids = [awssecuritygroup.neptunesg.id]
storage
encrypted = true
skipfinalsnapshot = true
tags =
```

Creating an ElastiCache Subnet Group

ElastiCache uses its own subnet group resource:

```

Subnet group for ElastiCache

resource "awselasticachesubnetgroup" "redis" {
name = "redis-subnet-group"
description = "Subnet group for ElastiCache Redis"
subnet
ids = local.privatesubnetids
tags = {
Name = "redis-subnet-group"
Environment = "production"
ManagedBy = "terraform"
}
}
```

```

Use it in a Redis replication group

resource "awselasticachereplicationgroup" "redis" {
replication
groupid = "app-redis"
description = "Application Redis cluster"
node
type = "cache.r6g.large"
numcacheclusters = 3
automaticfailoverenabled = true
subnetgroupname = awselasticachesubnetgroup.redis.name
security
groupids = [awssecuritygroup.redissg.id]
engine = "redis"
engineversion = "7.0"
at
restencryptionenabled = true
tags = {
Environment = "production"
}
}
```

Aurora cluster example reuses the same RDS subnet group.

resource "aws_rds_cluster" "aurora" { cluster_identifier = "app-aurora" engine = "aurora-postgresql" engine_version = "15.4" database_name = "appdb" master_username = "dbadmin" master_password = var.db_password db_subnet_group_name = aws_db_subnet_group.rds.name vpc_security_group_ids = [aws_security_group.db_sg.id] storage_encrypted = true skip_final_snapshot = true tags = { Environment = "production" } }

Variable definition for sensitive password:

variable "db_password" { type = string sensitive = true }

Specification Comparison

The following table summarizes the core arguments for the RDS DB subnet group resource.

Argument Required Forces New Resource Default / Notes
name Optional Yes Random unique name if omitted
name_prefix Optional Yes Conflicts with name
description Optional No "Managed by Terraform"
subnet_ids Required No List of VPC subnet IDs
tags Optional No Mapping of tags

Attributes exported by the resource include the identifiers and computed values alongside all input arguments.

Service-specific subnet group resources mirror this structure with names such as aws_docdb_subnet_group, aws_neptune_subnet_group, and aws_elasticache_subnet_group. Each service binds the subnet group via a dedicated attribute like db_subnet_group_name, neptune_subnet_group_name, or subnet_group_name.

Practical Notes

  • Subnet selection matters for high availability. RDS DB subnet groups generally require subnets in at least two availability zones. Spanning multiple availability zones enables Multi-AZ deployments where primary and standby instances are placed in different AZs within the subnet group.
  • Public subnets can be referenced in the tutorial example, but production designs typically use private subnets with NAT gateway egress.
  • The description argument defaults to "Managed by Terraform" for RDS DB subnet groups.
  • Import is name-based: terraform import aws_db_subnet_group.default production-subnet-group.
  • When using Jsonnet tooling, the aws.data.db_subnet_group.new helper injects a data source block and provides _ref accessors for attribute interpolation without manual string templating.

Conclusion

The aws_db_subnet_group resource is the control plane for database placement inside a VPC. By declaring name, subnet_ids, and optional description and tags, Terraform creates a named collection of subnets that RDS and Aurora instances can reference via db_subnet_group_name. The same pattern repeats across DocumentDB, Neptune, and ElastiCache with service-specific resource types.

In practice, design the subnet group to span at least two availability zones with private subnets, attach appropriate security groups, and reference the group in the database instance or cluster definition. For IaC automation beyond plain Terraform HCL, the Jsonnet data source helper provides programmatic injection of data_aws_db_subnet_group blocks with reference generation through the _ref attribute.

Consistent naming, tagging, and description conventions across services simplify cost allocation, compliance auditing, and operational troubleshooting. Importing existing subnet groups by name allows gradual migration of legacy resources under Terraform management without recreation.

Sources

  1. tf-libsonnet hashicorp-aws db subnet group
  2. typeerror terraform aws db subnet group
  3. hashicorp developer terraform aws rds tutorial
  4. oneuptime create database subnet groups terraform

Related Posts