Skip to content
7 min read·Lesson 5 of 8

Crossplane, Kratix, and the Control Plane Pattern

Beyond Terraform: building an internal control plane with Crossplane, Kratix, and operator patterns to expose typed infrastructure APIs to developers.

Infrastructure as code is solved — Terraform, Pulumi, and CDK all work. What is not solved is the question of how developers consume infrastructure. Handing every team a Terraform repo with cloud admin permissions does not scale and is rarely safe. The control-plane pattern is the answer the platform community has converged on.

The Idea

Build an in-cluster API that exposes higher-level resource types to developers — PostgresInstance, S3Bucket, KafkaTopic — implemented by a controller that talks to the cloud on their behalf. Developers kubectl apply a manifest; the controller reconciles. Same loop as Pods and Deployments, but for cloud resources.

This is what AWS, GCP, and Azure do internally for their own engineers. The tooling exists now to build it yourself.

Crossplane

Crossplane (CNCF Incubating, originally from Upbound) is the most widely adopted control plane framework. It works in two layers:

1. Providers and Managed Resources

A Provider is a controller that knows how to talk to a cloud. Install the AWS Provider and you get hundreds of CRDs like RDSInstance, S3Bucket, VPC:

apiVersion: rds.aws.crossplane.io/v1alpha1
kind: DBInstance
metadata:
  name: orders-db
spec:
  forProvider:
    region: eu-west-1
    dbInstanceClass: db.t4g.micro
    engine: postgres
    engineVersion: "16"
    allocatedStorage: 20
    masterUsername: orders
  providerConfigRef: { name: aws-default }

This is a one-to-one wrapper around the cloud API. Useful, but still exposes too much surface to developers.

2. Compositions and XRDs

The killer feature. Define your own abstraction:

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: postgresinstances.platform.acme.io
spec:
  group: platform.acme.io
  names:
    kind: PostgresInstance
    plural: postgresinstances
  claimNames:
    kind: Postgres
    plural: postgreses
  versions:
    - name: v1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                size: { type: string, enum: [small, medium, large] }
                region: { type: string }

Then write a Composition that says "when someone asks for a Postgres of size 'small', create an RDSInstance with these parameters, a subnet group, a security group, and a Secret with credentials." The developer's manifest becomes:

apiVersion: platform.acme.io/v1
kind: Postgres
metadata:
  name: orders-db
spec:
  size: small
  region: eu-west-1

Three lines. Behind the scenes Crossplane creates a dozen cloud resources. The developer sees only the abstraction the platform chose to expose.

Kratix and the Promise Pattern

Kratix (Syntasso) is younger and takes a different tack. Its abstraction is a Promise — a bundle that declares "I deliver a Postgres" and ships the controllers, RBAC, and templates needed to fulfil it. Promises can compose; one Promise can require another.

Kratix is multi-cluster from the ground up: a single platform cluster ("Kratix") schedules workloads onto destination clusters based on labels. Useful if your IDP serves many clusters across many regions or clouds.

Cluster API

If your control plane goal is clusters themselves, look at Cluster API (CAPI). It is a SIG-cluster-lifecycle project that exposes Cluster, MachineDeployment, MachineSet as Kubernetes resources, with providers for AWS, Azure, GCP, vSphere, bare metal. The standard way to declaratively provision and lifecycle fleets of Kubernetes clusters.

Why Bother? Trade-offs vs Terraform

ConcernTerraform / PulumiCrossplane-style control plane
Mental modelRun a CLI to plan/applykubectl apply, reconcile loop
Drift detectionPeriodic terraform planContinuous
Self-serviceDevelopers run TF (risky) or open PRsDevelopers apply a typed claim
StateExternal backend (S3, TF Cloud)Kubernetes API + cloud reality
RBACCloud IAM, TF Cloud teamsKubernetes RBAC + namespaces
Operational costLowHigher — you run controllers
Abstraction powerModules (still exposes most surface)XRDs (genuinely typed APIs)

Hybrid is common: Terraform for bootstrap (the platform cluster itself, the VPC, the IAM baseline) and Crossplane for everything developers consume.

The GitOps Combination

Crossplane CRDs are Kubernetes resources, which means they fit perfectly into Argo CD or Flux. A team's repo contains their Postgres claim; Argo CD applies it; Crossplane reconciles to AWS; the secret with credentials is written into the team's namespace; the application Pod consumes it. End to end declarative, no human "click here."

When to Reach for This

  • You serve many teams who currently provision via tickets or Terraform PRs that bottleneck on the platform team
  • You have repeated abstractions (every team's "small Postgres" looks the same)
  • You already have Kubernetes operators in production and the operational model is comfortable
  • You want a single pane (kubectl + portal) for application and infrastructure

When Not to

  • You are a small org with one cluster — overkill
  • You lack Kubernetes operational depth — running controllers that touch cloud at scale is non-trivial
  • Your cloud surface is exotic and unsupported by the Provider (compose with Terraform for the gap)

Operational Realities

  • Crossplane Providers have their own release cadence; track them like dependencies
  • Cloud-credentials handling is critical — use IRSA / workload identity, not static keys
  • Plan for backup of the Crossplane state — losing the control-plane Kubernetes cluster loses your IaC reality of record
  • For multi-region resilience, run multiple control planes — Kratix does this natively, Crossplane via federation patterns

Control planes are a powerful pattern but only if your platform team has the runway to operate them well. Used responsibly they collapse the gap between "deploy an app" and "provision a database" into a single mental model — which is the long-standing platform-engineering dream.

Key Takeaways

  • A control plane is a typed API surface for infrastructure — developers request resources via Kubernetes-native objects.
  • Crossplane is the most adopted; Kratix takes a "promise" abstraction; Cluster API does it for clusters specifically.
  • Composite resources let you define abstractions like "PostgresInstance" that bundle many cloud resources.
  • GitOps + Crossplane = declarative cloud infrastructure with the same reconciliation loop as apps.
  • Trade-off: more operational complexity, but a much cleaner developer experience than handing out Terraform.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →