This is an alpha feature. Crossplane may change or drop this feature at any time.

This feature was introduced in v1.17.

For more information read the Crossplane feature lifecycle.

This document is for an unreleased version of Crossplane.

This document applies to the Crossplane master branch and not to the latest release v2.0.

The change logs feature helps users of Crossplane Providers understand what changes a provider makes to the resources it manages. Whenever a provider creates, updates, or deletes a managed resource, the provider records an entry explaining the details of the change in its change log.

Change logs are important for awareness of the changes that a provider is making to its managed resources. Due to the nature of Crossplane’s active reconciliation, it’s possible for a provider to make changes to managed resources without any user interaction. Consider the scenario when someone updates a resource outside of Crossplane, for example via the AWS console or gcloud CLI. When Crossplane detects this configuration drift, it enforces the declared state and corrects the unexpected change without any user interaction.

With Crossplane acting continuously and autonomously to update critical infrastructure, it’s vital for users to have insight into the operations the provider performs, so they can build and maintain a strong sense of confidence and trust in their control planes. Change logs provide details about all changes the provider makes, so users can remain aware of any changes, even when they aren’t explicitly expecting any.

Tip
Change logs help you understand all the changes a provider is making to your resources, even when changes weren’t explicitly requested, for example because of Crossplane’s automatic correction of configuration drift.

Enabling change logs

Important
Change logs are an alpha feature and must be explicitly enabled for each provider through the use of a DeploymentRuntimeConfig.

To enable change logs for a provider, use a DeploymentRuntimeConfig to configure each provider pod that should start producing change logs. The DeploymentRuntimeConfig has several important configuration details:

  1. A command line argument to the provider container that enables the change logs feature, for example --enable-changelogs.
  2. A side car container that collects change events and produces change log entries to the provider’s pod logs.
  3. A shared volume mounted to both the provider and sidecar containers that enables communication of change events between the two containers.

Prerequisites

This guide assumes you have a control plane with Crossplane installed.

It also assumes you have the jq tool installed, to perform lightweight querying and filtering of the content in the change logs.

The only other prerequisite for enabling change logs is provider support for the change logs feature. Support for change logs is optional, and not all providers in the Crossplane ecosystem have added it yet.

Tip
Not all providers support the change logs feature. Check with your provider of choice to confirm it has added support for change logs.

This guide walks through a full example of generating change logs with provider-kubernetes.

Create a DeploymentRuntimeConfig

Create a DeploymentRuntimeConfig that enables change logs for the provider when it’s installed by performing the following configuration steps:

  1. Set the --enable-changelogs flag on the provider.
  2. Add the sidecar container to the provider pod.
  3. Declare a shared volume and mount it in the provider container and the sidecar container.
 1cat <<EOF | kubectl apply -f -
 2apiVersion: pkg.crossplane.io/v1beta1
 3kind: DeploymentRuntimeConfig
 4metadata:
 5  name: enable-changelogs
 6spec:
 7  deploymentTemplate:
 8    spec:
 9      selector: {}
10      template:
11        spec:
12          containers:
13          - name: package-runtime
14            args:
15            - --enable-changelogs
16            volumeMounts:
17            - name: changelogs-vol
18              mountPath: /var/run/changelogs
19          - name: changelogs-sidecar
20            image: xpkg.crossplane.io/crossplane/changelogs-sidecar:v0.0.1
21            volumeMounts:
22            - name: changelogs-vol
23              mountPath: /var/run/changelogs
24          volumes:
25          - name: changelogs-vol
26            emptyDir: {}
27  serviceAccountTemplate:
28    metadata:
29      name: provider-kubernetes
30EOF

Install the provider

Install the provider and instruct it to use the DeploymentRuntimeConfig that was just created.

 1cat <<EOF | kubectl apply -f -
 2apiVersion: pkg.crossplane.io/v1
 3kind: Provider
 4metadata:
 5  name: provider-kubernetes
 6spec:
 7  package: xpkg.crossplane.io/crossplane-contrib/provider-kubernetes:v0.18.0
 8  runtimeConfigRef:
 9    apiVersion: pkg.crossplane.io/v1beta1
10    kind: DeploymentRuntimeConfig
11    name: enable-changelogs
12EOF

Configure permissions

To allow the provider to create Kubernetes resources in the control plane, grant the appropriate permissions. This guide only creates a ConfigMap, so it only requires permissions for that resource type.

