Skip to content

Deployment Model

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

Deployment Layers

Deployment Layers Overview

Infrastructure

Provisioned by azd provision via Terraform in infra/.

Infrastructure Components

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/.

Foundation Components

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/.

Software Stack Components

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:

Deployment Flow

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.

Project Structure

See also