--- title: Managed Resources weight: 10 description: "Managed resources are the Crossplane representation of external provider resources" --- A _managed resource_ (`MR`) represents an external service in a Provider. When users create a new managed resource, the Provider reacts by creating an external resource inside the Provider's environment. Every external service managed by Crossplane maps to a managed resource. {{< hint "note" >}} Crossplane calls the object inside Kubernetes a _managed resource_ and the external object inside the Provider an _external resource_. {{< /hint >}} Examples of managed resources include: * Amazon AWS EC2 [`Instance`](https://marketplace.upbound.io/providers/upbound/provider-aws/latest/resources/ec2.aws.upbound.io/Instance/v1beta1) * Google Cloud GKE [`Cluster`](https://marketplace.upbound.io/providers/upbound/provider-gcp/latest/resources/container.gcp.upbound.io/Cluster/v1beta1) * Microsoft Azure PostgreSQL [`Database`](https://marketplace.upbound.io/providers/upbound/provider-azure/latest/resources/dbforpostgresql.azure.upbound.io/Database/v1beta1) {{< hint "tip" >}} You can create individual managed resources, but Crossplane recommends using [Compositions]({{}}) and Claims to create managed resources. {{< /hint >}} ## Managed resource fields The Provider defines the group, kind and version of a managed resource. The Provider also define the available settings of a managed resource. ### Group, kind and version Each managed resource is a unique API endpoint with their own group, kind and version. For example the [Upbound AWS Provider](https://marketplace.upbound.io/providers/upbound/provider-aws/latest/) defines the {{}}Instance{{}} kind from the group {{}}ec2.aws.upbound.io{{}} ```yaml {label="gkv",copy-lines="none"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Instance ``` ### deletionPolicy A managed resource's `deletionPolicy` tells the Provider what to do after deleting the managed resource. If the `deletionPolicy` is `delete` the Provider deletes the external resource as well. If the `deletionPolicy` is `orphan` the Provider deletes the managed resource but doesn't delete the external resource. #### Options * `deletionPolicy: Delete` - **Default** - Delete the external resource when deleting the managed resource. * `deletionPolicy: Orphan` - Leave the external resource when deleting the managed resource. #### Interaction with management policies The [management policy](#managementpolicies) takes precedence over the `deletionPolicy` when: - The related management policy alpha feature is enabled. - The resource configures a management policy other than the default value. See the table below for more details. {{< table "table table-sm table-hover">}} | managementPolicies | deletionPolicy | result | |-----------------------------|------------------|---------| | "*" (default) | Delete (default) | Delete | | "*" (default) | Orphan | Orphan | | contains "Delete" | Delete (default) | Delete | | contains "Delete" | Orphan | Delete | | doesn't contain "Delete" | Delete (default) | Orphan | | doesn't contain "Delete" | Orphan | Orphan | {{< /table >}} ### forProvider The {{}}spec.forProvider{{}} of a managed resource maps to the parameters of the external resource. For example, when creating an AWS EC2 instance, the Provider supports defining the AWS {{}}region{{}} and the VM size, called the {{}}instanceType{{}}. {{< hint "note" >}} The Provider defines the settings and their valid values. Providers also define required and optional values in the `forProvider` definition. Refer to the documentation of your specific Provider for details. {{< /hint >}} ```yaml {label="forProvider",copy-lines="none"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Instance # Removed for brevity spec: forProvider: region: us-west-1 instanceType: t2.micro ``` {{< hint "important">}} Crossplane considers the `forProvider` field of a managed resource the "source of truth" for external resources. Crossplane overrides any changes made to an external resource outside of Crossplane. If a user makes a change inside a Provider's web console, Crossplane reverts that change back to what's configured in the `forProvider` setting. {{< /hint >}} #### Referencing other resources Some fields in a managed resource may depend on values from other managed resources. For example a VM may need the name of a virtual network to use. Managed resources can reference other managed resources by external name, name reference or selector. ##### Matching by external name When matching a resource by name Crossplane looks for the name of the external resource in the Provider. For example, a AWS VPC object named `my-test-vpc` has the external name `vpc-01353cfe93950a8ff`. ```shell {copy-lines="1" kubectl get vpc NAME READY SYNCED EXTERNAL-NAME AGE my-test-vpc True True vpc-01353cfe93950a8ff 49m ``` To match the VPC by name, use the external name. For example, creating a Subnet managed resource attached to this VPC. ```yaml {copy-lines="none"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Subnet spec: forProvider: # Removed for brevity vpcId: vpc-01353cfe93950a8ff ``` ##### Matching by name reference To match a resource based on the name of the managed resource and not the external resource name inside the Provider, use a `nameRef`. For example, a AWS VPC object named `my-test-vpc` has the external name `vpc-01353cfe93950a8ff`. ```shell {copy-lines="1"} kubectl get vpc NAME READY SYNCED EXTERNAL-NAME AGE my-test-vpc True True vpc-01353cfe93950a8ff 49m ``` To match the VPC by name reference, use the managed resource name. For example, creating a Subnet managed resource attached to this VPC. ```yaml {copy-lines="none"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Subnet spec: forProvider: # Removed for brevity vpcIdRef: name: my-test-vpc ``` ##### Matching by selector Matching by selector is the most flexible matching method. {{}} The [Compositions]({{}}) section covers the `matchControllerRef` selector. {{}} Use `matchLabels` to match the labels applied to a resource. For example, this Subnet resource only matches VPC resources with the label `my-label: label-value`. ```yaml {copy-lines="none"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Subnet spec: forProvider: # Removed for brevity vpcIdSelector: matchLabels: my-label: label-value ``` #### Immutable fields Some providers don't support changing the fields of some managed resources after creation. For example, you can't change the `region` of an Amazon AWS `RDSInstance`. These fields are _immutable fields_. Amazon requires you delete and recreate the resource. Crossplane allows you to edit the immutable field of a managed resource, but doesn't apply the change. Crossplane never deletes a resource based on a `forProvider` change. {{}} Crossplane behaves differently than other tools like Terraform. Terraform deletes and recreates a resource to change an immutable field. Crossplane only deletes an external resource if their corresponding managed resource object is deleted from Kubernetes and the `deletionPolicy` is `delete`. {{< /hint >}} #### Late initialization Crossplane treats the managed resource as the source of truth by default; it expects to have all values under `spec.forProvider` including the optional ones. If not provided, Crossplane populates the empty fields with the values assigned by the provider. For example, consider fields such as `region` and `availabilityZone`. You might specify only the region and let the cloud provider choose the availability zone. In this case, if the provider assigns an availability zone, Crossplane uses that value to populate the `spec.forProvider.availabilityZone` field. {{}} With [managementPolicies]({{}}), this behavior can be turned off by not including the `LateInitialize` policy in the `managementPolicies` list. {{< /hint >}} ### initProvider {{}} The managed resource `initProvider` option is a beta feature related to [managementPolicies]({{}}). {{< /hint >}} The {{}}initProvider{{}} defines settings Crossplane applies only when creating a new managed resource. Crossplane ignores settings defined in the {{}}initProvider{{}} field that change after creation. {{}} Settings in `forProvider` are always enforced by Crossplane. Crossplane reverts any changes to a `forProvider` field in the external resource. Settings in `initProvider` aren't enforced by Crossplane. Crossplane ignores any changes to a `initProvider` field in the external resource. {{}} Using `initProvider` is useful for setting initial values that a Provider may automatically change, like an auto scaling group. For example, creating a {{}}NodeGroup{{}} with an initial {{}}desiredSize{{}}. Crossplane doesn't change the {{}}desiredSize{{}} setting back when an autoscaler scales the Node Group external resource. {{< hint "tip" >}} Crossplane recommends configuring {{}}managementPolicies{{}} without `LateInitialize` to avoid conflicts with `initProvider` settings. {{< /hint >}} ```yaml {label="initProvider",copy-lines="none"} apiVersion: eks.aws.upbound.io/v1beta1 kind: NodeGroup metadata: name: sample-eks-ng spec: managementPolicies: ["Observe", "Create", "Update", "Delete"] initProvider: scalingConfig: - desiredSize: 1 forProvider: region: us-west-1 scalingConfig: - maxSize: 4 minSize: 1 ``` ### managementPolicies {{}} The managed resource `managementPolicies` option is an alpha feature. The Provider determines support for management policies. Refer to the Provider's documentation to see if the Provider supports management policies. {{< /hint >}} Crossplane {{}}managementPolicies{{}} determine which actions Crossplane can take on a managed resource and its corresponding external resource. Apply one or more {{}}managementPolicies{{}} to a managed resource to determine what permissions Crossplane has over the resource. For example, give Crossplane permission to create and delete an external resource, but not make any changes, set the policies to {{}}["Create", "Delete", "Observe"]{{}}. ```yaml {label="managementPol1"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Subnet spec: managementPolicies: ["Create", "Delete", "Observe"] forProvider: # Removed for brevity ``` The default policy grants Crossplane full control over the resources. Defining the `managementPolicies` field with an empty array [pauses](#paused) the resource. {{}} The Provider determines support for management policies. Refer to the Provider's documentation to see if the Provider supports management policies. {{< /hint >}} Crossplane supports the following policies: {{}} | Policy | Description | | --- | --- | | `*` | _Default policy_. Crossplane has full control over a resource. | | `Create` | If the external resource doesn't exist, Crossplane creates it based on the managed resource settings. | | `Delete` | Crossplane can delete the external resource when deleting the managed resource. | | `LateInitialize` | Crossplane initializes some external resource settings not defined in the `spec.forProvider` of the managed resource. See [the late initialization]({{}}) section for more details. | | `Observe` | Crossplane only observes the resource and doesn't make any changes. Used for [observe only resources]({{}}). | | `Update` | Crossplane changes the external resource when changing the managed resource. | {{
}} The following is a list of common policy combinations: {{}} | Create | Delete | LateInitialize | Observe | Update | Description | | :---: | :---: | :---: | :---: | :---: | --- | | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | _Default policy_. Crossplane has full control over the resource. | | ✔️ | ✔️ | ✔️ | ✔️ | | After creation any changes made to the managed resource aren't passed to the external resource. Useful for immutable external resources. | | ✔️ | ✔️ | | ✔️ | ✔️ | Prevent Crossplane from managing any settings not defined in the managed resource. Useful for immutable fields in an external resource. | | ✔️ | ✔️ | | ✔️ | | Crossplane doesn't import any settings from the external resource and doesn't push changes to the managed resource. Crossplane recreates the external resource if it's deleted. | | ✔️ | | ✔️ | ✔️ | ✔️ | Crossplane doesn't delete the external resource when deleting the managed resource. | | ✔️ | | ✔️ | ✔️ | | Crossplane doesn't delete the external resource when deleting the managed resource. Crossplane doesn't apply changes to the external resource after creation. | | ✔️ | | | ✔️ | ✔️ | Crossplane doesn't delete the external resource when deleting the managed resource. Crossplane doesn't import any settings from the external resource. | | ✔️ | | | ✔️ | | Crossplane creates the external resource but doesn't apply any changes to the external resource or managed resource. Crossplane can't delete the resource. | | | | | ✔️ | | Crossplane only observes a resource. Used for [observe only resources]({{}}). | | | | | | | No policy set. An alternative method for [pausing](#paused) a resource. | {{< /table >}} ### providerConfigRef The `providerConfigRef` on a managed resource tells the Provider which [ProviderConfig]({{}}) to use when creating the managed resource. Use a ProviderConfig to define the authentication method to use when communicating to the Provider. {{< hint "important" >}} If `providerConfigRef` isn't applied, Providers use the ProviderConfig named `default`. {{< /hint >}} For example, a managed resource references a ProviderConfig named {{}}user-keys{{}}. This matches the {{}}name{{}} of a ProviderConfig. ```yaml {label="pcref",copy-lines="none"}} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Instance spec: forProvider: # Removed for brevity providerConfigRef: user-keys ``` ```yaml {label="pc"} apiVersion: aws.crossplane.io/v1beta1 kind: ProviderConfig metadata: name: user-keys # Removed for brevity ``` {{< hint "tip" >}} Each managed resource can reference different ProviderConfigs. This allows different managed resources to authenticate with different credentials to the same Provider. {{< /hint >}} ### providerRef Crossplane deprecated the `providerRef` field in `crossplane-runtime` [v0.10.0](https://github.com/crossplane/crossplane-runtime/releases/tag/v0.10.0). Managed resources using `providerRef`must use [`providerConfigRef`](#providerconfigref). ### writeConnectionSecretToRef When a Provider creates a managed resource it may generate resource-specific details, like usernames, passwords or connection details like an IP address. Crossplane stores these details in a Kubernetes Secret object specified by the `writeConnectionSecretToRef` values. For example, when creating an AWS RDS database instance with the Crossplane [community AWS provider](https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws/v0.40.0) generates an endpoint, password, port and username data. The Provider saves these variables in the Kubernetes secret {{}}rds-secret{{}}, referenced by the {{}}writeConnectionSecretToRef{{}} field. ```yaml {label="secretname",copy-lines="none"} apiVersion: database.aws.crossplane.io/v1beta1 kind: RDSInstance metadata: name: my-rds-instance spec: forProvider: # Removed for brevity writeConnectionSecretToRef: name: rds-secret ``` Viewing the Secret object shows the saved fields. ```yaml {copy-lines="1"} kubectl describe secret rds-secret Name: rds-secret # Removed for brevity Data ==== port: 4 bytes username: 10 bytes endpoint: 54 bytes password: 27 bytes ``` {{}} The Provider determines the data written to the Secret object. Refer to the specific Provider documentation for the generated Secret data. {{< /hint >}} ### publishConnectionDetailsTo The `publishConnectionDetailsTo` field expands on [`writeConnectionSecretToRef`](#writeconnectionsecrettoref) supporting storing managed resource information as a Kubernetes Secret object or in an external secrets store like [HashiCorp Vault](https://www.vaultproject.io/). Using `publishConnectionDetailsTo` requires enabling Crossplane External Secrets Stores (ESS). Enable ESS inside a Provider with a [ControllerConfig]({{}}) and in Crossplane with the `--enable-external-secret-stores` argument. {{< hint "note" >}} Not all Providers support `publishConnectionDetailsTo`. Check your Provider documentation for details. {{< /hint >}} #### Publish secrets to Kubernetes To publish the data generated by a managed resource as a Kubernetes Secret object provide a {{}}publishConnectionDetailsTo.name{{< /hover >}} ```yaml {label="k8secret",copy-lines="none"} apiVersion: rds.aws.upbound.io/v1beta1 kind: Instance spec: forProvider: # Removed for brevity publishConnectionDetailsTo: name: rds-kubernetes-secret ``` Crossplane can apply labels and annotations to the Kubernetes secret as well using {{}}publishConnectionDetailsTo.metadata{{}}. ```yaml {label="k8label",copy-lines="none"} apiVersion: rds.aws.upbound.io/v1beta1 kind: Instance spec: forProvider: # Removed for brevity publishConnectionDetailsTo: name: rds-kubernetes-secret metadata: labels: label-tag: label-value annotations: annotation-tag: annotation-value ``` #### Publish secrets to an external secrets store Publishing secrets data to an external secret store like [HashiCorp Vault](https://www.vaultproject.io/) relies on a {{}}publishConnectionDetailsTo.configRef{{}}. The {{}}configRef.name{{}} references a {{}}StoreConfig{{}} object. ```yaml {label="configref",copy-lines="none"} apiVersion: rds.aws.upbound.io/v1beta1 kind: Instance spec: forProvider: # Removed for brevity publishConnectionDetailsTo: name: rds-kubernetes-secret configRef: name: my-vault-storeconfig ``` ```yaml {label="storeconfig",copy-lines="none"} apiVersion: secrets.crossplane.io/v1alpha1 kind: StoreConfig metadata: name: my-vault-storeconfig # Removed for brevity ``` {{}} Read the [Vault as an External Secrets Store]({{}}) guide for details on using StoreConfig objects. {{< /hint >}} ## Annotations Crossplane applies a standard set of Kubernetes `annotations` to managed resources. {{
}} | Annotation | Definition | | --- | --- | | `crossplane.io/external-name` | The name of the managed resource inside the Provider. | | `crossplane.io/external-create-pending` | The timestamp of when Crossplane began creating the managed resource. | | `crossplane.io/external-create-succeeded` | The timestamp of when the Provider successfully created the managed resource. | | `crossplane.io/external-create-failed` | The timestamp of when the Provider failed to create the managed resource. | | `crossplane.io/paused` | Indicates Crossplane isn't reconciling this resource. Read the [Pause Annotation](#paused) for more details. | | `crossplane.io/composition-resource-name` | For managed resource created by a Composition, this is the Composition's `resources.name` value. | {{
}} ### Naming external resources By default Providers give external resources the same name as the Kubernetes object. For example, a managed resource named {{}}my-rds-instance{{}} has the name `my-rds-instance` as an external resource inside the Provider's environment. ```yaml {label="external-name",copy-lines="none"} apiVersion: database.aws.crossplane.io/v1beta1 kind: RDSInstance metadata: name: my-rds-instance ``` ```shell kubectl get rdsinstance NAME READY SYNCED EXTERNAL-NAME AGE my-rds-instance True True my-rds-instance 11m ``` Managed resource created with a `crossplane.io/external-name` annotation already provided use the annotation value as the external resource name. For example, the Provider creates managed resource named {{< hover label="custom-name" line="6">}}my-rds-instance{{}} but uses the name {{}}my-custom-name{{}} for the external resource inside AWS. ```yaml {label="custom-name",copy-lines="none"} apiVersion: database.aws.crossplane.io/v1beta1 kind: RDSInstance metadata: name: my-rds-instance annotations: crossplane.io/external-name: my-custom-namee ``` ```shell {copy-lines="1"} kubectl get rdsinstance NAME READY SYNCED EXTERNAL-NAME AGE my-rds-instance True True my-custom-name 11m ``` ### Creation annotations Providers create new managed resources with the `crossplane.io/external-create-pending` annotation. The Provider applies the `crossplane.io/external-create-succeeded` or `crossplane.io/external-create-failed` annotation after making the external API call and receiving a response. {{}} If a Provider restarts before creating the `succeed` or `fail` annotations the Provider can't reconcile the manged resource. Read Crossplane [issue #3037](https://github.com/crossplane/crossplane/issues/3037#issuecomment-1110142427) for more details {{< /hint >}} ### Paused Manually applying the `crossplane.io/paused` annotation causes the Provider to stop reconciling the managed resource. Pausing a resource is useful when modifying Providers or preventing race-conditions when editing Kubernetes objects. Apply a {{}}crossplane.io/paused: "true"{{}} annotation to a managed resource to pause reconciliation. {{< hint "note" >}} Only the value `"true"` pauses reconciliation. {{< /hint >}} ```yaml {label="pause"} apiVersion: ec2.aws.upbound.io/v1beta1 kind: Instance metadata: name: my-rds-instance annotations: crossplane.io/paused: "true" spec: forProvider: region: us-west-1 instanceType: t2.micro ``` Remove the annotation to resume reconciliation. ## Finalizers Crossplane applies a [Finalizer](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/) on managed resources to control their deletion. {{< hint "note" >}} Kubernetes can't delete objects with Finalizers. {{}} When Crossplane deletes a managed resource the Provider begins deleting the external resource, but the managed resource remains until the external resource is fully deleted. When the external resource is fully deleted Crossplane removes the Finalizer and deletes the managed resource object. ## Conditions Crossplane has a standard set of `Conditions` for a managed resource. View the `Conditions` of a managed resource with `kubectl describe ` {{}} Providers may define their own custom `Conditions`. {{}} ### Available `Reason: Available` indicates the Provider created the managed resource and it's ready for use. ```yaml {copy-lines="none"} Conditions: Type: Ready Status: True Reason: Available ``` ### Creating `Reason: Creating` indicates the Provider is attempting to create the managed resource. ```yaml {copy-lines="none"} Conditions: Type: Ready Status: False Reason: Creating ``` ### Deleting `Reason: Deleting` indicates the Provider is attempting to delete the managed resource. ```yaml {copy-lines="none"} Conditions: Type: Ready Status: False Reason: Deleting ``` ### ReconcilePaused `Reason: ReconcilePaused` indicates the managed resource has a [Pause](#paused) annotation ```yaml {copy-lines="none"} Conditions: Type: Synced Status: False Reason: ReconcilePaused ``` ### ReconcileError `Reason: ReconcileError` indicates Crossplane encountered an error while reconciling the managed resource. The `Message:` value of the `Condition` helps identify the Crossplane error. ```yaml {copy-lines="none"} Conditions: Type: Synced Status: False Reason: ReconcileError ``` ### ReconcileSuccess `Reason: ReconcileSuccess` indicates the Provider created and is monitoring the managed resource. ```yaml {copy-lines="none"} Conditions: Type: Synced Status: True Reason: ReconcileSuccess ``` ### Unavailable `Reason: Unavailable` indicates Crossplane expects the managed resource to be available, but the Provider reports the resource is unhealthy. ```yaml {copy-lines="none"} Conditions: Type: Ready Status: False Reason: Unavailable ``` ### Unknown `Reason: Unknown` indicates the Provider has an unexpected error with the managed resource. The `conditions.message` provides more information on what went wrong. ```yaml {copy-lines="none"} Conditions: Type: Unknown Status: False Reason: Unknown ``` ### Upjet Provider conditions [Upjet](https://github.com/upbound/upjet), the open source tool to generate Crossplane Providers, also has a set of standard `Conditions`. #### AsyncOperation Some resources may take more than a minute to create. Upjet based providers can complete their Kubernetes command before creating the managed resource by using an asynchronous operation. ##### Finished The `Reason: Finished` indicates the asynchronous operation completed successfully. ```yaml {copy-lines="none"} Conditions: Type: AsyncOperation Status: True Reason: Finished ``` ##### Ongoing `Reason: Ongoing` indicates the managed resource operation is still in progress. ```yaml {copy-lines="none"} Conditions: Type: AsyncOperation Status: True Reason: Ongoing ``` #### LastAsyncOperation The Upjet `Type: LastAsyncOperation` captures the previous asynchronous operation status as either `Success` or a failure `Reason`. ##### ApplyFailure `Reason: ApplyFailure` indicates the Provider failed to apply a setting to the managed resource. The `conditions.message` provides more information on what went wrong. ```yaml {copy-lines="none"} Conditions: Type: LastAsyncOperation Status: False Reason: ApplyFailure ``` ##### DestroyFailure `Reason: DestroyFailure` indicates the Provider failed to delete the managed resource. The `conditions.message` provides more information on what went wrong. ```yaml {copy-lines="none"} Conditions: Type: LastAsyncOperation Status: False Reason: DestroyFailure ``` ##### Success `Reason: Success` indicates the Provider successfully created the managed resource asynchronously. ```yaml {copy-lines="none"} Conditions: Type: LastAsyncOperation Status: True Reason: Success ```