function-deletion-protection

command module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2025 License: Apache-2.0 Imports: 22 Imported by: 0

README

function-deletion-protection

Note this function is in development. Please test in your environment before using it to protect critical workloads.

function-deletion-protection is a Crossplane Composition Function that blocks deletion of resources by creating ClusterUsage or Usage objects when resources are labeled with protection.fn.crossplane.io/block-deletion: "true", or when invoked by a WatchOperation.

When a Crossplane Usage is created for an Object, Crossplane creates a webhook that blocks any deletion requests until the Usage has been removed from the Cluster. See Usages for more information.

Attempts to delete an Object with a Usage will be rejected by an admission webhook:

$ kubectl delete XNetwork/configuration-aws-network  
Error from server (This resource is in-use by 1 usage(s), including the *v1beta1.Usage "configuration-aws-network-26d898-fn-protection" with reason: "created by function-deletion-protection via label protection.fn.crossplane.io/block-deletion".): admission webhook "nousages.protection.crossplane.io" denied the request: This resource is in-use by 1 usage(s), including the *v1beta1.Usage "configuration-aws-network-26d898-fn-protection" with reason: "created by function-deletion-protection via label protection.fn.crossplane.io/block-deletion".

Crossplane v1 and v2 Compatability

By default, this function creates v2 Usages using the protection.crossplane.io API Group in Crossplane version 2.0 or higher. The function has the ability to generate v1 Usages by setting enableV1Mode: true in the function Input.

Overview

Running this Function in a Composition Pipeline

When run in a Composition Pipeline this function monitors resources in a Composition for the protection.fn.crossplane.io/block-deletion label and creates corresponding Usage objects to prevent accidental deletion.

The function creates Usages for:

  • Composite resources (XRs) when labeled
  • Composed resources when labeled. If a Composed resources is protected, the parent Composite will also be protected.

Resources can be labeled outside of the Composition using kubectl label. The function will check if either the desired or observed state is labeled:

apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
metadata:
  labels:
    protection.fn.crossplane.io/block-deletion: "true"
  name: my-vpc

The function monitors the Composite and all Composed resources. In this case since the label is applied to a Cluster-scoped resource it will generate a ClusterUsage:

apiVersion: protection.crossplane.io/v1beta1
kind: ClusterUsage
metadata:
  name: my-vpc-2a782e-fn-protection
spec:
  of:
    apiVersion: ec2.aws.upbound.io/v1beta1
    kind: VPC
    resourceRef:
      name: my-vpc
  reason: created by function-deletion-protection via label protection.fn.crossplane.io/block-deletion

If the resources is Namespaced a Usage will be created in the Resource's namespace.

The label can be applied to the resource in the Composition (the "Desired" state), or it can be applied to the Resource in the cluster (the "Observed" state). If the Desired and Observed labels conflict, the function will default to creating the Usage.

Usage Reason Strings

The function provides granular reason strings to help identify why a Usage was created:

  • created by function-deletion-protection via label protection.fn.crossplane.io/block-deletion - A resource was protected because it has the protection.fn.crossplane.io/block-deletion: "true" label
  • created by function-deletion-protection because a composed resource is protected - A Composite resource was protected because one of its composed resources is protected
  • created by function-deletion-protection by an Operation - A resource was protected by a regular Operation (with the label)
  • created by function-deletion-protection by a WatchOperation - A resource was protected by a WatchOperation (automatic protection)

These reason strings appear in the Usage's spec.reason field and in deletion rejection messages, making it easy to understand why a resource cannot be deleted.

Running as an Operation

When invoked by a WatchOperation any Kubernetes resource on the Cluster that matches the watch conditions will have a Usage generated. In this example Namespaces with the block-deletion: "true" label will trigger an Operation:

---
apiVersion: ops.crossplane.io/v1alpha1
kind: WatchOperation
metadata:
  name: block-namespace-deletion
