Change Logs
This feature was introduced in v1.17.
For more information read the Crossplane feature lifecycle.
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.
Enabling change logs
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:
- A command line argument to the provider container that enables the change
logs feature, for example
--enable-changelogs. - A side car container that collects change events and produces change log entries to the provider’s pod logs.
- 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.
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:
- Set the
flag on the provider.--enable-changelogs - Add the
to the provider pod.sidecar container - Declare a
and mount it in theshared volume and theprovider container .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 and
instruct it to use the
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.
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"