Crossplane Concepts
Before making any decision about Helm's role, you need to understand how Crossplane's resource model actually works. This page explains every layer — from the lowest-level Managed Resource to the highest-level Claim — with diagrams showing how they connect.
The Four Layers
Crossplane has four distinct resource types. They form a stack, but you do not have to use all four. The decision about which layers to use is the entire point of this project.
Layer 1: Managed Resources (MRs)
A Managed Resource is a 1:1 representation of a cloud resource in your Kubernetes cluster. It is the lowest-level building block and corresponds directly to an API call in the cloud provider.
What it is
- A Kubernetes Custom Resource installed by a Crossplane provider
- Maps to exactly one cloud resource (one Azure VNet, one Storage Account, etc.)
- Crossplane's controller continuously reconciles the MR's spec with the real cloud state
- If someone changes the resource in Azure portal, Crossplane detects the drift and corrects it
Real example
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
metadata:
name: myapp-dev-vnet
spec:
forProvider:
location: eastus
resourceGroupNameRef:
name: myapp-dev-rg
addressSpace:
- "10.0.0.0/16"
providerConfigRef:
name: defaultKey fields
| Field | Purpose |
|---|---|
apiVersion | Identifies the provider and API group (e.g., network.azure.upbound.io/v1beta1) |
kind | The specific Azure resource type (VirtualNetwork, Subnet, Account, etc.) |
spec.forProvider | The actual Azure resource configuration — maps to Azure Resource Manager fields |
spec.providerConfigRef | Which set of Azure credentials to use |
*Ref / *Selector fields | References to other MRs — Crossplane resolves these at runtime |
How references work
MRs reference each other using *Ref (by name) or *Selector (by label). Crossplane resolves these references and injects the actual Azure resource IDs at runtime.
This is critical: Crossplane handles the wiring, not Helm. Helm only needs to produce consistent metadata.name values. The actual Azure resource ID resolution happens in the Crossplane controller.
Lifecycle
Layer 2: Compositions
A Composition is a mapping template that tells Crossplane how to turn a high-level request (an XR) into a set of low-level Managed Resources.
What it is
- A Kubernetes resource of kind
Composition - Contains a list of
resources:— each one is a Managed Resource template - Uses
patches:to inject values from the XR into each MR template - Installed once by the platform team, consumed by many XRs
What it looks like
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: azure-network
labels:
provider: azure
spec:
compositeTypeRef:
apiVersion: platform.example.org/v1alpha1
kind: XNetwork # This Composition serves XNetwork XRs
resources:
- name: vnet
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
spec:
forProvider:
location: "" # Patched from XR
addressSpace: [] # Patched from XR
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.location
toFieldPath: spec.forProvider.location
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.cidr
toFieldPath: spec.forProvider.addressSpace[0]
- name: subnet-app
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
addressPrefixes: []
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.appSubnetCidr
toFieldPath: spec.forProvider.addressPrefixes[0]The patching model
Compositions use patches to move data between the XR (high-level) and MRs (low-level):
Patch types
| Patch Type | Direction | Use Case |
|---|---|---|
FromCompositeFieldPath | XR → MR | Push XR values into MR specs |
ToCompositeFieldPath | MR → XR | Pull MR status back into XR (e.g., connection details) |
CombineFromComposite | XR → MR | Combine multiple XR fields into one MR field |
CombineToComposite | MR → XR | Combine multiple MR fields into one XR field |
Pipeline Mode (Modern Alternative)
Crossplane v1.14+ introduced pipeline-mode Compositions that use functions instead of patch-and-transform. This is what Upbound's reference platforms use.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: azure-network-pipeline
spec:
compositeTypeRef:
apiVersion: platform.example.org/v1alpha1
kind: XNetwork
mode: Pipeline
pipeline:
- step: render
functionRef:
name: function-kcl
input:
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
spec:
source: |
# KCL code that generates MRsWARNING
Pipeline mode is more powerful but adds complexity. Stick with patch-and-transform when you have fewer than 10 resources in a Composition.
Layer 3: Composite Resource Definitions (XRDs) and Composite Resources (XRs)
XRD — the schema
A CompositeResourceDefinition (XRD) defines a new custom API type in your cluster. It creates both an XR kind (cluster-scoped) and optionally a Claim kind (namespace-scoped).
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xnetworks.platform.example.org
spec:
group: platform.example.org
names:
kind: XNetwork # The cluster-scoped XR type
plural: xnetworks
claimNames:
kind: Network # The namespace-scoped Claim type
plural: networks
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
location:
type: string
cidr:
type: string
appSubnetCidr:
type: string
required:
- location
- cidrWhat the XRD creates
When you apply an XRD, Crossplane registers two new CRDs in your cluster:
XR — an instance
An XR (Composite Resource) is a concrete instance of the type defined by an XRD. It is cluster-scoped and triggers a Composition.
apiVersion: platform.example.org/v1alpha1
kind: XNetwork
metadata:
name: prod-network
spec:
parameters:
location: westeurope
cidr: "10.30.0.0/16"
appSubnetCidr: "10.30.1.0/24"
compositionRef:
name: azure-network # Which Composition to useWhen this XR is created, Crossplane:
- Finds the Composition named
azure-network(or selects one via labels) - Renders all the MR templates in that Composition
- Applies patches to inject the XR's
spec.parametersinto each MR - Creates the MRs in the cluster
- Crossplane's provider controllers reconcile those MRs against Azure
Layer 4: Claims
A Claim is a namespace-scoped request for a Composite Resource. It is the interface that application teams use — they never see MRs or Compositions.
apiVersion: platform.example.org/v1alpha1
kind: Network # This is the Claim kind (from XRD.spec.claimNames)
metadata:
name: my-network
namespace: team-alpha # Claims live in namespaces
spec:
parameters:
location: eastus
cidr: "10.10.0.0/16"
appSubnetCidr: "10.10.1.0/24"Claim vs XR
| Aspect | Claim | XR |
|---|---|---|
| Scope | Namespace | Cluster |
| Created by | Application teams | Platform teams (or by Claims) |
| Visibility | Only sees own namespace | Sees all resources cluster-wide |
| Name | Network (from claimNames) | XNetwork (from names) |
| Use case | Multi-tenant, RBAC-controlled | Single-tenant, admin access |
The full flow
Which Layers Does This Project Use?
Layer 1 only — Managed Resources.
Helm replaces Layers 2-4. Instead of XRDs + Compositions + Claims, Helm's values.yaml is your parameterization layer and templates/ render the MRs directly.
This means:
- No XRDs to write or maintain
- No Compositions to debug
- No Claim/XR indirection
- Full visibility into every Azure resource
helm templateshows you exactly what will be applied
The trade-off is documented in When to Abstract — there are concrete conditions under which you should graduate to Compositions.
Glossary
| Term | Full Name | What It Is |
|---|---|---|
| MR | Managed Resource | 1:1 map to a cloud resource. Installed by providers. |
| XRD | CompositeResourceDefinition | Schema that defines a new custom API type. Creates XR + Claim CRDs. |
| XR | Composite Resource | Cluster-scoped instance of an XRD. Triggers a Composition. |
| Claim | Claim | Namespace-scoped request for an XR. Consumer-facing interface. |
| Composition | Composition | Template mapping XR fields to MR specs via patches. |
| Provider | Provider | Crossplane package that installs MR CRDs (e.g., provider-azure-network). |
| ProviderConfig | ProviderConfig | Credentials configuration for a provider. |
forProvider | — | The spec block containing cloud-specific configuration. |
*Ref | Reference | Crossplane-native cross-resource reference resolved at runtime. |
*Selector | Selector | Label-based cross-resource reference resolved at runtime. |