Platform Engineering 05 - Infrastructure as Code for Platforms
Infrastructure Without IaC Is a Liability
When a developer requests a PostgreSQL database, someone on the ops team often handles it by logging into the cloud console, clicking through a wizard, picking a few settings, and sending back the connection string. This works in the moment. But the problems surface when the next person requests the same thing and receives subtly different settings, or when the original database needs to be recreated and nobody remembers how it was configured.
IaC makes infrastructure declarative, versioned, and repeatable. For platform teams, this is not a matter of preference. It is the foundation that makes self-service possible in the first place.
The Abstraction Layer
Does this mean developers should write IaC directly? Not quite. If developers end up writing Terraform or Crossplane themselves, the purpose of having a platform is defeated entirely. What the platform team needs to build is an abstraction layer โ a structure where developers declare what they need, and the platform handles how it gets implemented.
Developer request: Platform translates to:
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ "I need a โ โโโ โ - RDS instance (db.t3.medium) โ
โ PostgreSQL DB, โ โ - Security group โ
โ 50GB, staging" โ โ - Subnet placement โ
โ โ โ - Backup policy (daily) โ
โ โ โ - Monitoring alerts โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
In this structure, the developer doesn't need to know about security groups or subnet placement, because the platform encodes those decisions internally. Exposing a simple interface to the developer while encapsulating complex infrastructure decisions inside the platform โ that is the core purpose of the abstraction layer.
Terraform vs Pulumi vs Crossplane
| Terraform | Pulumi | Crossplane | |
|---|---|---|---|
| Language | HCL (declarative) | Python, TypeScript, Go, etc. | YAML (Kubernetes CRDs) |
| State | State file (remote backend) | State file (Pulumi Cloud or self-hosted) | Kubernetes etcd |
| Reconciliation | Run on apply only | Run on apply only | Continuous (controller loop) |
| Best for | General-purpose IaC | Teams that prefer real code | Kubernetes-native platforms |
| Platform fit | Modules as abstractions | Components as abstractions | Compositions as abstractions |
| Learning curve | Low-medium | Depends on language | Medium-high |
There is no single correct answer among these three tools. Terraform is the most widely used starting point, with the broadest ecosystem. Crossplane excels in environments that are already Kubernetes-centric. Pulumi is an attractive option for teams that would rather not learn a separate domain-specific language.
Crossplane: Kubernetes-Native IaC
The reason Crossplane has gained attention is that it allows infrastructure provisioning to be handled in the same way as Kubernetes resources. If developers already know kubectl apply, they can use the same workflow to provision cloud resources as well โ effectively extending a familiar interface to cover infrastructure.
# Developer submits this
apiVersion: database.platform.io/v1alpha1
kind: PostgreSQL
metadata:
name: orders-db
spec:
size: medium
storage: 50Gi
environment: staging
Behind this simple manifest, a Crossplane Composition expands the request into actual cloud resources. An RDS instance, security group, and parameter group are created automatically, but the developer never has to deal with that complexity directly. They simply receive their database.
Self-Service Flow
To understand how self-service actually works in practice, consider the following sequence. First, the developer selects a resource from a catalog, which may be accessed through a UI, CLI, or YAML file. The request is then validated against the platform's policies โ size limits, naming conventions, and allowed regions are checked at this stage. Once validated, the IaC engine provisions the resource, and connection details are delivered back to the developer as secrets and endpoints. The provisioned resource then becomes trackable in the developer portal.
Through this process, the developer receives a database within minutes, while the platform team gains consistency, compliance, and an audit trail without any additional manual effort.
The Real Difference
A platform without IaC is ultimately just a ticketing system with an extra step. With IaC, true self-service becomes possible. Developers get what they need in minutes, and every resource remains consistent, auditable, and reproducible.
In the end, the presence of an abstraction layer is what separates "we use Terraform" from "we have a platform."
In the next post, we look at developer portals โ the front door where developers find services, documentation, and tools all in one place.