spec:
  watch:
    apiVersion: v1
    kind: Namespace
    matchLabels:
      block-deletion: "true"
  operationTemplate:
    spec:
      mode: Pipeline
      pipeline:
        - step: block-deletion
          functionRef:
            name: crossplane-contrib-function-deletion-protection
          input:
            apiVersion: protection.fn.crossplane.io/v1beta1
            kind: Input
            cacheTTL: 1h
            enableV1Mode: false

See examples/operations for more information. Operations are a Crossplane 2.x feature.

Installation

The function can be installed in a Crossplane Composition Pipeline. A test docker image is available from my repository at index.docker.io/steve/function-deletion-protection until the project migrates to Crossplane repositories.

The function can be installed into a Crossplane cluster using the following manifest:

apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
  name: crossplane-contrib-function-deletion-protection
spec:
  package: index.docker.io/steve/function-deletion-protection:v0.2.0
Function Customization

Setting cacheTTL configures the Function Response Cache. This can reduce the number of times the function is called.

    - step: protect-resources
      functionRef:
        name: crossplane-contrib-function-protection
      input:
        apiVersion: protection.fn.crossplane.io/v1beta1
        kind: Input
        cacheTTL: 10m
Creating Crossplane v1 Usages

There is a Compatibility mode for generating Crossplane v1 Usages by setting enableV1Mode: true in the Function's input. When this setting is enabled, v1 Usages will be created. Please note that this feature will be removed when upstream Crossplane deprecates v1 APIs.

    - step: protect-resources
      functionRef:
        name: crossplane-contrib-function-protection
      input:
        apiVersion: protection.fn.crossplane.io/v1beta1
        kind: Input
        enableV1Mode: true

When this feature is enabled, the function will generate v1 Cluster-scoped Usages using the apiextensions.crossplane.io/v1beta1 API Group:

apiVersion: apiextensions.crossplane.io/v1beta1
kind": Usage
metadata:
  name: ...

Building

To build the Docker image for both arm64 and amd64 and save the results in a tar file, run:

export VERSION=0.2.0
# Build the function's runtime image
docker buildx build --platform linux/amd64 . --tag=test:v1 --target=image --output type=docker,dest=function-deletion-protection-runtime-amd64-v${VERSION}.tar
docker buildx build --platform linux/arm64 . --tag=test:v1 --target=image --output type=docker,dest=function-deletion-protection-runtime-arm64-v${VERSION}.tar

Next, build the Crossplane Package:

export VERSION=0.2.0
crossplane xpkg build -f package --embed-runtime-image-tarball=function-deletion-protection-runtime-amd64-v${VERSION}.tar -o function-deletion-protection-amd64-v${VERSION}.xpkg
crossplane xpkg build -f package --embed-runtime-image-tarball=function-deletion-protection-runtime-arm64-v${VERSION}.tar -o function-deletion-protection-arm64-v${VERSION}.xpkg

This package can be pushed to any Docker-compatible registry:

export VERSION=0.2.0
crossplane xpkg push index.docker.io/steve/function-deletion-protection:v0.2.0 -f function-deletion-protection-amd64-v${VERSION}.xpkg
crossplane xpkg push index.docker.io/steve/function-deletion-protection:v0.2.0 -f function-deletion-protection-arm64-v${VERSION}.xpkg

Taskfile Support

This project has several Taskfile tasks:

task --list 
task: Available tasks for this project:
* build-docker:       Builds the function into a deployable Docker image and saves it as a tar file.
* build-xpkg:         Creates a Crossplane .xpkg file from a Docker tar file.
* clean:              Removes Artifacts
* push-xpkg:          Pushes Crossplane package to an OCI repository. Please ensure the repository exists before pushing.

Documentation

Overview

Package main implements a Composition Function.

Directories

Path Synopsis
input
v1beta1
Package v1beta1 contains the input type for this Function +kubebuilder:object:generate=true +groupName=protection.fn.crossplane.io +versionName=v1beta1
Package v1beta1 contains the input type for this Function +kubebuilder:object:generate=true +groupName=protection.fn.crossplane.io +versionName=v1beta1

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL