Crossplane Kubernetes Infrastructure Management
Crossplane Kubernetes infrastructure management extends the Kubernetes API to provision and manage cloud resources using the same declarative approach you use for containers. Therefore, platform teams can offer self-service infrastructure through standard Kubernetes tooling. This guide covers production deployment patterns for multi-cloud environments. Moreover, because every resource becomes a Kubernetes object, the control plane continuously reconciles desired state rather than running a one-shot apply and forgetting about it.
Why Kubernetes-Native Infrastructure
Terraform and Pulumi require separate toolchains, state management, and access controls from your application platform. Moreover, developers must learn additional tools and workflows to provision infrastructure. As a result, platform teams become bottlenecks for resource provisioning.
In contrast, Crossplane lets developers request infrastructure using kubectl and standard Kubernetes manifests. Consequently, the same GitOps workflows that manage applications also manage infrastructure. The deeper difference is the reconciliation model. Terraform captures state in a file that can drift from reality between runs, whereas Crossplane stores desired state in etcd and a controller actively works to converge actual cloud resources toward it. Therefore, drift correction is continuous and automatic rather than something you discover on the next plan.
Kubernetes-native infrastructure management across cloud providers
Crossplane Kubernetes Infrastructure with Compositions
Compositions define reusable infrastructure templates that abstract cloud-specific details. Specifically, a platform team creates a composition for a database that works across AWS, GCP, and Azure:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: database.platform.example.com
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: Database
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
engine: postgres
engineVersion: "16"
instanceClass: db.t3.medium
allocatedStorage: 50
publiclyAccessible: false
Developers then request databases through simple claims without knowing the underlying cloud provider. Therefore, infrastructure provisioning becomes as simple as deploying a pod.
Defining the Claim API Developers Actually Use
A Composition only does half the job; you also need a CompositeResourceDefinition (XRD) that declares the simplified API developers interact with. The XRD defines the schema and validation for the claim, while the Composition maps that claim onto concrete provider resources. Together they form the contract between platform and product teams.
# XRD: the schema platform teams expose
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.platform.example.com
spec:
group: platform.example.com
names:
kind: XDatabase
plural: xdatabases
claimNames:
kind: Database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: string
enum: ["small", "medium", "large"]
required: ["size"]
---
# What a developer writes — nothing cloud-specific
apiVersion: platform.example.com/v1alpha1
kind: Database
metadata:
name: orders-db
namespace: team-checkout
spec:
size: medium
Notice that the developer’s manifest mentions no AWS, RDS, or engine version at all. As a result, the platform team can later swap the backing resource from RDS to Aurora, or even to a GCP Cloud SQL instance, by editing the Composition while every claim stays unchanged. This indirection is the whole point of Crossplane: it turns infrastructure into a versioned internal API.
The relationship between the pieces is worth stating plainly, because it trips up newcomers. The XRD defines a Composite Resource (the cluster-scoped XDatabase) and an optional namespaced Claim (the Database a developer creates). When someone submits a claim, Crossplane creates the matching composite, then the Composition expands that composite into the real provider resources. Therefore three objects exist for every request, and understanding that chain is essential when you debug why a claim is stuck. Checking kubectl describe on the composite, rather than the claim, usually surfaces the actual provider error.
Newer Crossplane releases also support composition functions, which let you generate resources with real code or templating instead of static patches. This is a meaningful upgrade for anything beyond trivial mappings. For instance, conditionally attaching a read replica only when size is large is awkward with declarative patches but straightforward in a function. Consequently, teams with branching infrastructure logic increasingly favor functions over the older patch-and-transform style.
Provider Configuration and Authentication
Crossplane providers connect to cloud APIs using provider configs with credentials stored in Kubernetes secrets. Furthermore, IRSA on AWS and Workload Identity on GCP enable credential-free authentication. Additionally, provider packages install cloud-specific CRDs automatically.
However, managing provider versions requires careful planning. As a result, pin provider versions in production and test upgrades in staging first. The official providers are also large; installing the full AWS provider registers thousands of CRDs and noticeably increases API server memory. Therefore, prefer the smaller, service-scoped provider families (for example, an RDS-only provider) so you install just the CRDs you actually use rather than the entire cloud surface.
Multi-cloud provider configuration with unified Kubernetes control plane
GitOps Integration with ArgoCD
Crossplane resources are standard Kubernetes objects, making ArgoCD integration seamless. Specifically, infrastructure definitions live alongside application manifests in Git repositories. Moreover, ArgoCD detects drift between desired and actual infrastructure state and reconciles automatically.
For example, if someone manually changes an RDS instance size through the AWS console, Crossplane detects the drift and restores the declared configuration. Meanwhile, all changes are auditable through Git history. One caveat is worth flagging: ArgoCD and Crossplane both reconcile, so you must configure ArgoCD to ignore the status fields and provider-generated annotations that Crossplane writes back. Otherwise ArgoCD perpetually reports the resource as OutOfSync, and the two controllers fight over the same object. For a deeper treatment of this pattern, see ArgoCD GitOps for Multi-Cluster.
When Not to Use Crossplane
Crossplane is powerful, but it is not the right default for every team. If you do not already run Kubernetes, adopting it solely to provision a handful of cloud resources adds a heavy operational dependency, and a focused tool like OpenTofu will be simpler. Similarly, for one-off or rarely-changing infrastructure, the reconciliation loop offers little value over a plain declarative apply. The model shines specifically when you are building an internal developer platform with many teams requesting infrastructure repeatedly. Therefore, weigh the control plane you must now operate against the self-service value it unlocks before committing.
Production Best Practices
Monitor Crossplane with standard Kubernetes observability tools. Furthermore, implement resource quotas to prevent infrastructure sprawl. Therefore, use namespaced claims with RBAC policies that limit which teams can provision which resource types and sizes. Additionally, watch the provider controller’s reconcile latency and error metrics, because a stuck reconcile often signals expired cloud credentials or a hit API rate limit rather than a problem in your manifests.
Production Crossplane deployment with monitoring and drift detection
Related Reading:
Further Resources:
In conclusion, Crossplane Kubernetes infrastructure management unifies application and infrastructure workflows under a single API. Therefore, adopt Crossplane to give developers self-service infrastructure while maintaining platform team governance, but commit to it only when the scale of repeated provisioning justifies operating the control plane.