Important
This guide grants specific permissions to the provider for example purposes. This approach isn’t intended to be representative of a production environment. See more examples for configuring provider-kubernetes in its examples directory.
 1cat <<EOF | kubectl apply -f -
 2apiVersion: rbac.authorization.k8s.io/v1
 3kind: ClusterRole
 4metadata:
 5  name: configmap-edit
 6rules:
 7  - apiGroups:
 8      - ""
 9    resources:
10      - configmaps
11    verbs:
12      - "*"
13---
14apiVersion: rbac.authorization.k8s.io/v1
15kind: ClusterRoleBinding
16metadata:
17  name: provider-kubernetes-configmap-edit
18subjects:
19  - kind: ServiceAccount
20    name: provider-kubernetes
21    namespace: crossplane-system
22roleRef:
23  kind: ClusterRole
24  name: configmap-edit
25  apiGroup: rbac.authorization.k8s.io
26---
27apiVersion: kubernetes.crossplane.io/v1alpha1
28kind: ProviderConfig
29metadata:
30  name: default
31spec:
32  credentials:
33    source: InjectedIdentity
34EOF

Create a resource

After installing and configuring the provider with change logs enabled, create a resource that generates change log entries that reflect the actions the control plane takes.

 1cat <<EOF | kubectl apply -f -
 2apiVersion: kubernetes.crossplane.io/v1alpha2
 3kind: Object
 4metadata:
 5  name: configmap-for-changelogs
 6spec:
 7  forProvider:
 8    manifest:
 9      apiVersion: v1
10      kind: ConfigMap
11      metadata:
12        namespace: default
13        name: configmap-for-changelogs
14      data:
15        key-1: cool-value-1
16EOF

Examine the change logs

Confirm that the change logs include the resource creation operation. Examine the pod logs for provider-kubernetes, specifically the changelogs-sidecar container:

 1kubectl -n crossplane-system logs -l pkg.crossplane.io/provider=provider-kubernetes -c changelogs-sidecar | jq
 2{
 3  "timestamp": "2025-04-25T08:23:34Z",
 4  "provider": "provider-kubernetes:v0.18.0",
 5  "apiVersion": "kubernetes.crossplane.io/v1alpha2",
 6  "kind": "Object",
 7  "name": "configmap-for-changelogs",
 8  "externalName": "configmap-for-changelogs",
 9  "operation": "OPERATION_TYPE_CREATE",
10  "snapshot": {
11  ...(omitted for brevity)...

Each change log entry contains rich information about the state of the resource when the change operation occurred. Because each entry is a structured JSON object, you can filter and query them to find any subset of information that interests you:

1kubectl -n crossplane-system logs -l pkg.crossplane.io/provider=provider-kubernetes -c changelogs-sidecar \
2  | jq '.timestamp + " " + .provider + " " + .kind + " " + .name + " " + .operation'
3"2025-04-25T08:23:34Z provider-kubernetes:v0.18.0 Object configmap-for-changelogs OPERATION_TYPE_CREATE"

Full lifecycle operations

Update and delete operations also generate corresponding change log entries.

Update the resource by patching its data field key-1 with a new value cooler-value-2:

1kubectl patch object configmap-for-changelogs --type=json \
2  -p='[{"op": "replace", "path": "/spec/forProvider/manifest/data/key-1", "value": "cooler-value-2"}]'
3object.kubernetes.crossplane.io/configmap-for-changelogs patched

Then, delete the object entirely:

1kubectl delete object configmap-for-changelogs
2object.kubernetes.crossplane.io "configmap-for-changelogs" deleted

Check the change logs again to verify that they include both the update and delete operations and capture the object’s full lifecycle:

1kubectl -n crossplane-system logs -l pkg.crossplane.io/provider=provider-kubernetes -c changelogs-sidecar \
2  | jq '.timestamp + " " + .provider + " " + .kind + " " + .name + " " + .operation'
3"2025-04-25T08:23:34Z provider-kubernetes:v0.18.0 Object configmap-for-changelogs OPERATION_TYPE_CREATE"
4"2025-04-25T08:24:21Z provider-kubernetes:v0.18.0 Object configmap-for-changelogs OPERATION_TYPE_UPDATE"
5"2025-04-25T08:24:25Z provider-kubernetes:v0.18.0 Object configmap-for-changelogs OPERATION_TYPE_DELETE"