Managed Resources in Crossplane are the fundamental building blocks that represent cloud provider resources, but they don’t map one-to-one with cloud provider APIs in the way you might expect.
Let’s see this in action. Imagine we want to provision an AWS S3 bucket.
First, we define a Bucket custom resource (CR) in Crossplane:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: my-crossplane-managed-bucket
spec:
forProvider:
region: us-east-1
acl: private
tags:
Environment: Production
When Crossplane reconciles this Bucket resource, it doesn’t directly call the AWS S3 API with these exact fields. Instead, it interacts with a lower-level Crossplane concept called a CompositeResourceDefinition (XRD) and a CompositeResource (CR) that it manages. The Bucket CR we defined is actually an instance of a CompositeResource defined by an XRD (e.g., Bucket.s3.aws.upbound.io).
This CompositeResource is then composed of one or more Managed Resources. A Managed Resource is a Crossplane custom resource that directly corresponds to a specific cloud provider API object. For our S3 bucket example, the Bucket CR might be composed of a Bucket Managed Resource.
Here’s how the mental model breaks down:
- Application Developer: Defines a high-level, cloud-agnostic abstraction (like a
BucketCR). This abstraction is defined by an XRD. - Crossplane (Composition): Uses a Composition to translate the application developer’s
CompositeResourceinto one or more specific cloud provider resources. This is where the mapping happens. - Managed Resource (Provider): A specific Crossplane resource (e.g.,
s3.aws.upbound.io/Bucket) that has a direct, one-to-one mapping to a cloud provider API object (e.g., AWS S3CreateBucketAPI call). The Crossplane provider (e.g.,provider-aws) handles the translation between the Managed Resource’s spec and the actual API call.
So, when you create a Bucket CR, Crossplane looks up its associated Composition. That Composition specifies which Managed Resources should be created to fulfill the Bucket request. For a simple S3 bucket, the Composition might instruct Crossplane to create a single s3.aws.upbound.io/Bucket Managed Resource.
The spec.forProvider block in our Bucket CR is then translated by the Composition into the spec.forProvider of the underlying s3.aws.upbound.io/Bucket Managed Resource. The provider-aws controller then takes that Managed Resource’s spec and translates it into the actual AWS S3 API call.
The key is that the CompositeResource (your Bucket CR) provides a standardized interface, while the Composition and Managed Resources provide the cloud-specific implementation details. You can have multiple Compositions for the same XRD, allowing you to provision the same logical resource (e.g., a database) using different cloud provider implementations (e.g., RDS, Cloud SQL, Azure Database).
The spec.parameters in a Composite Resource are not directly sent to the cloud provider API. Instead, they are consumed by the Composition, which then uses them to construct the spec.forProvider of the underlying Managed Resources. The Composition logic dictates how these parameters are mapped and transformed into the cloud-specific resource specifications.
The next concept you’ll encounter is how to define your own Compositions to customize the provisioning of managed cloud resources.