Secure-by-default Amazon DataZone data-governance/catalog fabric — the domain keystone plus projects, environment profiles, environments, environment-blueprint configuration, business glossaries/terms, custom form types, custom asset types, and user profiles, from a single composite call. Only the domain is taggable; every child collection cross-validates its key references at plan time. Built for the AWS provider v6.x.
- 🏛️ Provisions an
aws_datazone_domainkeystone plus the full governance/catalog fabric under it: projects, environment profiles, environments, environment-blueprint configurations, glossaries, glossary terms, custom form types, custom asset types, and user profiles — one composite call, one working, access-governed data-catalog domain. - 🔐 Optional customer-managed KMS key (
kms_key_identifier) for domain metadata/reporting-data encryption — null defaults to an AWS-owned key; supply a CMK fromtf-mod-aws-kmsfor any domain cataloging PII-adjacent metadata. - 🪪 IAM Identity Center integration is first-class (
single_sign_on) —user_assignmentdefaults to"MANUAL"(secure baseline): every data-portal user is an explicit, reviewable assignment, never an automatic grant to the whole Identity Center population. - 🛑 Domain and project deletion checks default to on (
skip_deletion_check = false) — DataZone refuses to delete a non-empty domain/project unless you explicitly opt into cascade deletion. - 🏷️ Only the domain is taggable. Confirmed against the live v6.54.0 schema: none of the nine child resources (project, environment, environment_profile, environment_blueprint_configuration, glossary, glossary_term, form_type, asset_type, user_profile) expose a
tags/tags_allargument — the mirror image oftf-mod-aws-organizations, where the parent is untaggable and the children are. - 🔗 Every cross-collection key reference is validated at plan time —
project_key,glossary_key,environment_profile_keytypos surface as a clearterraform planerror, never an opaque provider 400. - 🧬 Two resources have no synthetic
idat all —aws_datazone_form_typeandaws_datazone_asset_typeare identified by(domain, name[, revision]); this module surfacesname/revisionoutputs instead of fabricating an id that doesn't exist.
💡 Why it matters: DataZone is the access-grant and discovery layer for our data estate — it doesn't move data, it governs who can find and request it. Getting the domain's encryption, SSO, and deletion-safety defaults right here is what keeps a catalog of PII-adjacent metadata from becoming its own exposure surface.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- ⭐ Star this repository to help others discover this Terraform module.
- 🤝 Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- ☕ Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
tf-mod-aws-datazone sits downstream of the identity/encryption foundation modules and upstream of the actual data-plane modules it catalogs. It does not create IAM roles, KMS keys, an Identity Center instance, or the underlying Glue/Redshift/Lake Formation resources — those are sibling modules it consumes by ARN/id or is consumed by.
flowchart LR
iamrole["tf-mod-aws-iam-role<br/>domain_execution_role / service_role"]
kms["tf-mod-aws-kms<br/>kms_key_identifier"]
idc["IAM Identity Center<br/>(account opt-in)"]
dz["tf-mod-aws-datazone"]
glue["tf-mod-aws-glue"]
redshift["tf-mod-aws-redshift"]
lf["tf-mod-aws-lakeformation"]
s3["tf-mod-aws-s3-bucket"]
iamrole -->|"arn"| dz
kms -->|"arn"| dz
idc -->|"single_sign_on.type = IAM_IDC"| dz
dz -->|"environment_provisioned_resources"| glue
dz -->|"environment_provisioned_resources"| redshift
dz -->|"glossary_term_ids (tag-based access)"| lf
dz -.->|"catalogs metadata about"| s3
style dz fill:#FF9900,color:#fff,stroke:#cc7a00,stroke-width:2px
flowchart TB
subgraph DZMOD["tf-mod-aws-datazone"]
dom["aws_datazone_domain.this<br/>(keystone)"]
proj["aws_datazone_project.this<br/>for_each projects"]
envprof["aws_datazone_environment_profile.this<br/>for_each environment_profiles"]
env["aws_datazone_environment.this<br/>for_each environments"]
ebc["aws_datazone_environment_blueprint_configuration.this<br/>for_each environment_blueprint_configurations"]
glos["aws_datazone_glossary.this<br/>for_each glossaries"]
term["aws_datazone_glossary_term.this<br/>for_each glossary_terms"]
form["aws_datazone_form_type.this<br/>for_each form_types"]
asset["aws_datazone_asset_type.this<br/>for_each asset_types"]
user["aws_datazone_user_profile.this<br/>for_each user_profiles"]
dom -->|"id"| proj
dom -->|"id"| ebc
dom -->|"id"| user
proj -->|"id"| envprof
proj -->|"id"| glos
proj -->|"id"| form
proj -->|"id"| asset
envprof -->|"id"| env
proj -->|"id"| env
glos -->|"id"| term
form -.->|"name / revision"| asset
end
style dom fill:#FF9900,color:#fff,stroke:#cc7a00,stroke-width:2px
| Resource | Role | Cardinality | Taggable | Has id? |
|---|---|---|---|---|
aws_datazone_domain.this |
Keystone — domain identity, encryption, SSO | 1 | ✅ | ✅ (+ arn) |
aws_datazone_project.this |
Project namespace | per projects entry |
❌ | ✅ |
aws_datazone_environment_profile.this |
Reusable environment template | per environment_profiles entry |
❌ | ✅ |
aws_datazone_environment.this |
Deployed environment | per environments entry |
❌ | ✅ |
aws_datazone_environment_blueprint_configuration.this |
Regional blueprint enablement | per environment_blueprint_configurations entry |
❌ | ❌ (no attributes beyond arguments) |
aws_datazone_glossary.this |
Business glossary | per glossaries entry |
❌ | ✅ |
aws_datazone_glossary_term.this |
Glossary term | per glossary_terms entry |
❌ | ✅ |
aws_datazone_form_type.this |
Custom metadata schema | per form_types entry |
❌ | ❌ (composite name+revision identity) |
aws_datazone_asset_type.this |
Custom asset type | per asset_types entry |
❌ | ❌ (composite name identity) |
aws_datazone_user_profile.this |
Activated data-portal principal | per user_profiles entry |
❌ | ✅ |
ℹ️ Only
aws_datazone_domainexposes atagsargument in the v6.54.0 provider schema — the module deliberately does not attempt to tag any of the nine child resources.
| Requirement | Version |
|---|---|
| Terraform | >= 1.12.0 |
hashicorp/aws |
>= 6.0, < 7.0 |
No provider {} block is declared inside the module — the caller's configured provider (credentials, default_tags) is inherited. Credentials resolve through the standard AWS chain (env → SSO/shared credentials → assume_role → instance profile / IRSA → OIDC) at the root/pipeline level; there are no credential variables. DataZone resources are Regional (no region variable declared — see Architecture Notes for the environment cross-account/cross-region nuance, which is a plain string-argument concern, not a provider-alias one).
| Action | Required for | Notes |
|---|---|---|
datazone:CreateDomain, datazone:GetDomain, datazone:UpdateDomain, datazone:DeleteDomain, datazone:ListDomains |
Domain lifecycle | |
datazone:CreateProject, datazone:GetProject, datazone:UpdateProject, datazone:DeleteProject, datazone:ListProjects |
Project lifecycle | |
datazone:CreateEnvironmentProfile, datazone:GetEnvironmentProfile, datazone:UpdateEnvironmentProfile, datazone:DeleteEnvironmentProfile, datazone:ListEnvironmentProfiles |
Environment-profile lifecycle | |
datazone:CreateEnvironment, datazone:GetEnvironment, datazone:UpdateEnvironment, datazone:DeleteEnvironment, datazone:ListEnvironments |
Environment lifecycle | Provisioning is asynchronous — see AWS Prerequisites |
datazone:PutEnvironmentBlueprintConfiguration, datazone:GetEnvironmentBlueprintConfiguration, datazone:DeleteEnvironmentBlueprintConfiguration, datazone:ListEnvironmentBlueprintConfigurations, datazone:ListEnvironmentBlueprints, datazone:GetEnvironmentBlueprint |
Blueprint enablement + blueprint-id lookups | The last two are used by the caller's aws_datazone_environment_blueprint data-source lookup, out of scope for this module |
datazone:CreateGlossary, datazone:GetGlossary, datazone:UpdateGlossary, datazone:DeleteGlossary |
Glossary lifecycle | |
datazone:CreateGlossaryTerm, datazone:GetGlossaryTerm, datazone:UpdateGlossaryTerm, datazone:DeleteGlossaryTerm |
Glossary-term lifecycle | |
datazone:CreateFormType, datazone:GetFormType, datazone:UpdateFormType, datazone:DeleteFormType |
Form-type lifecycle | DeleteFormType only succeeds once status = DISABLED — see Troubleshooting |
datazone:CreateAssetType, datazone:GetAssetType, datazone:DeleteAssetType |
Asset-type lifecycle | |
datazone:CreateUserProfile, datazone:GetUserProfile, datazone:UpdateUserProfile |
User-profile lifecycle | No DeleteUserProfile action exists — see Architecture Notes |
datazone:TagResource, datazone:UntagResource, datazone:ListTagsForResource |
Tagging the domain | The only taggable resource in this module |
iam:PassRole |
Passing domain_execution_role, service_role, manage_access_role_arn, provisioning_role_arn to DataZone |
Scope the resource to only these specific role ARNs |
sso:* (scope down per your Identity Center delegation model) |
single_sign_on enablement |
AWS's own example policy grants broad sso:* — narrow this for production |
kms:CreateGrant, kms:DescribeKey |
kms_key_identifier (CMK) |
The CMK's own key policy must separately allow the DataZone service principal |
No DataZone service-linked role is auto-created by this module's actions; enabling an AWS-managed blueprint provisions a CloudFormation stack that creates its own resources in the target account/Region.
domain_execution_rolemust exist first, with a trust policy allowingsts:AssumeRole/sts:TagSession(andsts:SetContextfor V2) fordatazone.amazonaws.com, pluscloudformation.amazonaws.comfor CloudFormation-provisioned blueprints.domain_version = "V2"also requiresservice_role— a second IAM role with its own AWS-managed policy attachment (DataZone V2 shares SageMaker Unified Studio's domain model).- IAM Identity Center must be enabled account/organization-wide before
single_sign_on.type = "IAM_IDC"succeeds — an account-level opt-in outside this module's (and this catalog's Phase 1) scope. - Environment blueprints are AWS-managed, not created here. Resolve
environment_blueprint_identifiervia theaws_datazone_environment_blueprintdata source before referencing it. - Region model: domain/project/glossary/metadata-type resources are Regional with no us-east-1 coupling;
environment_profiles/environmentsprovision into a specific targetaws_account_id/aws_account_regionas plain string arguments — DataZone's native cross-account data-mesh model, not a Terraform provider-alias concern. - Service quotas (soft limits): domains per account/Region, projects per domain, environments per project, glossaries per project — consult DataZone's Service Quotas page before large rollouts.
tf-mod-aws-datazone/
├── providers.tf # terraform{} + required_providers (aws >= 6.0, < 7.0); no provider block
├── variables.tf # domain config, 9 child-collection maps, tags, timeouts
├── main.tf # aws_datazone_domain.this + 9 for_each child resources
├── outputs.tf # id + arn (domain), portal_url, child reference maps, tags_all
├── README.md # this file
└── SCOPE.md # in/out-of-scope, Consumes/Emits, IAM, prerequisites, gotchas
module "iam_domain_execution_role" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-iam-role?ref=v1.0.0"
name = "datazone-domain-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["sts:AssumeRole", "sts:TagSession"]
Principal = { Service = "datazone.amazonaws.com" }
}]
})
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-data-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
lending_analytics = {
name = "lending-analytics"
description = "Aggregated, de-identified lending analytics project."
}
}
tags = {
Environment = "prod"
Owner = "data-governance"
}
}| Input | Type | Source module |
|---|---|---|
domain_execution_role |
string (IAM role ARN) |
tf-mod-aws-iam-role |
service_role |
string (IAM role ARN, V2 only) |
tf-mod-aws-iam-role |
kms_key_identifier |
string (KMS key ARN) |
tf-mod-aws-kms |
environment_blueprint_configurations[*].manage_access_role_arn / provisioning_role_arn |
string (IAM role ARN) |
tf-mod-aws-iam-role |
environment_profiles[*].environment_blueprint_identifier |
string (blueprint id) |
aws_datazone_environment_blueprint data source (caller-resolved) |
user_profiles[*].user_identifier |
string (IAM ARN or Identity Center id) |
tf-mod-aws-iam-role, tf-mod-aws-iam-user, IAM Identity Center |
| Output | Description | Consumed by |
|---|---|---|
id |
Domain id | Every child resource's domain_identifier |
arn |
Domain ARN | IAM policies scoping datazone:* to this domain |
portal_url |
Data-portal URL | Human documentation / SSO bookmarking |
root_domain_unit_id |
Root domain-unit id | Future domain-unit modules |
project_ids / project_statuses |
Project maps keyed by caller key | Internal wiring; tf-mod-aws-lakeformation grants; audit |
environment_profile_ids |
Profile map | Internal environments wiring |
environment_ids / environment_provisioned_resources |
Environment maps | tf-mod-aws-glue/tf-mod-aws-redshift/tf-mod-aws-lakeformation |
glossary_ids / glossary_term_ids |
Glossary maps | projects[*].glossary_terms wiring; tag-based access control |
form_type_names / form_type_revisions |
Form-type composite identity | asset_types[*].forms_input wiring |
asset_type_names / asset_type_revisions |
Asset-type composite identity | Catalog automation |
user_profile_ids / user_profile_types |
User-profile maps | Access review / audit |
tags_all |
Domain's merged tags — the only taggable resource | Governance/audit |
1 · Minimal domain + project
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
core = { name = "core-catalog" }
}
}2 · `tags` merging with provider `default_tags`
provider "aws" {
default_tags {
tags = {
ManagedBy = "terraform"
CostCenter = "data-platform"
}
}
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
# Resource tags win on key conflict with default_tags; tags_all reflects the merge.
tags = {
Environment = "prod"
CostCenter = "data-governance" # overrides the provider default_tags value
}
}3 · Customer-managed KMS key (CMK) for domain encryption
module "kms" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-kms?ref=v1.0.0"
name = "datazone-catalog-cmk"
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
kms_key_identifier = module.kms.arn # PII-adjacent metadata: always supply a CMK
}4 · Secure-by-default opt-out: skipping the domain deletion check
module "datazone_sandbox" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog-sandbox"
domain_execution_role = module.iam_domain_execution_role.arn
# Opt-out — only for a throwaway sandbox domain being torn down wholesale.
# Production domains should leave this false and empty out children first.
skip_deletion_check = true
projects = {
scratch = {
name = "scratch"
skip_deletion_check = true
}
}
}5 · IAM Identity Center single sign-on
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
single_sign_on = {
type = "IAM_IDC"
user_assignment = "MANUAL" # explicit, reviewable per-user assignment (the default)
}
}6 · Environment profile + environment for a Data Lake blueprint
data "aws_datazone_environment_blueprint" "data_lake" {
domain_id = module.datazone.id
name = "DefaultDataLake"
managed = true
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
lending = { name = "lending" }
}
environment_blueprint_configurations = {
data_lake = {
environment_blueprint_identifier = data.aws_datazone_environment_blueprint.data_lake.id
enabled_regions = ["us-east-1"]
manage_access_role_arn = module.iam_manage_access_role.arn
provisioning_role_arn = module.iam_provisioning_role.arn
}
}
environment_profiles = {
lending_data_lake = {
name = "lending-data-lake-profile"
project_key = "lending"
aws_account_region = "us-east-1"
environment_blueprint_identifier = data.aws_datazone_environment_blueprint.data_lake.id
}
}
environments = {
lending_prod = {
name = "lending-prod-environment"
project_key = "lending"
environment_profile_key = "lending_data_lake"
}
}
}7 · Glossary with related terms
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
lending = { name = "lending" }
}
glossaries = {
lending_terms = {
name = "Lending Glossary"
project_key = "lending"
}
}
glossary_terms = {
borrower = {
name = "Borrower"
glossary_key = "lending_terms"
short_description = "A member entity that has received or applied for credit."
}
npi = {
name = "PII"
glossary_key = "lending_terms"
short_description = "Nonpublic personal information under privacy-regulation."
term_relations = {
classifies = [] # populated with asset-classifying term ids as the glossary matures
}
}
}
}8 · Custom form type with a Smithy model
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
lending = { name = "lending" }
}
form_types = {
npi_classification = {
name = "NpiClassificationFormType"
project_key = "lending"
description = "Classifies an asset's PII sensitivity tier."
model = {
smithy = <<-EOT
structure NpiClassificationFormType {
@required
sensitivityTier: String
containsSsn: Boolean
}
EOT
}
}
}
}9 · Custom asset type referencing the form type above
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
lending = { name = "lending" }
}
form_types = {
npi_classification = {
name = "NpiClassificationFormType"
project_key = "lending"
model = { smithy = "structure NpiClassificationFormType { @required sensitivityTier: String }" }
}
}
asset_types = {
loan_file = {
name = "LoanFile"
project_key = "lending"
description = "A governed loan-file data asset."
forms_input = [
{
map_block_key = "npi_classification"
type_identifier = "NpiClassificationFormType"
type_revision = "1"
required = true
}
]
}
}
}10 · Activating IAM and SSO user profiles
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
user_profiles = {
data_steward = {
user_identifier = module.iam_data_steward_role.arn
user_type = "IAM_USER"
}
analyst_sso = {
user_identifier = "11111111-2222-3333-4444-555555555555" # IAM Identity Center user id
user_type = "SSO_USER"
}
}
}11 · `for_each` pattern — many projects from a single caller-side map
locals {
business_units = toset(["lending", "deposits", "risk"])
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
projects = {
for bu in local.business_units : bu => {
name = bu
description = "Catalog project for the ${bu} business unit."
}
}
}12 · V2 domain requiring both execution and service roles
module "datazone_v2" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog-v2"
domain_version = "V2"
domain_execution_role = module.iam_domain_execution_role.arn
service_role = module.iam_domain_service_role.arn
}13 · `import` block — bringing an existing domain under management
import {
to = module.datazone.aws_datazone_domain.this
id = "dzd_54nakfrg9k6sri"
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog" # match the existing domain's name exactly
domain_execution_role = module.iam_domain_execution_role.arn
}14 · End-to-end composition — domain, IAM, KMS, project, blueprint, glossary, and the data-plane siblings it catalogs
module "iam_domain_execution_role" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-iam-role?ref=v1.0.0"
name = "datazone-domain-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["sts:AssumeRole", "sts:TagSession"]
Principal = { Service = "datazone.amazonaws.com" }
},
{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = { Service = "cloudformation.amazonaws.com" }
}
]
})
}
module "kms" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-kms?ref=v1.0.0"
name = "datazone-catalog-cmk"
}
module "glue" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-glue?ref=v1.0.0"
#... database/crawler backing the lending data lake...
}
module "lakeformation" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-lakeformation?ref=v1.0.0"
#... least-privilege grants scoped to module.datazone.project_ids["lending"]...
}
module "datazone" {
source = "git::https://github.com/microsoftexpert/tf-mod-aws-datazone?ref=v1.0.0"
name = "casey-catalog"
domain_execution_role = module.iam_domain_execution_role.arn
kms_key_identifier = module.kms.arn
single_sign_on = {
type = "IAM_IDC"
}
projects = {
lending = { name = "lending" }
}
glossaries = {
lending_terms = {
name = "Lending Glossary"
project_key = "lending"
}
}
glossary_terms = {
npi = {
name = "PII"
glossary_key = "lending_terms"
short_description = "Nonpublic personal information under privacy-regulation."
}
}
tags = {
Environment = "prod"
Owner = "data-governance"
}
}ℹ️ High-level grouping:
- Domain identity:
name,domain_execution_role - Domain configuration:
description,domain_version,kms_key_identifier,service_role,single_sign_on,skip_deletion_check - Child collections (
for_eachmaps):projects,environment_profiles,environments,environment_blueprint_configurations,glossaries,glossary_terms,form_types,asset_types,user_profiles - Universal:
tags,timeouts(domain-level only — see Architecture Notes for which child collections carry their own per-entrytimeouts)
- Primary:
id,arn(domain only — no child resource exposes an ARN) - Domain:
portal_url,root_domain_unit_id,domain_version - Projects:
project_ids,project_statuses - Environment profiles:
environment_profile_ids - Environments:
environment_ids,environment_provisioned_resources - Environment blueprint configurations:
environment_blueprint_configuration_blueprint_ids(reference only — this resource has no computed id/arn) - Glossaries / terms:
glossary_ids,glossary_term_ids - Form types:
form_type_names,form_type_revisions(composite identity — no synthetic id) - Asset types:
asset_type_names,asset_type_revisions(composite identity — no synthetic id) - User profiles:
user_profile_ids,user_profile_types - Tags:
tags_all(domain only)
ℹ️ No outputs are marked
sensitive— this module emits no secrets.
- ARN / ID formats: Domain
id→dzd_xxxxxxxxxxxxx;arn→arn:aws:datazone:<region>:<account_id>:domain/<id>. No child resource in this module exposes an ARN. - Only the domain is taggable — confirmed against the live v6.54.0 schema.
var.tagsflows exclusively toaws_datazone_domain.this;tags_allreflects the domain only. aws_datazone_form_typeandaws_datazone_asset_typehave noidattribute — their identity is the composite(domain_identifier, name, revision)and(domain_identifier, name)respectively. Reference them downstream byname/revision.aws_datazone_environment_blueprint_configurationexports no additional attributes at all — the(domain_id, environment_blueprint_id)pair supplied by the caller is the resource's complete identity.environment.user_parametersis FORCE-NEW — changing it destroys and recreates the environment (and whatever data-plane resources it provisioned). Treat as a planned-downtime change.domain_versionhas no supported downgrade/upgrade path in the DataZone API — treat as effectively FORCE-NEW even though the schema doesn't flag it.aws_datazone_user_profilehas no delete API — its timeouts expose onlycreate/update; removing auser_profilesentry deactivates the profile rather than truly deleting it.- Destroy ordering: a Domain (or Project) with
skip_deletion_check = false(the default) refuses to delete while it still owns child entities — Terraform's own dependency graph destroys children first in a normalterraform destroy, but a targeted destroy or console-created drift can still surface aConflictException. - No
us-east-1global-resource requirement — unlike CloudFront/ACM/WAFv2, DataZone has no global-service coupling;environment_profiles/environmentstarget a specific account/Region via plain string arguments, not a provider alias.
| Hardened default | Behavior | Opt-out / control |
|---|---|---|
| Domain encryption | kms_key_identifier = null (AWS-owned key) |
Supply a CMK ARN from tf-mod-aws-kms — recommended for any PII-adjacent domain |
| SSO user assignment | single_sign_on.user_assignment = "MANUAL" when SSO is configured — every user is an explicit, reviewable assignment |
Set user_assignment = "AUTOMATIC" — not recommended; document as a compliance exception |
| Domain/project deletion safety | skip_deletion_check = false — refuses to delete a non-empty domain/project |
skip_deletion_check = true — cascades deletion; irreversible, use only with a documented decommissioning plan |
| No implicit user activation | user_profiles defaults to {} — no principal is activated for the data portal unless explicitly named |
N/A — opt-in by design |
| Form/asset type lifecycle | status = "ENABLED" by default, matching normal operating mode |
Set status = "DISABLED" during authoring/review; understand the one-way console step required before Terraform can delete an ENABLED form type |
Other principles: one composite owns the full governance fabric so callers get a working, access-governed domain from a single call; every child collection is a map(object(...)) keyed by a caller-supplied stable string (never count), with cross-collection key references validated at the variable level; IAM roles, KMS keys, the Identity Center instance, and the underlying Glue/Redshift/Lake Formation data-plane resources are deliberately left to their dedicated sibling modules rather than duplicated here.
terraform init -backend=false
terraform validate
terraform fmt -check
terraform plan # requires valid AWS credentials (profile / SSO / OIDC) + region
terraform apply
terraform output
⚠️ Always pin the module source with?ref=v1.0.0, never a branch.
terraform init -backend=false && terraform validate— schema + reference integrity; theproject_key/glossary_key/environment_profile_keycross-field validations surface a bad key reference here, not mid-apply.terraform fmt -check— formatting.terraform planagainst a non-production account — confirm the domain'ssingle_sign_on/kms_key_identifierposture matches intent before the firstapply.- After
apply, confirmproject_ids/glossary_ids/environment_idsare populated as expected and thatenvironment_provisioned_resourcesreflects the blueprint's actual output. - Exercise a throwaway sandbox project's
skip_deletion_check = truepath before relying on it for a real decommission.
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
id = "dzd_54nakfrg9k6sri"
arn = "arn:aws:datazone:us-east-1:123456789012:domain/dzd_54nakfrg9k6sri"
portal_url = "https://dzd_54nakfrg9k6sri.datazone.us-east-1.on.aws"
root_domain_unit_id = "4z53za2s8g6zwr"
project_ids = { "lending" = "8h9j2k3l4m5n" }
glossary_ids = {}
tags_all = { "Environment" = "prod", "Owner" = "data-governance" }
ValidationExceptionon domain create citingservice_role:domain_version = "V2"requiresservice_roleto be set — this module's ownvalidation {}block should catch this atplantime; if you bypassed it via-target, supply the role and re-apply.ConflictExceptiondeleting the domain or a project: the domain/project still owns child entities. Either destroy children first (the normal Terraform dependency order) or setskip_deletion_check = truedeliberately, understanding it cascades.terraform destroyon a form type hangs or errors: the form type'sstatusisENABLED— DataZone will not let Terraform delete an enabled form type. Setstatus = "DISABLED"in a prior apply, confirm it took effect, then remove the map entry.- Perpetual diff / unexpected replace on an environment after a
user_parameterschange: this is documented, correct behavior —user_parametersis FORCE-NEW. Plan the change as a deliberate recreation, not a routine update. user_profilesentry "won't delete": there is noDeleteUserProfileAPI — removing the map entry deactivates the profile instead. This is expected DataZone behavior, not a module bug.- Tag drift warnings on the domain: a key collision between provider
default_tagsand this module'stags— resource tags win;tags_allshows the merged result. No other resource in this module can drift on tags since none are taggable. - Credential-chain failures (
NoCredentialProviders/ExpiredToken): no valid credentials resolved. SetAWS_PROFILE, refresh SSO, or confirm the OIDC role assumption targets the correct account/Region. AccessDeniedExceptionondatazone:*despite a permissive-looking policy: checkiam:PassRolescoping ondomain_execution_role/service_role/manage_access_role_arn/provisioning_role_arn— DataZone needs to pass these roles through, and a missingPassRolegrant surfaces as a DataZone-side access denial, not an IAM one.- Blueprint identifier lookups return nothing: confirm the
aws_datazone_environment_blueprintdata source is queried withmanaged = truefor AWS-managed blueprints (Data Lake, etc.) and the correctdomain_id— blueprint ids are domain-scoped.
- Terraform Registry —
hashicorp/aws:aws_datazone_domain,aws_datazone_project,aws_datazone_environment,aws_datazone_environment_profile,aws_datazone_environment_blueprint_configuration,aws_datazone_glossary,aws_datazone_glossary_term,aws_datazone_form_type,aws_datazone_asset_type,aws_datazone_user_profile - AWS — Amazon DataZone User Guide (domains, projects, environments, blueprints, business glossaries)
- AWS — Enabling AWS IAM Identity Center for DataZone
- AWS — Amazon DataZone quotas
- —
tf-mod-aws-iam-role,tf-mod-aws-kms,tf-mod-aws-glue,tf-mod-aws-redshift,tf-mod-aws-lakeformation,tf-mod-aws-s3-bucket(sibling/consuming modules)
🧡 "Infrastructure as Code should be standardized, consistent, and secure."