Infrastructure Provisioning with Crossplane
Crossplane Fundamentals
Crossplane is a CNCF incubating project that transforms your Kubernetes cluster into a universal control plane for infrastructure. It enables platform teams to offer self-service infrastructure to developers using Kubernetes-native APIs.
What is Crossplane?
Crossplane extends Kubernetes to manage any infrastructure resource—cloud services, databases, networks—using the same declarative approach you use for containers:
Traditional Infrastructure Management:
┌─────────────────────────────────────────────────────────┐
│ DEVELOPER │
│ │ │
│ ▼ │
│ "I need a database" │
│ │ │
│ ▼ │
│ [Ticket System] │
│ │ │
│ ▼ │
│ Ops Team │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ ▼ ▼ ▼ │
│ Terraform CloudFormation Manual │
│ │ │
│ Days/Weeks │
└─────────────────────────────────────────────────────────┘
With Crossplane:
┌─────────────────────────────────────────────────────────┐
│ DEVELOPER │
│ │ │
│ ▼ │
│ kubectl apply -f database.yaml │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ CROSSPLANE │ │
│ │ (Control Plane) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ ▼ ▼ ▼ │
│ AWS GCP Azure │
│ │ │
│ Minutes │
└─────────────────────────────────────────────────────────┘
Crossplane vs Terraform
Both tools manage infrastructure, but with different approaches:
| Aspect | Crossplane | Terraform |
|---|---|---|
| Runtime | Kubernetes (always running) | CLI (run on demand) |
| State | Kubernetes etcd | Terraform state file |
| Drift Detection | Continuous reconciliation | Manual terraform plan |
| API | Kubernetes API (kubectl, GitOps) | HCL/CLI |
| Abstraction | Compositions (XRDs) | Modules |
| Self-Service | Native (Kubernetes RBAC) | Requires wrapper tooling |
| GitOps | Native (ArgoCD/Flux) | Requires Atlantis/etc. |
# Crossplane continuously reconciles
# If someone manually changes a resource in AWS,
# Crossplane detects and corrects the drift automatically
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: my-database
spec:
forProvider:
dbInstanceClass: db.t3.micro
engine: postgres
# Crossplane ensures this state is always true
Installation
Install Crossplane using Helm:
# Add the Crossplane Helm repository
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
# Create namespace and install
kubectl create namespace crossplane-system
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--wait
# Verify installation
kubectl get pods -n crossplane-system
# NAME READY STATUS
# crossplane-xxxxxxxxx-xxxxx 1/1 Running
# crossplane-rbac-manager-xxxxxxxxx-xxxxx 1/1 Running
# Check Crossplane version
kubectl crossplane --version
Core Concepts
Crossplane introduces several key concepts:
# Crossplane Architecture
architecture:
providers:
description: "Connect to cloud APIs"
examples:
- provider-aws
- provider-gcp
- provider-azure
- provider-kubernetes
- provider-helm
managed_resources:
description: "Direct cloud resource mappings"
examples:
- RDSInstance (AWS)
- CloudSQLInstance (GCP)
- PostgreSQLServer (Azure)
composite_resources:
description: "Platform team abstractions"
components:
XRD: "Define the API schema"
Composition: "Define how to fulfill the API"
XR: "Instance of composite resource"
claims:
description: "Developer-facing API"
purpose: "Simplified resource requests"
Provider Architecture
Providers are the bridge between Crossplane and cloud APIs:
┌─────────────────────────────────────────────────────────┐
│ KUBERNETES CLUSTER │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Crossplane │ │ RBAC │ │
│ │ Core │ │ Manager │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ PROVIDERS │ │
│ ├─────────────┬─────────────┬─────────────────────┤ │
│ │provider-aws │provider-gcp │ provider-azure │ │
│ │ │ │ │ │
│ │ Watches: │ Watches: │ Watches: │ │
│ │ - RDSInstance│ - CloudSQL │ - SQLServer │ │
│ │ - S3Bucket │ - GKECluster│ - StorageAccount │ │
│ │ - VPC │ - VPCNetwork│ - VirtualNetwork │ │
│ └──────┬──────┴──────┬──────┴──────────┬──────────┘ │
│ │ │ │ │
└──────────┼─────────────┼──────────────────┼──────────────┘
│ │ │
▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐
│ AWS │ │ GCP │ │Azure│
│ API │ │ API │ │ API │
└─────┘ └─────┘ └─────┘
Installing a Provider
Install the AWS provider:
# provider-aws.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/upbound/provider-aws-ec2:v1.1.0
# Using family providers for modular installation
# provider-aws-ec2: EC2, VPC resources
# provider-aws-rds: RDS databases
# provider-aws-s3: S3 buckets
# Apply the provider
kubectl apply -f provider-aws.yaml
# Watch provider installation
kubectl get providers -w
# NAME INSTALLED HEALTHY PACKAGE AGE
# provider-aws True True xpkg.upbound.io/upbound/provider-aws-ec2:v1.1.0 60s
# Check provider pods
kubectl get pods -n crossplane-system | grep provider
Provider Configuration
Configure credentials for the provider:
# aws-credentials.yaml (Secret)
apiVersion: v1
kind: Secret
metadata:
name: aws-credentials
namespace: crossplane-system
type: Opaque
stringData:
credentials: |
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
---
# provider-config.yaml
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-credentials
key: credentials
# For production, use IRSA (IAM Roles for Service Accounts)
# provider-config-irsa.yaml
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: IRSA # Uses Kubernetes ServiceAccount with IAM role
Your First Managed Resource
Create an S3 bucket using Crossplane:
# s3-bucket.yaml
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: my-crossplane-bucket
spec:
forProvider:
region: us-east-1
tags:
Environment: development
ManagedBy: crossplane
providerConfigRef:
name: default
# Apply the resource
kubectl apply -f s3-bucket.yaml
# Watch the resource sync
kubectl get bucket my-crossplane-bucket -w
# NAME READY SYNCED EXTERNAL-NAME AGE
# my-crossplane-bucket True True my-crossplane-bucket 2m
# Describe for details
kubectl describe bucket my-crossplane-bucket
Resource Lifecycle
Crossplane manages the full lifecycle:
# Resource States
states:
creating:
READY: "False"
SYNCED: "False"
message: "Creating resource in cloud provider"
ready:
READY: "True"
SYNCED: "True"
message: "Resource exists and matches desired state"
out_of_sync:
READY: "True"
SYNCED: "False"
message: "Drift detected, reconciling..."
deleting:
action: "kubectl delete"
behavior: "Crossplane deletes cloud resource"
# Deletion Policy
# deletionPolicy: Delete (default) - Delete cloud resource
# deletionPolicy: Orphan - Keep cloud resource, remove from Crossplane
In the next lesson, we'll dive deep into providers and managed resources for real-world infrastructure. :::