Infrastructure Provisioning with Crossplane

Crossplane Fundamentals

4 min read

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. :::