Regulated Tier Blueprint¶
The Regulated tier is for organizations operating under regulatory requirements (HIPAA, FedRAMP, SOC2, financial-services mandates) that need maximum security posture: customer-managed keys, private compute, strict policy enforcement, and extended audit retention.
What This Tier Adds¶
| Addition | Description |
|---|---|
| Private AKS | Private API server, UDR egress, workload identity enabled |
| CMK encryption | Customer-managed key created in Key Vault for downstream services |
| 365-day retention | Full year of audit logs for compliance |
| Explicit policy flags | All governance flags set explicitly — no reliance on defaults |
| AKS diagnostics | Cluster logs included in diagnostics fan-out |
| Future hooks | Prepared for firewall, APIM, egress control, region restriction |
Recommended Variables¶
enable_cmk = true
enable_aks = true
enable_policy_baseline = true
log_retention_days = 365
cost_center = "CC-AI-0042"
allowed_locations = ["eastus2"]
require_private_endpoints = true
deny_public_paas = true
Future Regulated-Tier Modules¶
The following capabilities are planned for future releases:
| Module | Purpose |
|---|---|
networking/firewall |
Azure Firewall with UDR egress and FQDN application rules |
networking/apim |
API Management (internal mode) for governed AI API gateway |
networking/egress_control |
NSG flow logs, Network Watcher, traffic analytics |
governance/region_restriction |
Data replication restriction policies for data residency |
security/defender |
Defender for Cloud plans for Key Vault, Storage, Resource Manager, AKS |
identity/rbac |
Workload identities, CMK encryption roles, least-privilege operator roles |
Reference Composition¶
# =============================================================================
# TenantZero AI -- Regulated Tier Blueprint
# =============================================================================
#
# WHAT THIS IS
# ------------
# A reference composition for organizations operating under regulatory
# requirements (HIPAA, FedRAMP, SOC2, financial-services mandates) that need
# maximum security posture: customer-managed keys, private compute, strict
# policy enforcement, and extended audit retention.
#
# THIS FILE IS NOT EXECUTABLE. It is documentation that mirrors the real
# module composition pattern used by every TenantZero environment stack.
#
# WHAT FOUNDATION TIER INCLUDES
# ------------------------------
# - Foundation : naming, tags, resource_group
# - Networking : vnet, private_dns
# - Security : key_vault + private endpoint
# - AI : openai + PE, ai_search + PE
# - Data : cosmos OR postgres + PE
# - Observability: log_analytics, diagnostics
#
# WHAT ENTERPRISE TIER ADDS
# --------------------------
# + governance/policy_baseline (enabled)
# + cost_center tag (explicitly set)
# + Full diagnostics wiring
#
# WHAT THIS TIER ADDS
# -------------------
# + compute/aks_private (enabled -- private API server, UDR egress)
# + enable_cmk = true (CMK key created in Key Vault)
# + log_retention_days = 365 (1-year audit trail for compliance)
# + All policy flags explicit (no reliance on defaults)
# + AKS added to diagnostics (cluster logs sent to Log Analytics)
# + Prepared hooks for future (firewall, APIM, egress, region restriction)
#
# MODULE PATH CONVENTION
# ----------------------
# All source paths are relative to envs/<env>/ -- i.e. ../../modules/<ns>/<mod>
# =============================================================================
# -- Data source: current Azure context (tenant ID, subscription, etc.) -------
data "azurerm_client_config" "current" {}
# =============================================================================
# Local helpers
# =============================================================================
locals {
group_names = {
core = module.naming.resource_groups.core
net = module.naming.resource_groups.net
sec = module.naming.resource_groups.sec
obs = module.naming.resource_groups.obs
}
# ---------------------------------------------------------------------------
# REGULATED ADDITION: AKS requires its own private DNS zone for the
# private API server endpoint. Add it to the zone list when AKS is enabled.
# ---------------------------------------------------------------------------
private_dns_zones = concat(
[
"privatelink.openai.azure.com",
"privatelink.vaultcore.azure.net",
"privatelink.search.windows.net",
],
var.data_profile == "cosmos"
? ["privatelink.documents.azure.com"]
: ["privatelink.postgres.database.azure.com"],
var.enable_aks
? ["privatelink.${var.location}.azmk8s.io"]
: []
)
allowed_locations = length(var.allowed_locations) > 0 ? var.allowed_locations : [var.location]
cosmos_zone_id = try(module.private_dns.zone_ids["privatelink.documents.azure.com"], null)
postgres_zone_id = try(module.private_dns.zone_ids["privatelink.postgres.database.azure.com"], null)
postgres_subnet = try(module.networking.subnet_ids["snet-data"], module.networking.subnet_ids["snet-compute"])
aks_dns_zone_id = try(module.private_dns.zone_ids["privatelink.${var.location}.azmk8s.io"], null)
# ---------------------------------------------------------------------------
# REGULATED CHANGE: diagnostics_targets includes ALL resources, including
# AKS cluster and PostgreSQL when present. Every resource that supports
# diagnostic settings MUST be wired for compliance audit trails.
# ---------------------------------------------------------------------------
diagnostics_targets = compact(concat(
[
module.openai.resource_id,
module.key_vault.resource_id,
module.ai_search.resource_id,
],
var.data_profile == "cosmos"
? [module.cosmos[0].resource_id]
: [module.postgres[0].resource_id],
var.enable_aks
? [module.aks_private[0].cluster_id]
: []
))
}
# =============================================================================
# 1. FOUNDATION -- naming, tags, resource groups
# =============================================================================
module "naming" {
source = "../../modules/foundation/naming"
client_name = var.client_name # e.g. "contoso"
env = var.env # e.g. "prod"
unique_suffix = var.unique_suffix # e.g. "x7q"
}
# ---------------------------------------------------------------------------
# ENTERPRISE+REGULATED: cost_center is mandatory for chargeback tracking.
# ---------------------------------------------------------------------------
module "tags" {
source = "../../modules/foundation/tags"
client_name = var.client_name
env = var.env
cost_center = var.cost_center # e.g. "CC-AI-0042" -- required
extra_tags = var.tags
}
module "resource_groups" {
source = "../../modules/foundation/resource_group"
groups = {
core = { name = local.group_names.core, location = var.location, tags = module.tags.common_tags }
net = { name = local.group_names.net, location = var.location, tags = module.tags.common_tags }
sec = { name = local.group_names.sec, location = var.location, tags = module.tags.common_tags }
obs = { name = local.group_names.obs, location = var.location, tags = module.tags.common_tags }
}
}
# =============================================================================
# 2. NETWORKING -- VNet, subnets, NSGs, private DNS zones
# =============================================================================
# Regulated tier typically has a more segmented subnet layout:
# snet-pe -- private endpoints for PaaS services
# snet-compute -- AKS node pools
# snet-data -- PostgreSQL delegated subnet (if postgres profile)
# Ensure the VNet CIDR and subnet definitions in your tfvars accommodate
# the additional compute subnet capacity for AKS nodes.
module "networking" {
source = "../../modules/networking/vnet"
name = module.naming.vnet_name
resource_group_name = module.resource_groups.names["net"]
location = var.location
vnet_cidr = var.vnet_cidr
subnets = var.subnets
nsg_rules = var.nsg_rules
tags = module.tags.common_tags
}
module "private_dns" {
source = "../../modules/networking/private_dns"
resource_group_name = module.resource_groups.names["net"]
vnet_id = module.networking.vnet_id
zones = local.private_dns_zones # includes AKS zone when enabled
tags = module.tags.common_tags
}
# =============================================================================
# 3. SECURITY -- Key Vault + private endpoint + CMK key
# =============================================================================
module "key_vault" {
source = "../../modules/security/key_vault"
name = module.naming.key_vault_name
resource_group_name = module.resource_groups.names["sec"]
location = var.location
tenant_id = data.azurerm_client_config.current.tenant_id
tags = module.tags.common_tags
# All security defaults are already private-first:
# public_network_access_enabled = false
# enable_rbac_authorization = true
# purge_protection_enabled = true
# soft_delete_retention_days = 90
}
module "pe_key_vault" {
source = "../../modules/networking/private_endpoint"
name = "pe-${module.naming.key_vault_name}"
location = var.location
resource_group_name = module.resource_groups.names["sec"]
subnet_id = module.networking.subnet_ids["snet-pe"]
private_connection_resource_id = module.key_vault.resource_id
subresource_names = ["vault"]
private_dns_zone_ids = [module.private_dns.zone_ids["privatelink.vaultcore.azure.net"]]
tags = module.tags.common_tags
}
# ---------------------------------------------------------------------------
# REGULATED CHANGE: CMK is ENABLED. The customer-managed key is created in
# Key Vault after the private endpoint is established. Services that support
# CMK encryption (Cosmos DB, OpenAI, AI Search, PostgreSQL, AKS etcd) can
# reference azurerm_key_vault_key.cmk[0].id for their encryption config.
#
# NOTE: Some services require additional RBAC (Key Vault Crypto Service
# Encryption User) for their managed identities. Those role assignments
# will be added when the identity/rbac module is implemented.
# ---------------------------------------------------------------------------
resource "azurerm_key_vault_key" "cmk" {
count = var.enable_cmk ? 1 : 0 # Regulated: true
name = "cmk-default"
key_vault_id = module.key_vault.resource_id
key_type = "RSA"
key_size = 2048
key_opts = ["decrypt", "encrypt", "sign", "unwrapKey", "verify", "wrapKey"]
depends_on = [module.pe_key_vault]
}
# =============================================================================
# 4. AI SERVICES -- Azure OpenAI + AI Search, each with private endpoints
# =============================================================================
module "openai" {
source = "../../modules/ai/openai"
name = module.naming.openai_name
resource_group_name = module.resource_groups.names["core"]
location = var.location
sku = var.openai_sku
public_network_access_enabled = false
deployments = var.models
tags = module.tags.common_tags
}
module "pe_openai" {
source = "../../modules/networking/private_endpoint"
name = "pe-${module.naming.openai_name}"
location = var.location
resource_group_name = module.resource_groups.names["core"]
subnet_id = module.networking.subnet_ids["snet-pe"]
private_connection_resource_id = module.openai.resource_id
subresource_names = ["account"]
private_dns_zone_ids = [module.private_dns.zone_ids["privatelink.openai.azure.com"]]
tags = module.tags.common_tags
}
module "ai_search" {
source = "../../modules/ai/ai_search"
name = module.naming.ai_search_name
resource_group_name = module.resource_groups.names["core"]
location = var.location
sku = var.search_sku
replicas = var.search_replicas
partitions = var.search_partitions
public_network_access_enabled = false
tags = module.tags.common_tags
}
module "pe_ai_search" {
source = "../../modules/networking/private_endpoint"
name = "pe-${module.naming.ai_search_name}"
location = var.location
resource_group_name = module.resource_groups.names["core"]
subnet_id = module.networking.subnet_ids["snet-pe"]
private_connection_resource_id = module.ai_search.resource_id
subresource_names = ["searchService"]
private_dns_zone_ids = [module.private_dns.zone_ids["privatelink.search.windows.net"]]
tags = module.tags.common_tags
}
# =============================================================================
# 5. DATA -- Cosmos DB -or- PostgreSQL
# =============================================================================
module "cosmos" {
count = var.data_profile == "cosmos" ? 1 : 0
source = "../../modules/data/cosmos"
name = module.naming.cosmos_name
resource_group_name = module.resource_groups.names["core"]
location = var.location
tags = module.tags.common_tags
}
module "pe_cosmos" {
count = var.data_profile == "cosmos" ? 1 : 0
source = "../../modules/networking/private_endpoint"
name = "pe-${module.naming.cosmos_name}"
location = var.location
resource_group_name = module.resource_groups.names["core"]
subnet_id = module.networking.subnet_ids["snet-pe"]
private_connection_resource_id = module.cosmos[0].resource_id
subresource_names = ["Sql"]
private_dns_zone_ids = [local.cosmos_zone_id]
tags = module.tags.common_tags
}
module "postgres" {
count = var.data_profile == "postgres" ? 1 : 0
source = "../../modules/data/postgres"
name = module.naming.postgres_name
resource_group_name = module.resource_groups.names["core"]
location = var.location
delegated_subnet_id = local.postgres_subnet
private_dns_zone_id = local.postgres_zone_id
tenant_id = data.azurerm_client_config.current.tenant_id
administrator_password = var.postgres_administrator_password
tags = module.tags.common_tags
}
# =============================================================================
# 6. OBSERVABILITY -- Log Analytics workspace + diagnostic settings
# =============================================================================
# ---------------------------------------------------------------------------
# REGULATED CHANGE: log_retention_days = 365 for 1-year compliance retention.
# All deployed resources (including AKS and data stores) are wired into the
# diagnostics fan-out to ensure complete audit trail coverage.
# ---------------------------------------------------------------------------
module "log_analytics" {
source = "../../modules/observability/log_analytics"
name = module.naming.log_analytics_name
resource_group_name = module.resource_groups.names["obs"]
location = var.location
log_retention_days = var.log_retention_days # Regulated: 365
tags = module.tags.common_tags
}
module "diagnostics" {
source = "../../modules/observability/diagnostics"
# ---------------------------------------------------------------------------
# REGULATED CHANGE: diagnostics_targets includes AKS cluster_id and ALL
# data resources. This ensures every platform resource has log and metric
# forwarding for compliance audits and incident investigation.
# ---------------------------------------------------------------------------
target_resource_ids = local.diagnostics_targets
workspace_id = module.log_analytics.workspace_id
name_prefix = "diag-${module.naming.prefix}"
}
# =============================================================================
# 7. GOVERNANCE -- policy baseline (ALL FLAGS EXPLICIT)
# =============================================================================
# ---------------------------------------------------------------------------
# REGULATED CHANGE: All policy flags are set explicitly -- no reliance on
# module defaults. This makes the compliance posture auditable directly
# from the Terraform configuration without needing to inspect module code.
# ---------------------------------------------------------------------------
module "policy_baseline" {
count = var.enable_policy_baseline ? 1 : 0 # Regulated: true (always)
source = "../../modules/governance/policy_baseline"
scope = var.policy_scope != null ? var.policy_scope : module.resource_groups.ids["core"]
allowed_locations = local.allowed_locations # e.g. ["eastus2"] -- single region for data residency
require_private_endpoints = true # Explicit: audit resources without PEs
deny_public_paas = true # Explicit: block public network access on PaaS
}
# =============================================================================
# 8. COMPUTE -- Private AKS cluster (REGULATED TIER ADDITION)
# =============================================================================
# The private AKS cluster provides a secure compute plane for containerized
# AI workloads. The API server is accessible only through a private endpoint
# in the VNet. Egress uses user-defined routing (UDR) so that all outbound
# traffic can be inspected by a future firewall module.
#
# Subnet requirements:
# - snet-compute must have enough address space for AKS nodes (e.g. /22)
# - Max pods per node defaults to 30; plan IP space accordingly
#
# The cluster's system-assigned managed identity will need RBAC roles
# for pulling images (AcrPull) and managing network resources. These will
# be added when the identity/rbac module is implemented.
module "aks_private" {
count = var.enable_aks ? 1 : 0 # Regulated: true
source = "../../modules/compute/aks_private"
name = module.naming.aks_name
resource_group_name = module.resource_groups.names["core"]
location = var.location
subnet_id = module.networking.subnet_ids["snet-compute"]
private_dns_zone_id = local.aks_dns_zone_id # Private API server DNS
outbound_type = "userDefinedRouting" # Required for firewall egress
tags = module.tags.common_tags
}
# =============================================================================
# REGULATED TIER -- RECOMMENDED VARIABLE VALUES
# =============================================================================
#
# When configuring a Regulated tier environment, use these values in your
# .tfvars file:
#
# enable_cmk = true # Customer-managed encryption keys
# enable_aks = true # Private AKS compute cluster
# enable_policy_baseline = true # Full governance policy set
# log_retention_days = 365 # 1-year compliance retention
# cost_center = "CC-..." # Mandatory cost allocation
# allowed_locations = ["eastus2"] # Single-region data residency
# require_private_endpoints = true # Audit PE coverage
# deny_public_paas = true # Block public PaaS access
#
# =============================================================================
# FUTURE REGULATED-TIER MODULES (not yet implemented)
# =============================================================================
#
# The following capabilities are planned for future Regulated tier releases:
#
# networking/firewall
# Azure Firewall deployed in a dedicated snet-fw subnet. All AKS egress
# and inter-VNet traffic routes through the firewall via UDR. Application
# rules restrict outbound to approved FQDNs only (e.g. MCR, Azure APIs).
# This is why aks_private.outbound_type is set to "userDefinedRouting".
#
# networking/apim
# Azure API Management (internal mode) deployed behind the VNet. Provides
# a governed gateway for AI API consumers with rate limiting, JWT
# validation, and usage analytics. Connects to OpenAI and AI Search
# through their private endpoints.
#
# networking/egress_control
# NSG flow logs, Network Watcher, and traffic analytics. Provides
# visibility into all network flows for compliance reporting and
# anomaly detection. Integrates with Log Analytics workspace.
#
# governance/region_restriction
# Enhanced policy assignments that restrict not just resource deployment
# location but also data replication targets. Ensures data residency
# requirements are met for GDPR, data sovereignty, or sector-specific
# regulations.
#
# security/defender
# Microsoft Defender for Cloud with enhanced tier plans enabled for
# Key Vault, Storage, Resource Manager, DNS, and Kubernetes (AKS).
# Provides threat detection, vulnerability assessment, and security
# posture scoring.
#
# identity/rbac
# Comprehensive role assignments: workload identities for AKS pods
# (via workload identity federation), CMK encryption roles for service
# managed identities, and least-privilege operator roles. Eliminates
# all shared-key authentication paths.
#
# Each module will follow the established composition pattern and integrate
# with the existing naming, tagging, networking, and observability layers.