Deployment Model
The platform deploys across three independent Terraform layers, each with its own state and lifecycle.
Deployment Layers

Infrastructure
Provisioned by azd provision via Terraform in infra/.

Azure resources are provisioned directly. AKS Managed Add-ons are enabled on the cluster and managed by Azure, not by Terraform lifecycle.
An optional access-bootstrap layer (infra-access/) separates privileged Azure authorization (RBAC grants, policy exemptions, DNS roles) from core infrastructure so it can be applied by a different identity.
Foundation
Deployed by the post-provision hook via Terraform in software/foundation/.

Bootstrap operators are installed via Helm. Shared primitives are applied via kubectl_manifest to establish CRDs, the base gateway, and storage classes that all stacks depend on.
Software Stack
Deployed by the pre-deploy hook via Terraform in software/stack/.

Middleware and OSDU services share a single Terraform state because services have explicit depends_on relationships with middleware modules. Each service is toggled independently via feature flags.
Why this split?
The AKS cluster must exist before any Kubernetes resources can be deployed. Foundation components (operators, CRDs, StorageClasses) are cluster-wide singletons that all stacks share. The software stack deploys instances and services that can vary per stack.
Evolution
The original design used two Terraform states (see ADR-0003); the foundation layer was extracted later to improve lifecycle isolation.
Namespace Architecture
Each layer deploys into a dedicated namespace. Named stacks append a suffix for isolation (see ADR-0017):
Cluster-wide operators (cert-manager, ECK, CNPG), Gateway CRDs, and StorageClasses.
- Istio injection: N/A (operators run outside the mesh)
- Shared across all stacks — never suffixed with a stack name
Middleware instances: Elasticsearch, PostgreSQL, Redis, RabbitMQ, MinIO, Keycloak, Airflow.
- Istio injection: Enabled (STRICT mTLS, with pod-level opt-outs)
- Named stacks get
platform-{name}(e.g.,platform-blue)
OSDU common resources and all OSDU services.
- Istio injection: Enabled (STRICT mTLS)
- Named stacks get
osdu-{name}(e.g.,osdu-blue)
Multi-Stack Deployment
Multiple OSDU instances can share the same cluster. Each stack gets isolated namespaces and its own middleware, while the foundation layer is shared.
# Deploy the default stack
azd deploy
# Deploy a second stack
azd env set STACK_NAME blue
azd deploy
Each stack maintains its own Terraform state. Foundation resources (operators, CRDs) are managed once.
Deployment Flow
The deployment lifecycle is orchestrated by Azure Developer CLI (azd) hooks. Each hook maps to a PowerShell script that manages a specific deployment phase:

Why a gate? Azure Policy/Gatekeeper is eventually consistent. Fresh clusters have a window where policies aren't fully reconciled. The post-provision hook makes safeguards readiness an explicit gate before deploying any workloads (see ADR-0007).
Lifecycle Scripts
Each azd hook maps to a PowerShell script in scripts/. These scripts bridge the gap between azd's lifecycle model and the multi-layer Terraform architecture.
| Script | Hook | Purpose |
|---|---|---|
| resolve-chart-versions | prerestore | Query OCI registry for latest chart versions |
| pre-provision | preprovision | Validate prerequisites, auto-generate credentials |
| bootstrap-access | manual | RBAC grants, policy exemptions, DNS roles |
| post-provision | postprovision | Wait for safeguards, deploy foundation layer |
infra-access bootstrap
bootstrap-access.ps1 runs manually because it requires elevated Azure permissions. See ADR-0020.
| Script | Hook | Purpose |
|---|---|---|
| pre-deploy | predeploy | Deploy software stack: middleware + OSDU services |
| Script | Hook | Purpose |
|---|---|---|
| pre-down | predown | Destroy stack and foundation before cluster teardown |
| post-down | postdown | Clean up .terraform directories and stale state |
External Access
When DNS and ingress are configured, the gateway module exposes multiple endpoints externally via HTTPS with automatic TLS certificates (cert-manager + Let's Encrypt):
| Endpoint | Hostname | Purpose |
|---|---|---|
| OSDU API | {prefix}.{zone} | Path-based routing to all enabled OSDU services |
| Kibana | {prefix}-kibana.{zone} | Elasticsearch/Kibana dashboard |
| Keycloak | {prefix}-keycloak.{zone} | Identity provider admin console and token endpoint |
| Airflow | {prefix}-airflow.{zone} | DAG monitoring and task execution UI (optional) |
Each endpoint is optional, independently exposed, and backed by its own Gateway API HTTPS listener, HTTPRoute, TLS Certificate, and cross-namespace ReferenceGrants.
Repository Structure
The repository layout mirrors the deployment layers. Each directory maps to a Terraform state with its own lifecycle.

See also
- Infrastructure — AKS Automatic, node pools, networking, and Azure resource configuration
- Platform Services — middleware components deployed on the cluster
- Service Architecture — how OSDU services are deployed, configured, and bootstrapped