Stage 7 · Master
Self-Service Platform API & CLI
Provisioning Infrastructure with Crossplane
Compositions, XRDs, Claims. Provision cloud resources (RDS, Redis, S3, VPC) through Kubernetes API. Composition functions for logic.
Why Crossplane?
Crossplane extends Kubernetes to provision cloud infrastructure (RDS, Redis, S3, VPC, IAM) using the same API patterns as Kubernetes resources. No Terraform state files, no separate pipeline — just kubectl apply.
| Aspect | Terraform | Crossplane |
|---|---|---|
| State | Local/remote state file | Kubernetes etcd (source of truth) |
| API | CLI + plan/apply | Kubernetes CRUD (kubectl, controllers) |
| Drift | Detected on next plan | Continuous reconciliation |
| Secrets | Separate management | Kubernetes Secrets + External Secrets |
| RBAC | Terraform Cloud/Enterprise | Kubernetes RBAC |
| Composition | Modules | Compositions + Functions (Go/TypeScript) |
| Learning Curve | HCL + provider docs | Kubernetes + Go/TypeScript |
Core Concepts: XRD, Composition, Claim
- XRD (CompositeResourceDefinition): Defines the API schema for a platform capability (e.g., PostgreSQLInstance). Cluster-scoped.
- Composition: Template that defines how to satisfy a Claim. Creates managed resources (RDS, Secret, SecurityGroup).
- Claim (Namespaced): Developer-facing resource (e.g., PostgreSQLInstanceClaim). References XRD. User creates this.
- Composite Resource (XR): Created by Composition from Claim. Cluster-scoped. Owns managed resources.
- Managed Resources: Actual cloud resources (AWS RDS, GCP CloudSQL, Azure PostgreSQL).
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: postgresqlinstances.database.platform.example.com
spec:
group: database.platform.example.com
names:
kind: PostgreSQLInstance
plural: postgresqlinstances
claimNames:
kind: PostgreSQLInstanceClaim
plural: postgresqlinstanceclaims
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
engineVersion:
type: string
enum: ["14", "15", "16"]
default: "15"
instanceClass:
type: string
enum: ["db.t3.micro", "db.t3.small", "db.t3.medium", "db.r6g.large"]
default: "db.t3.small"
storageGB:
type: integer
minimum: 20
maximum: 65536
default: 100
backupRetentionDays:
type: integer
minimum: 1
maximum: 35
default: 7
multiAZ:
type: boolean
default: true
databaseName:
type: string
pattern: "^[a-z][a-z0-9_]{0,62}$"
default: "app"
status:
type: object
properties:
endpoint:
type: string
port:
type: integer
secretRef:
type: string
XRD defines the API for PostgreSQL instances. Developers create Claims; platform defines Composition.
Writing Compositions
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgresqlinstance-aws-rds
labels:
provider: aws
database: postgresql
spec:
compositeTypeRef:
apiVersion: database.platform.example.com/v1alpha1
kind: PostgreSQLInstance
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: DBInstance
spec:
forProvider:
region: us-east-1
engine: postgres
engineVersion: "15"
instanceClass: db.t3.small
allocatedStorage: 100
storageEncrypted: true
deletionProtection: true
backupRetentionPeriod: 7
multiAZ: true
publiclyAccessible: false
vpcSecurityGroupIdRefs:
- name: sg-rds
dbSubnetGroupNameRef:
name: subnet-group
tags:
platform.example.com/managed-by: crossplane
spec:
writeConnectionSecretToRef:
namespace: crossplane-system
name: postgresql-connection
patches:
- fromFieldPath: spec.engineVersion
toFieldPath: spec.forProvider.engineVersion
policy: Optional
- fromFieldPath: spec.instanceClass
toFieldPath: spec.forProvider.instanceClass
policy: Optional
- fromFieldPath: spec.storageGB
toFieldPath: spec.forProvider.allocatedStorage
policy: Optional
- fromFieldPath: spec.backupRetentionDays
toFieldPath: spec.forProvider.backupRetentionPeriod
policy: Optional
- fromFieldPath: spec.multiAZ
toFieldPath: spec.forProvider.multiAZ
policy: Optional
- fromFieldPath: metadata.uid
toFieldPath: spec.forProvider.dbInstanceIdentifier
transforms:
- type: string
string:
fmt: "pg-%s"
percentSpecifiers:
- fromFieldPath: metadata.uid
- name: security-group
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
spec:
forProvider:
region: us-east-1
vpcIdRef:
name: platform-vpc
ingress:
- fromPort: 5432
toPort: 5432
protocol: tcp
securityGroupRef:
name: platform-apps-sg
- name: secret
base:
apiVersion: v1
kind: Secret
metadata:
namespace: crossplane-system
stringData:
username: postgres
patches:
- fromFieldPath: metadata.uid
toFieldPath: metadata.name
transforms:
- type: string
string:
fmt: "postgresql-%s-credentials"
percentSpecifiers:
- fromFieldPath: metadata.uid
connectionDetails:
- fromConnectionSecretKey: endpoint
- fromConnectionSecretKey: port
- fromConnectionSecretKey: username
- fromConnectionSecretKey: password
Composition uses function-patch-and-transform to create RDS instance, security group, and connection secret from Claim spec.
Composition Functions
Functions are container images that implement logic: conditionals, loops, math, string manipulation, external API calls. Written in Go, TypeScript, Python, or any language.
| Function | Purpose | Example |
|---|---|---|
| function-patch-and-transform | Patch resources with values from Claim | Set instance class from spec |
| function-auto-ready | Auto-set Ready condition | Mark XR ready when all managed resources ready |
| function-environment-configs | Load env-specific configs | Different VPC per environment |
| function-go-templating | Go template rendering | Complex string formatting |
| function-kustomize | Kustomize rendering | Overlay environment patches |
| function-helm | Helm chart rendering | Deploy operator via Helm |
| Custom (Go/TS/Python) | Arbitrary logic | Call external API, validate quota, generate names |
Platform API → Crossplane
Platform controller creates Claims (namespaced) when developer requests capability. Crossplane creates Composite Resource + Managed Resources. Platform controller watches Claim status for connection details.
Day 2 Operations
- Upgrades: Update Composition → Crossplane rolls managed resources (respecting disruption budgets)
- Scaling: Patch Claim spec → Crossplane updates RDS instance class
- Backups: Automated via RDS backup retention; point-in-time restore via new Claim with snapshot ID
- Rotation: Credentials in Kubernetes Secret → External Secrets Operator syncs to Vault/app
- Deletion: Delete Claim → Crossplane deletes managed resources (respecting deletionProtection)
- Drift: Crossplane reconciles continuously — manual AWS console changes reverted
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.