Crossplane Concepts
Crossplane transforms your Kubernetes cluster into a universal control plane for infrastructure. Instead of using vendor-specific tools (Terraform CLI, AWS Console, gcloud), you declare infrastructure as Kubernetes custom resources and let Crossplane reconcile them into real cloud resources.
kubectl workflows, RBAC, and GitOps pipelines you already use for applications.
- Providers — Extend the Kubernetes API with CRDs for a specific cloud (AWS, GCP, Azure). Each Provider installs hundreds of new resource types
- Managed Resources — Individual cloud resources represented as Kubernetes objects (e.g., an S3 Bucket, a CloudSQL Instance)
- ProviderConfig — Credentials and configuration for authenticating to the cloud provider
- Compositions — Templates that combine multiple Managed Resources into reusable blueprints (covered in Part 2)
Install Crossplane
Crossplane installs into its own namespace and runs as a set of controllers that watch for infrastructure CRDs:
# Add the Crossplane Helm repository
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
# Install Crossplane into the crossplane-system namespace
helm install crossplane crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set args='{"--enable-usages"}'
# Verify the installation
kubectl get pods -n crossplane-system
# Expected: crossplane and crossplane-rbac-manager pods Running
# Check Crossplane version
kubectl get deployment crossplane -n crossplane-system \
-o jsonpath='{.spec.template.spec.containers[0].image}'
Configure a Provider
Providers are Crossplane packages that install cloud-specific CRDs and controllers. After installing a Provider, you configure it with credentials via a ProviderConfig:
# Install the AWS Provider
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.7.0
runtimeConfigRef:
name: default
# Apply the Provider
kubectl apply -f provider-aws-s3.yaml
# Wait for the Provider to become healthy
kubectl get providers.pkg.crossplane.io
# NAME INSTALLED HEALTHY PACKAGE AGE
# provider-aws-s3 True True xpkg.upbound.io/upbound/provider-aws-s3:v1.7.0 60s
# Create a credentials Secret for AWS
kubectl create secret generic aws-credentials \
-n crossplane-system \
--from-file=credentials=./aws-credentials.txt
# Configure the Provider with credentials
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-credentials
key: credentials
Managed Resources
With the Provider installed and configured, you can create Managed Resources — Kubernetes objects that map 1:1 to cloud resources. Crossplane continuously reconciles desired state with actual cloud state.
# Create an S3 Bucket as a Managed Resource
apiVersion: s3.aws.upbound.io/v1beta2
kind: Bucket
metadata:
name: my-crossplane-bucket
spec:
forProvider:
region: us-east-1
tags:
Environment: production
ManagedBy: crossplane
providerConfigRef:
name: default
# Apply and observe the resource
kubectl apply -f bucket.yaml
# Check the status
kubectl get bucket my-crossplane-bucket
# NAME READY SYNCED EXTERNAL-NAME AGE
# my-crossplane-bucket True True my-crossplane-bucket 2m
# Describe for detailed conditions
kubectl describe bucket my-crossplane-bucket
# Delete the cloud resource by deleting the K8s object
kubectl delete bucket my-crossplane-bucket
Resource Status & Readiness
Every Managed Resource reports its state through standard Kubernetes conditions. The two critical conditions are Synced (Crossplane successfully communicated with the cloud API) and Ready (the cloud resource is available for use).
kubectl apply, a resource transitions: Synced=False → Synced=True, Ready=False → Ready=True. If provisioning fails, Synced shows the error. The external-name annotation stores the cloud-side identifier (ARN, resource ID).
# Watch resource conditions in real-time
kubectl get bucket -w
# Query specific conditions
kubectl get bucket my-crossplane-bucket -o jsonpath='{.status.conditions}'
# Check the external-name (cloud resource identifier)
kubectl get bucket my-crossplane-bucket \
-o jsonpath='{.metadata.annotations.crossplane\.io/external-name}'
# List all managed resources across all types
kubectl get managed
Exercises
provider-aws-s3 and configure it with AWS credentials (use localstack for a free local AWS simulation). Create an S3 Bucket Managed Resource and verify it reaches Ready=True and Synced=True status.
provider-aws-rds). Create an RDS Instance Managed Resource with spec.forProvider specifying engine, instanceClass, and masterUsername. Observe the provisioning lifecycle and check the external-name annotation once ready.
kubectl describe to observe the reconciliation event.
Key Takeaways & Next Steps
- Crossplane turns Kubernetes into a control plane for cloud infrastructure
- Providers install CRDs for specific cloud services; ProviderConfig supplies credentials
- Managed Resources are 1:1 mappings to cloud resources with continuous reconciliation
- Synced and Ready conditions report provisioning status; external-name stores the cloud ID
- Drift detection automatically corrects manual changes to match declared state
Next in the Series
In Part 2: Compositions & XRDs, we'll define reusable infrastructure blueprints using Compositions and expose simplified platform APIs via CompositeResourceDefinitions.