mirror of https://github.com/crossplane/docs.git
1111 lines
38 KiB
Markdown
1111 lines
38 KiB
Markdown
---
|
|
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` defined in [provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws).
|
|
* Google Cloud GKE `Cluster` defined in [provider-upjet-gcp](https://github.com/crossplane-contrib/provider-upjet-gcp).
|
|
* Microsoft Azure PostgreSQL `Database` defined in [provider-upjet-azure](https://github.com/crossplane-contrib/provider-upjet-azure).
|
|
|
|
{{< hint "tip" >}}
|
|
|
|
You can create individual managed resources, but Crossplane recommends using
|
|
[Compositions]({{<ref "./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 [provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws)
|
|
defines the {{<hover label="gkv" line="2">}}Instance{{</hover>}} kind from the
|
|
group {{<hover label="gkv" line="1">}}ec2.aws.upbound.io{{</hover>}}
|
|
|
|
```yaml {label="gkv",copy-lines="none"}
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: Instance
|
|
```
|
|
|
|
<!-- vale off -->
|
|
### deletionPolicy
|
|
<!-- vale on -->
|
|
|
|
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:
|
|
<!-- vale write-good.Passive = NO -->
|
|
- The related management policy alpha feature is enabled.
|
|
<!-- vale write-good.Passive = YES -->
|
|
- 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 >}}
|
|
|
|
<!-- vale off -->
|
|
### forProvider
|
|
<!-- vale on -->
|
|
|
|
The {{<hover label="forProvider" line="4">}}spec.forProvider{{</hover>}} 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 {{<hover label="forProvider" line="5">}}region{{</hover>}} and the VM
|
|
size, called the
|
|
{{<hover label="forProvider" line="6">}}instanceType{{</hover>}}.
|
|
|
|
{{< 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.
|
|
|
|
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
|
|
```
|
|
|
|
##### Matching by controller reference
|
|
|
|
Matching a controller reference ensures that the matching resource is part of
|
|
the same composite resource.
|
|
|
|
{{<hint "note" >}}
|
|
Learn more about composite resources in the
|
|
[Composite Resources]({{<ref "./composite-resources">}}) section.
|
|
{{</hint >}}
|
|
|
|
Matching only a controller reference simplifies the matching process without
|
|
requiring labels or more information.
|
|
|
|
For example, creating an AWS `InternetGateway` requires a `VPC`.
|
|
|
|
The `InternetGateway` could match a label, but every VPC created by this
|
|
Composition shares the same label.
|
|
|
|
Using `matchControllerRef` matches only the VPC created in the same composite
|
|
resource that created the `InternetGateway`.
|
|
|
|
```yaml {label="controller1",copy-lines="none"}
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
name: my-vpc
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: InternetGateway
|
|
name: my-gateway
|
|
spec:
|
|
forProvider:
|
|
vpcIdSelector:
|
|
matchControllerRef: true
|
|
```
|
|
|
|
Resources can match both labels and a controller reference to match a specific
|
|
resource in the larger composite resource.
|
|
|
|
For example, this Composition creates two `VPC` resources, but the
|
|
`InternetGateway` must match only one.
|
|
|
|
Applying a `label` to the second `VPC` allows the `InternetGateway` to match the
|
|
label `type: internet` and only match objects in the same composite resource
|
|
with `matchControllerRef`.
|
|
|
|
```yaml {label="controller2",copy-lines="none"}
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- name: my-first-vpc
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
metadata:
|
|
labels:
|
|
type: backend
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
- name: my-second-vpc
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
metadata:
|
|
labels:
|
|
type: internet
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
- name: my-gateway
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: InternetGateway
|
|
spec:
|
|
forProvider:
|
|
vpcIdSelector:
|
|
matchControllerRef: true
|
|
matchLabels:
|
|
type: internet
|
|
```
|
|
|
|
{{<hint "note" >}}
|
|
These examples use Function Patch and Transform. Learn more about functions and
|
|
Compositions in the [Compositions]({{<ref "./compositions">}}) section.
|
|
{{</hint >}}
|
|
|
|
|
|
|
|
#### 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.
|
|
|
|
{{<hint "note" >}}
|
|
<!-- vale write-good.Passive = NO -->
|
|
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`.
|
|
<!-- vale write-good.Passive = YES -->
|
|
{{< /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.
|
|
|
|
{{<hint "note" >}}
|
|
<!-- vale write-good.Passive = NO -->
|
|
With [managementPolicies]({{<ref "./managed-resources#managementpolicies" >}}),
|
|
this behavior can be turned off by not including the `LateInitialize` policy in
|
|
the `managementPolicies` list.
|
|
<!-- vale write-good.Passive = YES -->
|
|
{{< /hint >}}
|
|
|
|
<!-- vale off -->
|
|
### initProvider
|
|
<!-- vale on -->
|
|
|
|
{{<hint "important" >}}
|
|
The managed resource `initProvider` option is a beta feature related to
|
|
[managementPolicies]({{<ref "./managed-resources#managementpolicies" >}}).
|
|
|
|
{{< /hint >}}
|
|
|
|
The
|
|
{{<hover label="initProvider" line="7">}}initProvider{{</hover>}} defines
|
|
settings Crossplane applies only when creating a new managed resource.
|
|
Crossplane ignores settings defined in the
|
|
{{<hover label="initProvider" line="7">}}initProvider{{</hover>}}
|
|
field that change after creation.
|
|
|
|
{{<hint "note" >}}
|
|
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.
|
|
{{</hint >}}
|
|
|
|
Using `initProvider` is useful for setting initial values that a Provider may
|
|
automatically change, like an auto scaling group.
|
|
|
|
For example, creating a
|
|
{{<hover label="initProvider" line="2">}}NodeGroup{{</hover>}}
|
|
with an initial
|
|
{{<hover label="initProvider" line="9">}}desiredSize{{</hover>}}.
|
|
Crossplane doesn't change the
|
|
{{<hover label="initProvider" line="9">}}desiredSize{{</hover>}}
|
|
setting back when an autoscaler scales the Node Group external resource.
|
|
|
|
{{< hint "tip" >}}
|
|
Crossplane recommends configuring
|
|
{{<hover label="initProvider" line="6">}}managementPolicies{{</hover>}} 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
|
|
```
|
|
|
|
<!-- vale off -->
|
|
### managementPolicies
|
|
<!-- vale on -->
|
|
|
|
{{<hint "note" >}}
|
|
The managed resource `managementPolicies` option is a beta feature. Crossplane enables
|
|
beta features by default.
|
|
|
|
The Provider determines support for management policies.
|
|
Refer to the Provider's documentation to see if the Provider supports
|
|
management policies.
|
|
{{< /hint >}}
|
|
|
|
Crossplane
|
|
{{<hover label="managementPol1" line="4">}}managementPolicies{{</hover>}}
|
|
determine which actions Crossplane can take on a
|
|
managed resource and its corresponding external resource.
|
|
Apply one or more
|
|
{{<hover label="managementPol1" line="4">}}managementPolicies{{</hover>}}
|
|
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
|
|
{{<hover label="managementPol1" line="4">}}["Create", "Delete", "Observe"]{{</hover>}}.
|
|
|
|
```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.
|
|
|
|
{{<hint "important" >}}
|
|
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:
|
|
{{<table "table table-sm table-hover">}}
|
|
| 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]({{<ref "./managed-resources#late-initialization" >}}) section for more details. |
|
|
| `Observe` | Crossplane only observes the resource and doesn't make any changes. Used for [observe only resources]({{<ref "../guides/import-existing-resources#import-resources-automatically">}}). |
|
|
| `Update` | Crossplane changes the external resource when changing the managed resource. |
|
|
{{</table >}}
|
|
|
|
The following is a list of common policy combinations:
|
|
{{<table "table table-sm table-hover table-striped-columns" >}}
|
|
| Create | Delete | LateInitialize | Observe | Update | Description |
|
|
| :---: | :---: | :---: | :---: | :---: | --- |
|
|
| {{<check>}} | {{<check>}} | {{<check>}} | {{<check>}} | {{<check>}} | _Default policy_. Crossplane has full control over the resource. |
|
|
| {{<check>}} | {{<check>}} | {{<check>}} | {{<check>}} | | After creation any changes made to the managed resource aren't passed to the external resource. Useful for immutable external resources. |
|
|
| {{<check>}} | {{<check>}} | | {{<check>}} | {{<check>}} | Prevent Crossplane from managing any settings not defined in the managed resource. Useful for immutable fields in an external resource. |
|
|
| {{<check>}} | {{<check>}} | | {{<check>}} | | 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. |
|
|
| {{<check>}} | | {{<check>}} | {{<check>}} | {{<check>}} | Crossplane doesn't delete the external resource when deleting the managed resource. |
|
|
| {{<check>}} | | {{<check>}} | {{<check>}} | | Crossplane doesn't delete the external resource when deleting the managed resource. Crossplane doesn't apply changes to the external resource after creation. |
|
|
| {{<check>}} | | | {{<check>}} | {{<check>}} | Crossplane doesn't delete the external resource when deleting the managed resource. Crossplane doesn't import any settings from the external resource. |
|
|
| {{<check>}} | | | {{<check>}} | | Crossplane creates the external resource but doesn't apply any changes to the external resource or managed resource. Crossplane can't delete the resource. |
|
|
| | | | {{<check>}} | | Crossplane only observes a resource. Used for [observe only resources]({{<ref "../guides/import-existing-resources#import-resources-automatically">}}). |
|
|
| | | | | | No policy set. An alternative method for [pausing](#paused) a resource. |
|
|
{{< /table >}}
|
|
|
|
<!-- vale off -->
|
|
### providerConfigRef
|
|
<!-- vale on -->
|
|
|
|
The `providerConfigRef` on a managed resource tells the Provider which
|
|
[ProviderConfig]({{<ref "./providers#provider-configuration">}}) 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
|
|
{{<hover label="pcref" line="6">}}user-keys{{</hover>}}.
|
|
|
|
This matches the {{<hover label="pc" line="4">}}name{{</hover>}} 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 >}}
|
|
|
|
<!-- vale off -->
|
|
### providerRef
|
|
<!-- vale on -->
|
|
|
|
<!-- vale Crossplane.Spelling = NO -->
|
|
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).
|
|
<!-- vale Crossplane.Spelling = YES -->
|
|
|
|
<!-- vale off -->
|
|
### writeConnectionSecretToRef
|
|
<!-- vale on -->
|
|
|
|
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://github.com/crossplane-contrib/provider-aws)
|
|
generates an endpoint, password, port and username data. The Provider saves
|
|
these variables in the Kubernetes secret
|
|
{{<hover label="secretname" line="9" >}}rds-secret{{</hover>}}, referenced by
|
|
the
|
|
{{<hover label="secretname" line="9" >}}writeConnectionSecretToRef{{</hover>}}
|
|
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
|
|
```
|
|
|
|
{{<hint "important" >}}
|
|
The Provider determines the data written to the Secret object. Refer to the
|
|
specific Provider documentation for the generated Secret data.
|
|
{{< /hint >}}
|
|
|
|
<!-- vale off -->
|
|
### publishConnectionDetailsTo
|
|
<!-- vale on -->
|
|
|
|
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
|
|
[DeploymentRuntimeConfig]({{<ref "providers#runtime-configuration" >}}) 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
|
|
{{<hover label="k8secret" line="7">}}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
|
|
{{<hover label="k8label" line="8">}}publishConnectionDetailsTo.metadata{{</hover>}}.
|
|
|
|
```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
|
|
{{<hover label="configref" line="8">}}publishConnectionDetailsTo.configRef{{</hover>}}.
|
|
|
|
The
|
|
{{<hover label="configref" line="9">}}configRef.name{{</hover>}} references a
|
|
{{<hover label="storeconfig" line="4">}}StoreConfig{{</hover>}}
|
|
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
|
|
```
|
|
|
|
{{<hint "tip" >}}
|
|
Read the
|
|
[Vault as an External Secrets Store]({{<ref "../guides/vault-as-secret-store">}})
|
|
guide for details on using StoreConfig objects.
|
|
{{< /hint >}}
|
|
|
|
## Annotations
|
|
|
|
Crossplane applies a standard set of Kubernetes `annotations` to managed
|
|
resources.
|
|
|
|
{{<table "table table-sm">}}
|
|
| 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. |
|
|
{{</table >}}
|
|
|
|
### Naming external resources
|
|
By default Providers give external resources the same name as the Kubernetes
|
|
object.
|
|
|
|
For example, a managed resource named
|
|
{{<hover label="external-name" line="4">}}my-rds-instance{{</hover >}} 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{{</hover>}} but uses
|
|
the name {{<hover label="custom-name" line="5">}}my-custom-name{{</hover >}}
|
|
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-name
|
|
```
|
|
|
|
```shell {copy-lines="1"}
|
|
kubectl get rdsinstance
|
|
NAME READY SYNCED EXTERNAL-NAME AGE
|
|
my-rds-instance True True my-custom-name 11m
|
|
```
|
|
|
|
### Creation annotations
|
|
|
|
When an external system like AWS generates nondeterministic resource names it's
|
|
possible for a provider to create a resource but not record that it did. When
|
|
this happens the provider can't manage the resource.
|
|
|
|
{{<hint "tip">}}
|
|
Crossplane calls resources that a provider creates but doesn't manage _leaked
|
|
resources_.
|
|
{{</hint>}}
|
|
|
|
Providers set three creation annotations to avoid and detect leaked resources:
|
|
|
|
* {{<hover label="creation" line="8">}}crossplane.io/external-create-pending{{</hover>}} -
|
|
The last time the provider was about to create the resource.
|
|
* {{<hover label="creation" line="9">}}crossplane.io/external-create-succeeded{{</hover>}} -
|
|
The last time the provider successfully created the resource.
|
|
* `crossplane.io/external-create-failed` - The last time the provider failed to
|
|
create the resource.
|
|
|
|
Use `kubectl get` to view the annotations on a managed resource. For example, an
|
|
AWS VPC resource:
|
|
|
|
```yaml {label="creation" copy-lines="2-9"}
|
|
$ kubectl get -o yaml vpc my-vpc
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
metadata:
|
|
name: my-vpc
|
|
annotations:
|
|
crossplane.io/external-name: vpc-1234567890abcdef0
|
|
crossplane.io/external-create-pending: "2023-12-18T21:48:06Z"
|
|
crossplane.io/external-create-succeeded: "2023-12-18T21:48:40Z"
|
|
```
|
|
|
|
A provider uses the
|
|
{{<hover label="creation" line="7">}}crossplane.io/external-name{{</hover>}}
|
|
annotation to lookup a managed resource in an external system.
|
|
|
|
The provider looks up the resource in the external system to determine if it
|
|
exists, and if it matches the managed resource's desired state. If the provider
|
|
can't find the resource, it creates it.
|
|
|
|
Some external systems don't let a provider specify a resource's name when the
|
|
provider creates it. Instead the external system generates an nondeterministic
|
|
name and returns it to the provider.
|
|
|
|
When the external system generates the resource's name, the provider attempts to
|
|
save it to the managed resource's `crossplane.io/external-name` annotation. If
|
|
it doesn't, it _leaks_ the resource.
|
|
|
|
A provider can't guarantee that it can save the annotation. The provider could
|
|
restart or lose network connectivity between creating the resource and saving
|
|
the annotation.
|
|
|
|
A provider can detect that it might have leaked a resource. If the provider
|
|
thinks it might have leaked a resource, it stops reconciling it until you tell
|
|
the provider it's safe to proceed.
|
|
|
|
{{<hint "important">}}
|
|
Anytime an external system generates a resource's name there is a risk the
|
|
provider could leak the resource.
|
|
|
|
The safest thing for a provider to do when it detects that it might have leaked
|
|
a resource is to stop and wait for human intervention.
|
|
|
|
This ensures the provider doesn't create duplicates of the leaked resource.
|
|
Duplicate resources can be costly and dangerous.
|
|
{{</hint>}}
|
|
|
|
When a provider thinks it might have leaked a resource it creates a `cannot
|
|
determine creation result` event associated with the managed resource. Use
|
|
`kubectl describe` to see the event.
|
|
|
|
```shell {copy-lines="1"}
|
|
kubectl describe queue my-sqs-queue
|
|
|
|
# Removed for brevity
|
|
|
|
Events:
|
|
Type Reason Age From Message
|
|
---- ------ ---- ---- -------
|
|
Warning CannotInitializeManagedResource 29m (x19 over 19h) managed/queue.sqs.aws.crossplane.io cannot determine creation result - remove the crossplane.io/external-create-pending annotation if it is safe to proceed
|
|
```
|
|
|
|
Providers use the creation annotations to detect that they might have leaked a
|
|
resource.
|
|
|
|
Each time a provider reconciles a managed resource it checks the resource's
|
|
creation annotations. If the provider sees a create pending time that's more
|
|
recent than the most recent create succeeded or create failed time, it knows
|
|
that it might have leaked a resource.
|
|
|
|
{{<hint "note">}}
|
|
Providers don't remove the creation annotations. They use the timestamps to
|
|
determine which is most recent. It's normal for a managed resource to have
|
|
several creation annotations.
|
|
{{</hint>}}
|
|
|
|
The provider knows it might have leaked a resource because it updates all the
|
|
resource's annotations at the same time. If the provider couldn't update the
|
|
creation annotations after it created the resource, it also couldn't update the
|
|
`crossplane.io/external-name` annotation.
|
|
|
|
{{<hint "tip">}}
|
|
If a resource has a `cannot determine creation result` error, inspect the
|
|
external system.
|
|
|
|
Use the timestamp from the `crossplane.io/external-create-pending` annotation to
|
|
determine when the provider might have leaked a resource. Look for resources
|
|
created around this time.
|
|
|
|
If you find a leaked resource, and it's safe to do so, delete it from the
|
|
external system.
|
|
|
|
Remove the `crossplane.io/external-create-pending` annotation from the managed
|
|
resource after you're sure no leaked resource exists. This tells the provider to
|
|
resume reconciliation of and recreate the managed resource.
|
|
{{</hint>}}
|
|
|
|
Providers also use the creation annotations to avoid leaking resources.
|
|
|
|
When a provider writes the `crossplane.io/external-create-pending` annotation it
|
|
knows it's reconciling the latest version of the managed resource. The write
|
|
would fail if the provider was reconciling an old version of the managed
|
|
resource.
|
|
|
|
If the provider reconciled an old version with an outdated
|
|
`crossplane.io/external-name` annotation it could mistakenly determine that the
|
|
resource didn't exist. The provider would create a new resource, and leak the
|
|
existing one.
|
|
|
|
Some external systems have a delay between when a provider creates a resource
|
|
and when the system reports that it exists. The provider uses the most recent
|
|
create succeeded time to account for this delay.
|
|
|
|
If the provider didn't account for the delay, it could mistakenly determine
|
|
that the resource didn't exist. The provider would create a new resource, and
|
|
leak the existing one.
|
|
|
|
### 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 {{<hover label="pause" line="6">}}crossplane.io/paused: "true"{{</hover>}}
|
|
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.
|
|
|
|
{{<hint "important">}}
|
|
Kubernetes and Crossplane can't delete resources with a `paused` annotation,
|
|
even with `kubectl delete`.
|
|
|
|
Read
|
|
[Crossplane discussion #4839](https://github.com/crossplane/crossplane/issues/4839)
|
|
for more details.
|
|
{{< /hint >}}
|
|
|
|
## 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.
|
|
{{</hint >}}
|
|
|
|
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 <managed_resource>`
|
|
|
|
|
|
{{<hint "note" >}}
|
|
Providers may define their own custom `Conditions`.
|
|
{{</hint >}}
|
|
|
|
|
|
### 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
|
|
```
|
|
|
|
<!-- vale off -->
|
|
### ReconcilePaused
|
|
<!-- vale on -->
|
|
`Reason: ReconcilePaused` indicates the managed resource has a [Pause](#paused)
|
|
annotation
|
|
|
|
```yaml {copy-lines="none"}
|
|
Conditions:
|
|
Type: Synced
|
|
Status: False
|
|
Reason: ReconcilePaused
|
|
```
|
|
|
|
<!-- vale off -->
|
|
### ReconcileError
|
|
<!-- vale on -->
|
|
`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
|
|
```
|
|
|
|
<!-- vale off -->
|
|
### ReconcileSuccess
|
|
<!-- vale on -->
|
|
`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`.
|
|
|
|
|
|
<!-- vale off -->
|
|
#### AsyncOperation
|
|
<!-- vale on -->
|
|
|
|
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
|
|
```
|
|
|
|
<!-- vale off -->
|
|
#### LastAsyncOperation
|
|
<!-- vale on -->
|
|
|
|
The Upjet `Type: LastAsyncOperation` captures the previous asynchronous
|
|
operation status as either `Success` or a failure `Reason`.
|
|
|
|
<!-- vale off -->
|
|
##### ApplyFailure
|
|
<!-- vale on -->
|
|
|
|
`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
|
|
```
|
|
|
|
<!-- vale off -->
|
|
##### DestroyFailure
|
|
<!-- vale on -->
|
|
|
|
`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
|
|
```
|