Module: ipam
Terraform module to provision:
- Amazon VPC IP Address Manager (IPAM)
- Private IPAM scopes (public scopes cannot be created; the one AWS
makes with the IPAM is exported as
public_default_scope_id) - IPAM pools, nested up to four levels deep, including VPC
resource-planning pools via
source_resource - CIDRs provisioned into those pools, by explicit CIDR or by netmask length, with BYOIP authorization contexts where required
- Manual CIDR reservations that hold space inside a pool without attaching it to anything
- Resource discovery and resource discovery associations, for cross-account and cross-organization monitoring, with organizational unit exclusions
- AWS Resource Access Manager (AWS RAM) resource shares, to share individual pools with accounts, organizational units, or the whole organization
- Delegated IPAM administration via the
organization-adminsubmodule
Introduction
The pool hierarchy
IPAM pools form a tree: a top-level pool holds a supernet, Regional pools draw
from it, and workload pools draw from those. This module takes that tree as a
flat map(object) keyed by your own name for each pool, where a pool names
its parent rather than being physically nested inside it:
pools = {
core = { cidrs = { primary = { cidr = "10.0.0.0/8" } } }
regional = { parent = "core", locale = "us-east-2", cidrs = { primary = { netmask_length = 12 } } }
env = { parent = "regional", locale = "us-east-2", cidrs = { primary = { netmask_length = 16 } } }
}
Two reasons it is flat rather than nested:
- Terraform cannot express a recursive type. A nested
sub_poolsattribute forcestype = any, which gives up schema documentation, IDE completion, and terraform-docs output. That is exactly what happened toaws-ia/ipam, whose centralpool_configurationsinput istype = anywith a 25-line prose schema in a comment. Every input in this module is concretely typed. - Keys stay stable. Adding or removing a pool does not disturb the
for_eachkeys of its siblings, and thepool_idsoutput stays keyed by the names you chose.
Map keys must be known at plan time — they come from your configuration, not
from another resource's attributes.
Following a convention, and setting one
Worth being precise about which is which:
- The input shape follows an existing Cloud Posse convention. A flat
map(object)keyed by a logical name, concretely typed,default = {},nullable = false, key semantics in an inline comment, and the plan-time-key caveat stated in the description isterraform-aws-eks-cluster'saccess_entry_mapapplied to a new domain. - The per-depth materialisation sets one. No Cloud Posse module had
previously modelled a hierarchy, so
aws_vpc_ipam_pool.level_0….level_3, the depth partition inlocals, and thepreconditionguards are new. They follow the spirit of two existing patterns rather than any direct precedent:terraform-aws-dynamic-subnetsduplicates a near-identical resource set across a structural dimension in-repo (public.tf/private.tf) with the branching precomputed inlocals, andterraform-aws-vpcalready splits level 0 from level N for a single concept — acount-gatedaws_vpc.defaultplus afor_each-keyedaws_vpc_ipv4_cidr_block_association.defaultreferencing it, which is structurally one pool tier.
Why tiers are resources here, not a child module
aws-ia/ipam solves the same recursion problem by calling a shared
./modules/sub_pool child module once per depth. This module uses four
resources in the root instead, deliberately:
- A
sub_poolmodule has no standalone value. Everymodules/*in the Cloud Posse fleet is separately documented and separately consumable; a deduplication helper is not. - It keeps resource addresses shallow and predictable —
aws_vpc_ipam_pool.level_1["core"]rather thanmodule.level_one["core"].aws_vpc_ipam_pool.sub[0]. That matters concretely: a consumer migrating between modules has to hand-writemovedblocks against these addresses, because amovedblock can only name addresses relative to its own module instance and so cannot be shipped here. Burying addresses one module deep is precisely what makes migrating offaws-ia/ipampainful, so reproducing it would be self-defeating. - A child module would need its own
context.tf,versions.tfandREADME.md, and CI runs the full bats and tflint matrix over every directory containing a.tffile.
Depth is capped at 4
A pool hierarchy in this module can be four levels deep: a top-level pool
plus three generations beneath it. This is a Terraform limitation rather than an
AWS one. A resource cannot reference itself, so
source_ipam_pool_id = aws_vpc_ipam_pool.this[each.value.parent].id inside
aws_vpc_ipam_pool.this is a cycle. The module instead partitions your map by
computed depth and declares four tiers: aws_vpc_ipam_pool.level_0 through
.level_3.
A deeper tree, a parent that names no existing pool, and a cycle in the
parent links are each rejected at plan time by a separate check that names
the offending pools — the three are reported distinctly rather than lumped
together, since a cycle is not a depth problem. Raising the cap later is a
non-breaking change: one more tier, no input or output shape change, no state
movement for existing pools.
Create and destroy ordering
CIDR provisioning is tiered alongside the pools, so creation runs
pool → its CIDRs → child pool → child's CIDRs, and destruction runs exactly
backwards. This is not cosmetic: DeprovisionIpamPoolCidr fails while any
allocation exists against a CIDR, and a child pool's provisioned CIDR is such an
allocation. Manual reservations likewise carry an explicit depends_on to the
pool CIDRs, because an allocation that references only ipam_pool_id gets no
dependency edge to the CIDR it consumes. Getting this wrong does not fail fast —
it burns the provider's 32-minute allocation-release timeout and then fails.
The module cannot order things it cannot see. A VPC or subnet created from one
of these pools makes an allocation outside this module's graph, and AWS takes up
to 20 minutes to release it after the consumer is deleted. Keep such consumers
in the same configuration with a depends_on, or expect a cold destroy to sit
in that wait.
Provider floor
The module requires AWS provider >= 6.56.0. The strict floor for the
complete argument surface is 6.48.0, which added tags to
aws_vpc_ipam_pool_cidr_allocation. The higher floor buys two fixes that matter
to IPAM specifically: aws_subnet now waits for IPAM to release its CIDR on
delete — the one destroy-ordering hazard no amount of depends_on inside this
module can fix — and resource-planning pools no longer fail when the VPC lives
in another account. Pin lower only if you use neither IPAM-backed subnets nor
cross-account source_resource pools.
Migrating from aws-ia/ipam
See docs/migration-aws-ia-v1.md for the input
mapping, the moved blocks to write in your root module, and state mv /
import fallbacks.
Usage
Here's how to invoke this module in your projects:
module "ipam" {
source = "cloudposse/ipam/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
operating_regions = ["us-east-2", "us-west-2"]
pools = {
core = {
cidrs = {
primary = { cidr = "10.0.0.0/8" }
}
}
use2 = {
parent = "core"
locale = "us-east-2"
cidrs = {
primary = { netmask_length = 12 }
}
# Share this pool with the whole organization
ram_share = {
principals = ["arn:aws:organizations::123456789012:organization/o-abcde12345"]
}
}
use2_prod = {
parent = "use2"
locale = "us-east-2"
allocation_default_netmask_length = 24
cidrs = {
primary = { netmask_length = 16 }
}
# Hold space inside the pool without attaching it to anything
allocations = {
reserved = { netmask_length = 20, description = "Held for future use" }
}
}
}
context = module.this.context
}
Consumers index the pool_ids output by the names they supplied:
module "vpc" {
source = "cloudposse/vpc/aws"
version = "2.2.0"
ipv4_primary_cidr_block_association = {
ipv4_ipam_pool_id = module.ipam.pool_ids["use2_prod"]
ipv4_netmask_length = 20
}
context = module.this.context
}
Quick Start
The smallest useful configuration is an IPAM with a single pool:
module "ipam" {
source = "cloudposse/ipam/aws"
# version = "x.x.x"
pools = {
core = {
cidrs = {
primary = { cidr = "10.0.0.0/8" }
}
}
}
context = module.this.context
}
This creates the IPAM (which brings its own public scope, private scope, default
resource discovery, and default association), one top-level pool in the private
default scope, and provisions 10.0.0.0/8 into it. Grow the tree by adding
entries that name core as their parent.
Note that the provider defaults an IPAM to the billable advanced tier. Set
ipam_tier = "free" if that is what you want.
Examples
Here is an example of using this module:
examples/complete- builds a full four-level pool hierarchy in a named private scope, provisions a CIDR into each tier, holds a manual reservation in the deepest pool, and creates a resource discovery
For automated tests of the complete example using Terratest (which tests and deploys the example on AWS), see test.
Variables
Required Variables
Optional Variables
create_ipam(bool) optionalWhether to create an
aws_vpc_ipam.Set to
falseto build pools inside an IPAM that already exists — the usual
shape for a second instance of this module in another Region, or for pools
managed separately from the IPAM itself. Whenfalse, supply
existing_ipam_scope_id, andexisting_ipam_idas well if you need the
IPAM-level outputs or any resource discovery associationDefault value:
truecreate_resource_discovery(bool) optionalWhether to create an
aws_vpc_ipam_resource_discovery.Only needed for cross-account or cross-organization monitoring. Every account
already gets a default resource discovery and a default association to its own
IPAM; those surface as thedefault_resource_discovery_idand
default_resource_discovery_association_idoutputs and are not managed hereDefault value:
falseexisting_ipam_id(string) optionalID of an existing
aws_vpc_ipamto build against. Only consulted whencreate_ipamisfalseDefault value:
nullexisting_ipam_scope_id(string) optionalID of an existing IPAM scope that top-level pools default into. Only consulted
whencreate_ipamisfalse.Required whenever
create_ipamisfalseandpoolscontains a top-level
pool that does not resolve a scope of its own. Scope IDs are attributes of the
aws_vpc_ipamresource, so there is no way to look a default scope up from an
IPAM ID alone — a caller binding to an existing IPAM has to pass one throughDefault value:
nullipam_cascade_enabled(bool) optionalWhether to enable cascade delete on the IPAM.
Delete-time only. The provider reads this solely in its Delete path, so
toggling it produces no API call and no observable change until a destroy.On destroy it tears down every private scope, every pool inside them, and every
allocation inside those — including address space that is in live use. Without
it, destroying a non-empty IPAM fails, which is usually what you want. Leave
falseunless you are deliberately building a disposable environmentDefault value:
falseipam_description(string) optionalDescription for the IPAM. Defaults to the null-label ID. Only used when
create_ipamistrueDefault value:
nullipam_tier(string) optionalIPAM tier. Valid values:
free,advanced.Leaving this
nullinherits the provider's own default ofadvanced, which is
the billable tier — setfreeexplicitly if that is what you want. Mutable in
placeDefault value:
nullipam_timeoutsoptionalOperation timeouts for the
aws_vpc_ipamresource.nullentries inherit the provider defaults of 3m eachType:
object({
create = optional(string, null)
update = optional(string, null)
delete = optional(string, null)
})Default value:
{ }metered_account(string) optionalWhich account is metered for IPAM usage. Valid values:
ipam-owner,
resource-owner.Optional and Computed in the provider, so leaving it
nullnever produces a
diffDefault value:
nulloperating_regions(list(string)) optionalRegions the IPAM may discover, monitor, and allocate from.
The provider requires this to include the Region the module is applied into,
and enforces that at create time only — removing the current Region later
is not blocked by Terraform, though the API may still reject it. When empty,
the module registers just the current Region.Fully mutable: the provider diffs the set and sends add/remove to
ModifyIpam,
so growing or shrinking this list never replaces the IPAMDefault value:
[ ]pool_cidr_timeoutsoptionalOperation timeouts applied to every
aws_vpc_ipam_pool_cidr.nullentries
inherit the provider defaults of create 10m and delete 32m.Do not lower the 32m delete. That budget is the up-to-20-minute window AWS
takes to release VPC and subnet allocations after the consuming resource is
deleted, plus the deprovision wait. Shortening it turns a slow destroy into a
failed oneType:
object({
create = optional(string, null)
delete = optional(string, null)
})Default value:
{ }pool_timeoutsoptionalOperation timeouts applied to every
aws_vpc_ipam_pool.nullentries inherit
the provider defaults.The provider's 35m create default is not padding — pool provisioning is
genuinely slow. Do not shorten it without a reasonType:
object({
create = optional(string, null)
update = optional(string, null)
delete = optional(string, null)
})Default value:
{ }poolsoptionalIPAM pools to create, as a flat map keyed by your own name for each pool.
Keys must be known atplantime.Hierarchy is expressed by naming another entry in this same map as a pool's
parent, rather than by physically nesting the objects. A pool with no
parentis top-level and sits directly in a scope. A flat keyed map is used
because Terraform cannot express a recursive type — nesting would force
type = anyand give up schema documentation and IDE completion — and because
the keys stay stable as pools are added and removed.Nesting is capped at a depth of 4: a top-level pool plus three generations
beneath it. The cap is a Terraform limitation rather than an AWS one — a
resource cannot reference itself, so an arbitrarily deep tree cannot be built
from a singleaws_vpc_ipam_poolblock. The module partitions this map by
computed depth and declares four tiers,aws_vpc_ipam_pool.level_0through
.level_3. A deeper tree, aparentnaming no existing pool, and a cycle in
theparentlinks are each rejected at plan time by a separate check that
names the offending pools.Each pool's provisioned CIDRs nest under its
cidrs, its manual reservations
under itsallocations, and its RAM sharing underram_shareType:
map(object({
# key is your own name for the pool. It is the key of the `pool_ids`,
# `pool_arns` and `pool_cidrs` outputs, and the value another entry names in
# its `parent`. Keys must be known at `plan` time, and are a compatibility
# contract with your consumers: renaming one replaces the pool.
# Name of the entry in this same map that is this pool's parent. Omit for a
# top-level pool. Nesting is capped at a depth of 4 — see the validations.
parent = optional(string, null)
# --- identity. All ForceNew: changing any of these replaces the pool, and the
# --- replacement cascades to every CIDR, allocation and child pool beneath it.
address_family = optional(string, "ipv4")
locale = optional(string, null)
# Scope selection, in precedence order: an explicit `ipam_scope_id` wins, then
# `scope` naming a key of `var.scopes`, then the parent pool's scope for a
# child, then the IPAM's private default scope.
ipam_scope_id = optional(string, null)
scope = optional(string, null)
# Public-scope pools only. `aws_service` accepts `ec2` or `global-services` —
# the provider validates against the SDK enum, which carries both, even though
# the upstream documentation lists only `ec2`.
aws_service = optional(string, null)
public_ip_source = optional(string, null)
# Cannot be validated from configuration: the provider does a live scope lookup
# during apply and only sends this when `address_family` is `ipv6`, the scope is
# public, and `public_ip_source` is not `amazon`. Setting it when unavailable
# can report erroneous differences.
publicly_advertisable = optional(bool, null)
# VPC resource-planning pool. The block and all four fields are ForceNew, and
# `resource_region` must equal this pool's `locale`.
source_resource = optional(object({
resource_id = string
resource_owner = string
resource_region = string
resource_type = optional(string, "vpc")
}), null) # source_resource
# --- mutable in place. These six are the entire payload `ModifyIpamPool` ever
# --- receives; every other argument above replaces the pool.
#
# Provider defect: the Update path reads these with `d.GetOk` rather than
# `d.HasChange`, and `GetOk` reports a zero value as unset. Resetting
# `auto_import` to `false`, any netmask length to `0`, or `description` to `""`
# is silently dropped — the API never receives it and the old value persists.
# Treat them as one-way; to clear one, replace the pool.
allocation_default_netmask_length = optional(number, null)
allocation_max_netmask_length = optional(number, null)
allocation_min_netmask_length = optional(number, null)
allocation_resource_tags = optional(map(string), {})
auto_import = optional(bool, null)
description = optional(string, null)
# Delete-time only, exactly as `ipam_cascade_enabled`. On destroy this tears
# down the pool's provisioned CIDRs, allocations and child pools. Note the
# pool's own Delete does not *wait* for children the way the CIDR resource
# waits for allocations — without cascade it simply fails on a non-empty pool.
cascade = optional(bool, false)
tags = optional(map(string), {})
# --- CIDRs provisioned into this pool, keyed by an arbitrary name. Every
# --- argument is ForceNew; the resource has no Update function at all.
cidrs = optional(map(object({
# `cidr` and `netmask_length` are mutually exclusive. Set neither and the pool
# must carry `allocation_default_netmask_length` or the apply fails.
cidr = optional(string, null)
netmask_length = optional(number, null)
# BYOIP proof of ownership: the RIR/X.509-signed message and its signature,
# needed solely when provisioning a public BYOIP range into a public-scope
# pool. Never needed for private space, and never for
# `public_ip_source = "amazon"`. Not persisted to state, so it cannot drift.
cidr_authorization_context = optional(object({
message = optional(string, null)
signature = optional(string, null)
}), null) # cidr_authorization_context
})), {}) # cidrs
# --- manual reservations against this pool, keyed by an arbitrary name.
# --- Everything except `tags` is ForceNew; the Update function is a stub that
# --- calls no API.
allocations = optional(map(object({
cidr = optional(string, null)
netmask_length = optional(number, null)
# Ranges IPAM must skip when *choosing* a block. Inert unless paired with
# `netmask_length` — with an explicit `cidr` it does nothing, silently.
disallowed_cidrs = optional(set(string), null)
description = optional(string, null)
tags = optional(map(string), {})
})), {}) # allocations
# --- RAM sharing. Set `principals` to share this pool with other accounts,
# --- organizational units, or the whole organization.
ram_share = optional(object({
principals = optional(set(string), [])
allow_external_principals = optional(bool, false)
permission_arns = optional(set(string), null)
tags = optional(map(string), {})
}), null) # ram_share
}))Default value:
{ }private_gua_enabled(bool) optionalWhether IPAM treats your own globally-unique IPv6 ranges (from
2000::/3) as
private address space. Maps to the provider'senable_private_gua. Mutable in
placeDefault value:
nullram_share_permission_arns(list(string)) optionalDefault RAM permission ARNs applied to every pool share that does not set its
ownpermission_arns. Leave empty to let RAM apply its default managed
permission for IPAM poolsDefault value:
[ ]region(string) optionalAWS Region for every resource this module creates. Leave
nullto inherit the
Region from the provider configuration.Changing this replaces every resource in the module. The provider applies
ForceNewtoregionthrough a CustomizeDiff interceptor rather than a schema
flag, so it does not show up asForceNewin the resource documentationDefault value:
nullresource_discovery_associationsoptionalResource discoveries to associate with this IPAM, keyed by name. Keys must be
known atplantime. This is the bind step that lets an IPAM in one account see
resources discovered in another.ipam_iddefaults to this module's IPAM.Both IDs are Required but not ForceNew, and the provider's Update function
makes zero API calls — changing either would otherwise plan an in-place update
that does nothing and then reverts on the next refresh. The module forces
replacement itself withreplace_triggered_by, so changing an ID here replaces
the association instead of silently doing nothingType:
map(object({
# key names the association and fills the null-label `attributes` slot
ipam_id = optional(string, null)
ipam_resource_discovery_id = string
tags = optional(map(string), {})
}))Default value:
{ }resource_discovery_description(string) optionalDescription for the resource discovery. Defaults to the null-label ID. Only used when
create_resource_discoveryistrueDefault value:
nullresource_discovery_operating_regions(list(string)) optionalRegions the resource discovery monitors. When empty, falls back to
operating_regions, and then to the current Region.Independent of
operating_regions: the provider keeps the two sets in no sync
whatsoever. The IPAM's set governs whichlocalevalues pools may use; this
one governs which Regions get discovered and monitored. A discovery can watch a
Region the IPAM cannot allocate into, and vice versa.Like the IPAM's set, this must include the current Region at create time, and
that rule is enforced on create onlyDefault value:
[ ]resource_discovery_organizational_unit_exclusions(list(string)) optionalAWS Organizations entity paths to exclude from discovery — Organizations IDs
joined by/. End a path with/*to exclude all child OUs. Subject to the
documented IPAM quota on exclusionsDefault value:
[ ]scopesoptionalAdditional private IPAM scopes to create, keyed by name. Keys must be known
atplantime.Additional public scopes cannot be created —
CreateIpamScopeonly ever
produces a private scope, and there is no scope-type argument anywhere in the
provider schema. The single public scope is the one IPAM creates alongside
itself; consume it read-only through thepublic_default_scope_idoutput.Only
descriptionis mutable; it is the one fieldModifyIpamScopeacceptsType:
map(object({
# key is the scope name, used for the null-label `attributes` slot, as the key
# of the `scope_ids` output, and as the value a pool's `scope` names
description = optional(string, null)
tags = optional(map(string), {})
}))Default value:
{ }
Context Variables
The following variables are defined in the context.tf file of this module and part of the terraform-null-label pattern.
context.tf file of this module and part of the terraform-null-label pattern.additional_tag_map(map(string)) optionalAdditional key-value pairs to add to each map in
tags_as_list_of_maps. Not added totagsorid.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration.Required: No
Default value:
{ }attributes(list(string)) optionalID element. Additional attributes (e.g.
workersorcluster) to add toid,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by thedelimiter
and treated as a single ID element.Required: No
Default value:
[ ]context(any) optionalSingle object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables asnullto use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged.Required: No
Default value:
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}delimiter(string) optionalDelimiter to be used between ID elements.
Defaults to-(hyphen). Set to""to use no delimiter at all.Required: No
Default value:
nulldescriptor_formats(any) optionalDescribe additional descriptors to be output in the
descriptorsoutput map.
Map of maps. Keys are names of descriptors. Values are maps of the form
\{<br/> format = string<br/> labels = list(string)<br/> \}
(Type isanyso the map values can later be enhanced to provide additional options.)
formatis a Terraform format string to be passed to theformat()function.
labelsis a list of labels, in order, to pass toformat()function.
Label values will be normalized before being passed toformat()so they will be
identical to how they appear inid.
Default is{}(descriptorsoutput will be empty).Required: No
Default value:
{ }enabled(bool) optionalSet to false to prevent the module from creating any resources
Required: NoDefault value:
nullenvironment(string) optionalID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'
Required: NoDefault value:
nullid_length_limit(number) optionalLimit
idto this many characters (minimum 6).
Set to0for unlimited length.
Set tonullfor keep the existing setting, which defaults to0.
Does not affectid_full.Required: No
Default value:
nulllabel_key_case(string) optionalControls the letter case of the
tagskeys (label names) for tags generated by this module.
Does not affect keys of tags passed in via thetagsinput.
Possible values:lower,title,upper.
Default value:title.Required: No
Default value:
nulllabel_order(list(string)) optionalThe order in which the labels (ID elements) appear in the
id.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present.Required: No
Default value:
nulllabel_value_case(string) optionalControls the letter case of ID elements (labels) as included in
id,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via thetagsinput.
Possible values:lower,title,upperandnone(no transformation).
Set this totitleand setdelimiterto""to yield Pascal Case IDs.
Default value:lower.Required: No
Default value:
nulllabels_as_tags(set(string)) optionalSet of labels (ID elements) to include as tags in the
tagsoutput.
Default is to include all labels.
Tags with empty values will not be included in thetagsoutput.
Set to[]to suppress all generated tags.
Notes:
The value of thenametag, if included, will be theid, not thename.
Unlike othernull-labelinputs, the initial setting oflabels_as_tagscannot be
changed in later chained modules. Attempts to change it will be silently ignored.Required: No
Default value:
[
"default"
]name(string) optionalID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as atag.
The "name" tag is set to the fullidstring. There is no tag with the value of thenameinput.Required: No
Default value:
nullnamespace(string) optionalID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique
Required: NoDefault value:
nullregex_replace_chars(string) optionalTerraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set,"/[^a-zA-Z0-9-]/"is used to remove all characters other than hyphens, letters and digits.Required: No
Default value:
nullstage(string) optionalID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'
Required: NoDefault value:
nulltags(map(string)) optionalAdditional tags (e.g.
{'BusinessUnit': 'XYZ'}).
Neither the tag keys nor the tag values will be modified by this module.Required: No
Default value:
{ }tenant(string) optionalID element (Rarely used, not included by default). A customer identifier, indicating who this instance of a resource is for
Required: NoDefault value:
null
Outputs
allocation_cidrsMap from
<pool name>/<allocation name>to the CIDR reserved by each manual reservationallocation_idsMap from
<pool name>/<allocation name>to the AWS allocation ID of each
manual reservation.This is
ipam_pool_allocation_id, not the Terraform resource ID — the latter
is the composite<allocation id>_<pool id>and is whatterraform import
takesallocationsMap from
<pool name>/<allocation name>to the fullaws_vpc_ipam_pool_cidr_allocationresource (all attributes), includingresource_id,resource_owner,resource_typeandnetmask_lengthdefault_resource_discovery_association_idID of the resource discovery association IPAM creates alongside itself. Not managed by this module
default_resource_discovery_idID of the resource discovery IPAM creates alongside itself. Not managed by this module
ipamThe full
aws_vpc_ipamresource created by this module (all attributes).nullwhencreate_ipamisfalseipam_arnARN of the IPAM created by this module.
nullwhencreate_ipamisfalseipam_idID of the IPAM — the one created here, or
existing_ipam_idwhencreate_ipamisfalsepool_arnsMap from the keys of
poolsto the ARN of each created pool, flattened across every depth tierpool_cidr_idsMap from
<pool name>/<cidr name>to the Terraform ID of each provisioned pool CIDR, which is the composite<cidr>_<pool id>pool_cidrsMap from the keys of
poolsto the list of CIDRs provisioned into that pool.A pool with no provisioned CIDRs maps to an empty list. Values for CIDRs
requested bynetmask_lengthare chosen by IPAM and so are only known after
applypool_cidrs_detailMap from
<pool name>/<cidr name>to the fullaws_vpc_ipam_pool_cidrresource (all attributes), flattened across every depth tierpool_idsMap from the keys of
poolsto the ID of each created pool, flattened across
every depth tier.This is the module's primary interface. The keys are the ones you supplied, so
a downstream component can re-export this map whole and let its own consumers
index it by name without knowing anything about the pool hierarchypool_namesMap from the keys of
poolsto the null-label ID generated for each pool —
the value used as that pool'sNametag and as its default descriptionpool_scope_idsMap from the keys of
poolsto the scope each pool was created in, flattened across every depth tierpool_statesMap from the keys of
poolsto the state of each created pool, flattened across every depth tierpoolsMap from the keys of
poolsto the fullaws_vpc_ipam_poolresource (all attributes), flattened across every depth tierprivate_default_scope_idID of the IPAM's private default scope, which top-level pools land in unless they name another
public_default_scope_idID of the IPAM's public default scope. Read-only: additional public scopes
cannot be created, so this is the only public scope there will ever be.
nullwhencreate_ipamisfalseram_resource_share_arnsMap from the keys of
poolsthat requested RAM sharing to the ARN of that pool's resource shareram_resource_sharesMap from the keys of
poolsthat requested RAM sharing to the fullaws_ram_resource_shareresource (all attributes)resource_discoveryThe full
aws_vpc_ipam_resource_discoveryresource created by this module (all attributes, includingowner_idandis_default).nullwhencreate_resource_discoveryisfalseresource_discovery_arnARN of the resource discovery created by this module.
nullwhencreate_resource_discoveryisfalseresource_discovery_association_idsMap from the keys of
resource_discovery_associationsto the ID of each associationresource_discovery_associationsMap from the keys of
resource_discovery_associationsto the fullaws_vpc_ipam_resource_discovery_associationresource (all attributes, includingstate,owner_idandipam_arn)resource_discovery_idID of the resource discovery created by this module.
nullwhencreate_resource_discoveryisfalsescope_arnsMap from the keys of
scopesto the ARN of each created scopescope_countNumber of scopes on the IPAM, including the two default ones
scope_idsMap from the keys of
scopesto the ID of each created scopescopesMap from the keys of
scopesto the fullaws_vpc_ipam_scoperesource (all attributes)
Dependencies
Requirements
terraform, version:>= 1.4.0aws, version:>= 6.56.0
Providers
aws, version:>= 6.56.0terraform
Modules
| Name | Version | Source | Description |
|---|---|---|---|
pool_label | 0.25.0 | cloudposse/label/null | n/a |
resource_discovery_association_label | 0.25.0 | cloudposse/label/null | n/a |
scope_label | 0.25.0 | cloudposse/label/null | n/a |
this | 0.25.0 | cloudposse/label/null | n/a |
Resources
The following resources are used by this module:
aws_ram_principal_association.default(resource)aws_ram_resource_association.default(resource)aws_ram_resource_share.default(resource)aws_vpc_ipam.default(resource)aws_vpc_ipam_pool.level_0(resource)aws_vpc_ipam_pool.level_1(resource)aws_vpc_ipam_pool.level_2(resource)aws_vpc_ipam_pool.level_3(resource)aws_vpc_ipam_pool_cidr.level_0(resource)aws_vpc_ipam_pool_cidr.level_1(resource)aws_vpc_ipam_pool_cidr.level_2(resource)aws_vpc_ipam_pool_cidr.level_3(resource)aws_vpc_ipam_pool_cidr_allocation.default(resource)aws_vpc_ipam_resource_discovery.default(resource)aws_vpc_ipam_resource_discovery_association.default(resource)aws_vpc_ipam_scope.default(resource)terraform_data.pool_graph_guard(resource)terraform_data.resource_discovery_association_ids(resource)terraform_data.scope_ipam_id(resource)
Data Sources
The following data sources are used by this module:
aws_region.current(data source)