Infrastructure with Crossplane

KubernetesDevOps
Share on LinkedIn

Platform engineers kept a spreadsheet of "who requested which RDS instance." Terraform lived in a repo app developers could not touch; tickets took days. Crossplane moved the contract onto the cluster: developers apply a PostgreSQLInstance CR with size and environment; a Composition creates AWS RDS, security groups, and secrets. The spreadsheet died.

Crossplane extends Kubernetes to manage external infrastructure. Providers talk to AWS, GCP, Azure; Composite Resource Definitions (XRDs) define your abstractions; Compositions wire abstractions to managed resources.

Install Crossplane and provider

helm repo add crossplane-stable https://charts.crossplane.io/stable
helm install crossplane crossplane-stable/crossplane --namespace crossplane-system --create-namespace

kubectl apply -f provider-aws.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws
spec:
  package: xpkg.upbound.io/upbound/provider-aws-s3:v1.14.0

Configure provider credentials via IRSA, workload identity, or ProviderConfig secret ref—never commit keys.

Define a Composite Resource Definition

Platform team exposes simplified API:

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xpostgresinstances.platform.example.com
spec:
  group: platform.example.com
  names:
    kind: XPostgreSQLInstance
    plural: xpostgresinstances
  claimNames:
    kind: PostgreSQLInstance
    plural: postgresinstances
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                storageGB:
                  type: integer
                environment:
                  type: string
              required: [storageGB, environment]

Composition maps to cloud resources

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: aws-postgres-standard
spec:
  compositeTypeRef:
    apiVersion: platform.example.com/v1alpha1
    kind: XPostgreSQLInstance
  resources:
    - name: rds
      base:
        apiVersion: rds.aws.upbound.io/v1beta1
        kind: Instance
        spec:
          forProvider:
            engine: postgres
            instanceClass: db.t3.micro
            allocatedStorage: 20
      patches:
        - fromFieldPath: spec.storageGB
          toFieldPath: spec.forProvider.allocatedStorage

App team claim

apiVersion: platform.example.com/v1alpha1
kind: PostgreSQLInstance
metadata:
  name: orders-db
  namespace: checkout
spec:
  storageGB: 50
  environment: production
  compositionSelector:
    matchLabels:
      provider: aws

Crossplane reconciles until RDS exists; status fields surface endpoint and readiness.

GitOps integration

Store XRDs and Compositions in a platform repo; app teams commit Claims in app repos. Argo CD or Flux reconciles both. RBAC limits who can create Claims vs who can edit Compositions.

Operations

When Crossplane fits

Good: internal platform APIs, self-service databases and buckets, Kubernetes-native teams.

Poor: one-off infra, teams without K8s ops maturity, need for Terraform module marketplace day one.

Composition functions and patch-and-transform

Crossplane 1.14+ supports Composition Functions (pipeline mode) for logic that YAML patches express poorly—conditional resources, loops over parameters, validation. When a Composition grows past a few patches, refactor to a function written in Go or KCL rather than copy-pasting patch blocks. Functions run as separate pods; pin versions and test in staging like any controller upgrade.

Treat Compositions like Terraform modules: semver, changelog, and consumer Claims pinned to compositionRevisionRef when you need controlled rollouts.

Day-2 operations and drift

Managed resources expose Ready conditions—watch kubectl get managed -A in your platform dashboard. Manual edits in the AWS console create drift; enable managementPolicies and deletion policies consciously. A Claim deleted with deletionPolicy: Orphan leaves cloud resources running—good for accidental protection, bad for cost leaks.

Run regular orphaned resource audits linking cloud tags crossplane.io/claim-name to actual Claims in etcd backups.

What to measure after rollout

Track error rates, tail latency, and resource utilization for two weeks after changes land—most regressions appear under real traffic mixes, not in staging smoke tests. Keep a rollback path documented: feature flags, Helm revision, or Git revert with known good digest. Review on-call pages tied to the topic quarterly; delete alerts that never fire and add thresholds that would have caught your last incident.

Run a short blameless postmortem if production surprised you, even for minor issues. The goal is updating this runbook section with one concrete lesson per quarter so the next engineer inherits context, not just configuration snippets.

Documentation your team should maintain

Maintain a one-page runbook link from your main service README: prerequisites, owner rotation, last drill date, and known sharp edges. Link to vendor docs in the Resources section below but capture org-specific decisions (CIDR ranges, cluster names, approval gates) in internal docs that stay current. New hires should deploy a safe canary within a week using only that runbook—if they cannot, the doc is incomplete.

Pre-production checklist

Before promoting to production, walk through this list with someone who was not the primary author—fresh eyes catch assumptions.

If any item is "we will do that later," treat it as a release blocker for tier-1 services.

Common questions from reviewers

Reviewers and auditors often ask whether this approach scales with team growth and whether it fails safely. Answer explicitly in your design doc: what happens when dependencies are down, when credentials expire, and when traffic doubles overnight. Prefer defaults that deny or degrade gracefully over defaults that fail open. Document known limits (throughput ceilings, supported versions, regions) in the same place operators look during incidents—avoid scattering critical constraints across Slack threads.

Resources

Frequently asked questions

How is Crossplane different from Terraform in a Kubernetes cluster?

Crossplane represents infrastructure as Kubernetes CRDs reconciled by controllers—same reconciliation loop model as Deployments. Terraform runs plan/apply as jobs or CLI with separate state. Crossplane fits teams standardizing on kubectl, GitOps, and RBAC for infra; Terraform fits broad multi-cloud modules and mature provider ecosystems.

What is a Composite Resource in Crossplane?

An XRD defines your platform API—e.g., DatabaseInstance—with fields app teams need. A Composition templates how that CR maps to managed resources (RDS, VPC rules). Developers claim an XR; Crossplane materializes cloud objects from the Composition.

Do I still need Terraform if I adopt Crossplane?

Many organizations use both—Crossplane for app-adjacent dynamic infra inside clusters, Terraform for foundational networking and org-level landing zones. Evaluate overlap to avoid two sources of truth for the same bucket or database.

Hiring a senior Android / Flutter engineer?

I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.

Get in touch →