Resources created by Crossplane aren’t deleted if Crossplane isn’t uninstalled in order.

This can leave cloud resources running, requiring manual deletion.

Ordered Crossplane uninstall

Most Crossplane resources have dependencies on other Crossplane resources.

For example, a managed resource is dependent on the provider.

Failure to delete Crossplane resources in order may prevent Crossplane from deleting provisioned external resources.

Removing Crossplane resources should happen in the following order:

  1. Remove all composite resource definitions
  2. Remove all remaining managed resources
  3. Remove all providers

Deleting the Crossplane pod removes remaining Crossplane components like claims.


Collect an inventory of all external resources with kubectl get managed.

Depending on the size of the Kubernetes API server and number of resources, this command may take minutes to return.

 1kubectl get managed
 2NAME                                                 READY   SYNCED   EXTERNAL-NAME          AGE
 3securitygroup.ec2.aws.upbound.io/my-db-7mc7h-j84h8   True    True     sg-0da6e9c29113596b6   3m1s
 4securitygroup.ec2.aws.upbound.io/my-db-8bhr2-9wsx9   True    True     sg-02695166f010ec05b   2m26s
 6NAME                                         READY   SYNCED   EXTERNAL-NAME                       AGE
 7route.ec2.aws.upbound.io/my-db-7mc7h-vw985   True    True     r-rtb-05822b8df433e4e2b1080289494   3m1s
 8route.ec2.aws.upbound.io/my-db-8bhr2-7m2wq   False   True                                         2m26s
10NAME                                                     READY   SYNCED   EXTERNAL-NAME      AGE
11securitygrouprule.ec2.aws.upbound.io/my-db-7mc7h-mkd9s   True    True     sgrule-778063708   3m1s
12securitygrouprule.ec2.aws.upbound.io/my-db-8bhr2-lzr89   False   True                        2m26s
14NAME                                              READY   SYNCED   EXTERNAL-NAME           AGE
15routetable.ec2.aws.upbound.io/my-db-7mc7h-mnqvm   True    True     rtb-05822b8df433e4e2b   3m1s
16routetable.ec2.aws.upbound.io/my-db-8bhr2-dfhj6   True    True     rtb-02e875abd25658254   2m26s
18NAME                                          READY   SYNCED   EXTERNAL-NAME              AGE
19subnet.ec2.aws.upbound.io/my-db-7mc7h-7m49d   True    True     subnet-0c1ab32c5ec129dd1   3m2s
20subnet.ec2.aws.upbound.io/my-db-7mc7h-9t64t   True    True     subnet-07075c17c7a72f79e   3m2s
21subnet.ec2.aws.upbound.io/my-db-7mc7h-rs8t8   True    True     subnet-08e88e826a42e55b4   3m2s
22subnet.ec2.aws.upbound.io/my-db-8bhr2-9sjpx   True    True     subnet-05d21c7b52f7ac8ca   2m26s
23subnet.ec2.aws.upbound.io/my-db-8bhr2-dvrxf   True    True     subnet-0432310376b5d09de   2m26s
24subnet.ec2.aws.upbound.io/my-db-8bhr2-t7dpr   True    True     subnet-0080fdcb6e9b70632   2m26s
26NAME                                       READY   SYNCED   EXTERNAL-NAME           AGE
27vpc.ec2.aws.upbound.io/my-db-7mc7h-ktbbh   True    True     vpc-08d7dd84e0c12f33e   3m3s
28vpc.ec2.aws.upbound.io/my-db-8bhr2-mrh2x   True    True     vpc-06994bf323fc1daea   2m26s
30NAME                                                   READY   SYNCED   EXTERNAL-NAME           AGE
31internetgateway.ec2.aws.upbound.io/my-db-7mc7h-s2x4v   True    True     igw-0189c4da07a3142dc   3m1s
32internetgateway.ec2.aws.upbound.io/my-db-8bhr2-q7dzl   True    True     igw-01bf2a1dbbebf6a27   2m26s
34NAME                                                         READY   SYNCED   EXTERNAL-NAME                AGE
35routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-28qb4   True    True     rtbassoc-0718d680b5a0e68fe   3m1s
36routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-9hdlr   True    True     rtbassoc-0faaedb88c6e1518c   3m1s
37routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-txhmz   True    True     rtbassoc-0e5010724ca027864   3m1s
38routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-bvgkt   False   True                                  2m26s
39routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-d9gbg   False   True                                  2m26s
40routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-k6k8m   False   True                                  2m26s
42NAME                                            READY   SYNCED   EXTERNAL-NAME       AGE
43instance.rds.aws.upbound.io/my-db-7mc7h-5d6w4   False   True     my-db-7mc7h-5d6w4   3m1s
44instance.rds.aws.upbound.io/my-db-8bhr2-tx9kf   False   True     my-db-8bhr2-tx9kf   2m26s
46NAME                                               READY   SYNCED   EXTERNAL-NAME       AGE
47subnetgroup.rds.aws.upbound.io/my-db-7mc7h-8c8n9   True    True     my-db-7mc7h-8c8n9   3m2s
48subnetgroup.rds.aws.upbound.io/my-db-8bhr2-mc5ps   True    True     my-db-8bhr2-mc5ps   2m27s
50NAME                                                   READY   SYNCED   EXTERNAL-NAME                 AGE
51bucket.s3.aws.upbound.io/crossplane-bucket-867737b10   True    True
52crossplane-bucket-867737b10   5m26s

Remove composite resource definitions

Removing installed composite resource definitions removes any composite resources defined by the composite resource definition and the managed resourced they created.

View the installed composite resource definitions with kubectl get xrd.

1kubectl get xrd
2NAME                                                ESTABLISHED   OFFERED   AGE
3compositepostgresqlinstances.database.example.org   True          True      40s

Delete the composite resource definitions with kubectl delete xrd.

1kubectl delete xrd compositepostgresqlinstances.database.example.org

Remove managed resources

Manually delete any managed resources manually created.

Use kubectl get managed to view remaining managed resources.

1kubectl get managed
2NAME                                                   READY   SYNCED   EXTERNAL-NAME                 AGE
3bucket.s3.aws.upbound.io/crossplane-bucket-867737b10   True    True     crossplane-bucket-867737b10   8h

Use kubectl delete to remove the resources.

1kubectl delete bucket.s3.aws.upbound.io/crossplane-bucket-867737b10

Remove Crossplane providers

List the installed providers with kubectl get providers.

1kubectl get providers
2NAME                   INSTALLED   HEALTHY   PACKAGE                                        AGE
3upbound-provider-aws   True        True      xpkg.upbound.io/upbound/provider-aws:v0.27.0   8h

Remove the installed providers with kubectl delete provider.

1kubectl delete provider upbound-provider-aws

Uninstall the Crossplane deployment

Uninstall Crossplane using Helm with helm uninstall

1helm uninstall crossplane --namespace crossplane-system

Verify Helm removed the Crossplane pods with kubectl get pods

1kubectl get pods -n crossplane-system
2No resources found in crossplane-system namespace.

Delete the Crossplane namespace

When Helm installs Crossplane it creates the crossplane-system namespace. Helm doesn’t uninstall this namespace with helm uninstall.

Manually delete the Crossplane namespace with kubectl delete namespace.

1kubectl delete namespace crossplane-system

Verify Kubernetes removed the namespace with kubectl get namespaces

1kubectl get namespace
2NAME              STATUS   AGE
3default           Active   2m45s
4kube-flannel      Active   2m42s
5kube-node-lease   Active   2m47s
6kube-public       Active   2m47s
7kube-system       Active   2m47s