Module Catalog — Multicloud Network + Cluster Provisioning
This is the target catalog of reusable Terraform module repos for BYOC network and Kubernetes cluster provisioning, across AWS, Azure, and GCP. Only the AWS VPC/EKS modules exist today (terraform-workspace-infra-aws and terraform-cogrion-aws-eks-managed-node-group, see Overview); the rest of this catalog is the planned shape, not yet built.
cogrion-terraform stays root/live config only — it consumes these modules, it is never itself a module source.
Split vs combine rule
Combine two pieces of infrastructure into one module (one state) only if all three hold:
- Always created/destroyed together — no scenario where one exists without the other
- Zero other consumers — nothing else in the platform depends on either piece independently
- The separation is purely artificial — the only reason they were split was to avoid a
terraform_remote_statechicken-and-egg problem, not a real lifecycle difference
If any of the three fails, split the modules. Lifecycle divergence and blast-radius containment win over convenience — a module that's easy to write is not the goal; a module whose blast radius matches its actual failure domain is.
This is the same reasoning terraform-cogrion-aws-eks-managed-node-group already applies as a deliberate exception (see below) — worth stating as a rule now that the catalog is expanding to more modules and more clouds, so future splits/combines get decided consistently instead of case-by-case.
Multicloud network
BYOC network layer per cloud — subnets, routing, private connectivity for the cluster and its dependencies. Long-lived, independent lifecycle from any cluster: other consumers (RDS, VPC endpoints, multi-cluster tenants) are expected, so these never collapse into a cluster module under the rule above.
| Repo | Cloud | Scope |
|---|---|---|
terraform-cogrion-aws-vpc | AWS | Subnets (public/private/pod), NAT, route tables, VPC endpoints for EKS/ECR/S3 |
terraform-cogrion-azure-vnet | Azure | Subnets, NSGs, route tables, private endpoints for ACR/Key Vault — mirrors AWS subnet topology for cross-cloud KCL parity |
terraform-cogrion-gcp-vpc | GCP | Subnets, Cloud NAT, firewall rules, Private Service Connect for GKE |
Multicloud cluster
Cluster control plane and node provisioning per cloud. Each cluster module consumes its cloud's network module via a one-directional data-source/tag lookup — never terraform_remote_state — since the network's lifecycle (rule #1 above) doesn't match the cluster's (recreation for major version upgrades, blue/green).
| Repo | Cloud | Scope |
|---|---|---|
terraform-cogrion-aws-eks-cluster | AWS | EKS control plane only (wraps terraform-aws-eks) — OIDC provider, core addons (VPC CNI, CoreDNS, kube-proxy), access entries |
terraform-cogrion-aws-eks-managed-node-group | AWS | (existing, unchanged) Bootstrap/system node group — see note below on why this one combines cluster + bootstrap as a deliberate exception |
terraform-cogrion-azure-aks-cluster | Azure | AKS control plane only — managed identity, OIDC issuer for workload identity federation |
terraform-cogrion-azure-aks-node-pool | Azure | System + workload node pool taxonomy, spot/priority config, taints/labels matching AWS NodePool conventions (exact-match keys) |
terraform-cogrion-gcp-gke-cluster | GCP | GKE control plane only (Autopilot + Standard variants) — Workload Identity Federation, private cluster config, release channel pinning |
terraform-cogrion-gcp-gke-node-pool | GCP | System + workload node pool taxonomy, Standard variant only (Autopilot doesn't expose node pool control) — same taint/label conventions as AWS/Azure |
Node pools are split from their cluster module on every cloud except the AWS exception below: node pools scale and change independently of the control plane, so they fail rule #1.
Why terraform-cogrion-aws-eks-managed-node-group combines cluster + bootstrap
This repo already merges what would otherwise be a cluster module and a bootstrap/node-group module into one state — a deliberate exception to the split-by-lifecycle rule above, justified because:
- Bootstrap has zero other consumers (rule #2) — nothing else in the platform stands up bootstrap workloads independently of a cluster
- Bootstrap always shares fate with its cluster (rule #1) — there's no scenario where the system node group exists without the EKS control plane it bootstraps
- The old split (
terraform-workspace-infra-aws'sworkspace-cluster+workspace-cluster-bootstrap) existed only because of aterraform_remote_statechicken-and-egg problem between the two (rule #3) — a purely artificial reason, not a real lifecycle difference
Karpenter takes over all workload-node provisioning after bootstrap, so this module's node group is scoped to system/bootstrap nodes only — not a general-purpose node pool module, which is why it doesn't set the pattern for Azure/GCP's separate node-pool repos above.
Multicloud identity and access
Cross-account/subscription/project trust setup so the control plane can operate against customer-owned cloud accounts without long-lived keys.
| Repo | Cloud | Scope |
|---|---|---|
terraform-cogrion-aws-cross-account-role | AWS | Cross-account IAM role for enable_customer_managed_account — scoped trust policy for the control plane to assume into customer-provisioned AWS accounts, least-privilege per BYOC operation type (deploy, read, drain) |
terraform-cogrion-azure-cross-subscription-role | Azure | Custom RBAC role + assignment for the Cogrion service principal against customer subscriptions, scoped to resource group |
terraform-cogrion-gcp-cross-project-role | GCP | Custom IAM role + service account impersonation binding against customer-owned projects, no long-lived keys |
terraform-cogrion-multicloud-workload-identity | All | Thin wrapper normalizing OIDC/workload-identity federation (IRSA / Azure Workload Identity / GCP Workload Identity Federation) so platform-agent and in-cluster services get one interface regardless of cloud |
Multicloud DNS and edge
| Repo | Scope |
|---|---|
terraform-cogrion-multicloud-dns-delegation | Sibling-label DNS delegation (generalizes the Route53/Cloudflare pattern) — per-region, per-cloud zone delegation without nested zone-cut conflicts |
terraform-cogrion-multicloud-lb-ingress | Normalizes external load balancer provisioning (ALB/NLB, Azure LB, GCP LB) feeding cluster ingress — single interface for KCL templates regardless of cloud |
Supporting platform modules
Infra prerequisites for platform components that aren't network/cluster/identity but still need per-tenant or per-region Terraform-managed resources.
| Repo | Scope |
|---|---|
terraform-cogrion-aws-openbao-backend | Per-tenant OpenBao storage backend — Raft + S3 snapshot config, KMS-backed unseal, blast-radius isolation per tenant |
terraform-cogrion-aws-keycloak-infra | Infra prerequisites for the Keycloak Helm deploy (RDS/Aurora if moving off the embedded DB, backup config) — does not manage realms, that stays in ArgoCD PostSync + kcadm.sh, a separate concern |
terraform-cogrion-aws-observability-backend | Per-region Loki/OpenObserve S3 backend + IAM, matching the fan-out-at-read-time architecture that avoids cross-region ingestion |
terraform-cogrion-multicloud-codeartifact-registry | Package registry provisioning (AWS CodeArtifact today, abstracted for future Azure Artifacts/Artifact Registry parity) for @cogrion/platform-core distribution |
terraform-cogrion-multicloud-secrets-sync | Cross-cloud secret sync scaffolding — replicates OpenBao-issued secrets into cloud-native stores (Secrets Manager/Key Vault/Secret Manager) where tenant tooling needs native integration instead of ESO-direct |