Release Notes — v3.0.0
Overview
v3.0.0 is a major release with significant breaking changes. The most critical change is the removal of all previously-deprecated v1beta1 API versions, driven by a major upstream Terraform Google Provider version bump (v6.47.0 → v7.39.0). This release also ships a new Storage Version Migrator that must be run before upgrading if you are coming from v2.x or v1.x. Skipping the migration will leave CRDs in an inconsistent state and controllers will fail to start cleanly.
⚠️ Mandatory: Storage Version Migration
This step is required for all users upgrading from v1.x or v2.x.
This release removes v1beta1 API versions that were deprecated in prior releases. If you have existing managed resources stored in etcd under the old API version, the old version must be migrated to the current storage version before it can be removed from the CRD. Skipping this step will block API server from decoding objects correctly, causing reconciliation failures.
A built-in Storage Version Migrator is shipped in this release. It runs as an init container before the provider starts and automatically migrates all CRD objects to the current storage version.
How to apply
Apply the DeploymentRuntimeConfig included in the repository at examples/deploymentruntimeconfig-sv-migration.yaml before or alongside upgrading the provider package. You must update the image fields in the file to match the v3.0.0 package image you are deploying.
# Apply before or alongside the provider upgrade
# DeploymentRuntimeConfig that adds a storage version migration init container.
# Apply this before or alongside the Provider resource when upgrading from a
# release that carries v1beta1 CRDs to one where v1beta2 is the storage version.
#
# Reference it from your Provider via:
# spec:
# runtimeConfigRef:
# name: sv-migration
#
# NOTE: Do NOT apply this DRC to the family/config provider package. That
# package has no managed resources with version history and does not generate
# the init subcommand, so the init container would fail to start.
#
# The init container image must match the provider package image being deployed.
# Update the image tag whenever you upgrade the provider.
#
# RBAC NOTE:
# The init container runs under the provider's ServiceAccount. To fully
# complete the migration it needs permission to patch customresourcedefinitions/status
# (so it can remove the old version from status.storedVersions). This permission
# is not granted by Crossplane's RBAC manager by default.
#
# Without it, the object-level migration still succeeds (all v1beta1 objects
# are patched and re-stored as v1beta2), but status.storedVersions is not
# cleared. The init container logs a warning and continues rather than failing.
#
# To grant the missing permission, apply the ClusterRole and ClusterRoleBinding
# defined at the bottom of this file. They bind to the ServiceAccount whose
# name is fixed via spec.serviceAccountTemplate.metadata.name below ("sv-migration-sa").
# By pinning the SA name in the DRC we can pre-create the binding without
# knowing the ephemeral revision name that Crossplane would otherwise assign.
# Without this DRC, the SA would be named after the provider revision
# (e.g. provider-gcp-storage-abc1234) and would change on every upgrade.
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: sv-migration
spec:
serviceAccountTemplate:
metadata:
# Pinning the SA name makes the ClusterRoleBinding below stable across
# provider upgrades. Change this per sub-provider if needed.
name: sv-migration-sa
deploymentTemplate:
spec:
selector: {}
template:
spec:
containers:
- name: package-runtime
# Must match the provider package image being deployed.
image: xpkg.upbound.io/upbound/provider-gcp-storage:v3.0.0
args:
- --debug
initContainers:
- name: sv-migrator
# Must match the provider package image being deployed.
image: xpkg.upbound.io/upbound/provider-gcp-storage:v3.0.0
args:
- init
- --debug
securityContext:
runAsUser: 2000
runAsGroup: 2000
allowPrivilegeEscalation: false
privileged: false
runAsNonRoot: true
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
---
# ClusterRole granting permission to patch CRD status.
# Required for the init container to clear status.storedVersions after migration.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: provider-gcp-crd-status-patcher
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions/status"]
verbs: ["patch"]
---
# Binds the ClusterRole to the ServiceAccount named above.
# Adjust the namespace to match where Crossplane is installed
# (typically upbound-system or crossplane-system).
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: provider-gcp-crd-status-patcher
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: provider-gcp-crd-status-patcher
subjects:
- kind: ServiceAccount
name: sv-migration-sa
namespace: upbound-system
Then reference it from your Provider resource:
spec:
runtimeConfigRef:
name: sv-migrationImportant: Do NOT apply this DRC to the
provider-gcp-family/provider-gcp-configpackage. That package carries no managed resources and does not include theinitsubcommand — the init container would fail to start.
The RBAC resources bundled in the example file grant the init container permission to patch customresourcedefinitions/status, which is required to clear status.storedVersions. Adjust the namespace field in the ClusterRoleBinding to match your Crossplane installation namespace (typically upbound-system or crossplane-system).
Once migration is verified (check init container logs for per-CRD progress), you may remove the runtimeConfigRef and revert to your normal DeploymentRuntimeConfig.
See the upstream documentation for the full step-by-step guide:
Also see the MR API Versioning Policy.
Required Upgrade Path
Do not skip versions when upgrading to v3.0.0. The storage version migration is a multi-step process tied to the API versions present at each release.
Coming from v2.x
v2.x.y → v2.6.0 → v3.0.0
You must pass through v2.6.0 first. v2.6.0 introduced the v1beta2 storage version for resources that previously used v1beta1 as storage. Reaching v2.6.0 before v3.0.0 ensures all objects are written into v1beta2 while both API versions are still served; the storage version migrator in v3.0.0 then clears the v1beta1 entry from status.storedVersions before the version is removed.
Coming from v1.x
v1.x → v2.0.0 → v2.6.0 → v3.0.0
Rule of thumb: you must visit
v2.6.x(minimum v2.6.0) and then to v3.0.0.
Breaking Changes
1. Terraform Google Provider: v6.47.0 → v7.39.0
The underlying Terraform Google provider has been bumped by a full major version. This brings a large set of upstream schema changes that are reflected as API changes in the generated CRDs.
2. v1beta1 API Versions Removed
All v1beta1 API versions that were deprecated in prior releases have been permanently removed. Resources that only had a v1beta1 version have been deleted entirely. Resources that had multiple API versions (e.g. v1beta1 + v1beta2) retain their non-v1beta1 versions.
The following groups had one or more v1beta1 resources removed:
| Group | Affected resources (v1beta1 removed) |
|---|---|
accesscontextmanager |
AccessLevel, AccessLevelCondition, AccessPolicyIAMMember, ServicePerimeter |
alloydb |
Backup, Cluster, Instance |
apigee |
Environment, EnvironmentIAMMember, Organization |
appengine |
Application, ServiceNetworkSettings, StandardAppVersion |
artifact |
RegistryRepository, RegistryRepositoryIAMMember |
beyondcorp |
AppConnection, AppConnector |
bigquery |
AnalyticsHubDataExchangeIAMMember, AnalyticsHubListing, Connection, Dataset, DatasetAccess, DatasetIAMBinding, DatasetIAMMember, DataTransferConfig, Job, Reservation, Routine, Table, TableIAMBinding |
bigtable |
AppProfile, GarbageCollectionPolicy, Instance, InstanceIAMMember |
binaryauthorization |
Attestor, Policy |
certificatemanager |
Certificate |
cloudbuild |
Trigger, WorkerPool |
cloudfunctions |
Function, FunctionIAMMember |
cloudfunctions2 |
Function |
cloudplatform |
FolderIAMMember, OrganizationIAMMember, ProjectIAMMember, ServiceAccountIAMMember |
cloudrun |
DomainMapping, Service, ServiceIAMMember, V2Job, V2Service |
cloudscheduler |
Job |
cloudtasks |
Queue |
composer |
Environment |
compute |
Autoscaler, BackendBucket, BackendService, Disk, DiskIAMMember, Firewall, FirewallPolicyRule, ForwardingRule, GlobalForwardingRule, HealthCheck, Image, ImageIAMMember, Instance, InstanceFromTemplate, InstanceGroupManager, InstanceIAMMember, InstanceTemplate, ManagedSSLCertificate, NodeGroup, NodeTemplate, PacketMirroring, PerInstanceConfig, RegionAutoscaler, RegionBackendService, RegionDisk, RegionDiskIAMMember |
container |
Cluster, NodePool |
containeranalysis |
Note |
containerattached |
Cluster |
containeraws |
Cluster, NodePool |
containerazure |
Cluster, NodePool |
datacatalog |
Entry, EntryGroup, PolicyTag, Taxonomy |
datafusion |
Instance |
datalossprevention |
DeidentifyTemplate, InspectTemplate, JobTrigger, StoredInfoType |
dataplex |
Lake, Zone |
dataproc |
Cluster, MetastoreService |
datastream |
ConnectionProfile, PrivateConnection, Stream |
dialogflowcx |
Agent, EntityType, Flow, Intent, Page, Version, Webhook |
dns |
ManagedZone, RecordSet, ResponsePolicy |
eventarc |
Channel, GoogleChannelConfig, Trigger |
filestore |
Backup, Instance |
firebaserules |
Release, Ruleset |
gke |
BackupBackupPlan, BackupRestorePlan, HubMembership |
gkehub |
Feature, MembershipIAMMember |
healthcare |
DatasetIAMMember, DicomStore, FhirStore, Hl7V2Store |
iam |
WorkforcePool, WorkforcePoolProvider, WorkloadIdentityPool, WorkloadIdentityPoolProvider |
iap |
TunnelIAMMember, WebIAMMember |
identityplatform |
DefaultSupportedIdPConfig, TenantOAuthIdPConfig |
kms |
CryptoKey, CryptoKeyIAMMember, KeyRing, KeyRingIAMMember |
logging |
ProjectSink |
memcache |
Instance |
mlengine |
Model |
monitoring |
AlertPolicy, CustomService, MetricDescriptor, NotificationChannel, Service, SLO, UptimeCheckConfig |
networkconnectivity |
Spoke |
networkmanagement |
ConnectivityTest |
notebooks |
Environment, Instance, InstanceIAMMember, Runtime, RuntimeIAMMember |
osconfig |
OSPolicyAssignment, PatchDeployment |
privateca |
CAPool, CAPoolIAMMember, Certificate, CertificateAuthority, CertificateTemplate, CertificateTemplateIAMMember |
pubsub |
LiteSubscription, LiteTopic, Subscription, SubscriptionIAMMember, Topic, TopicIAMMember |
redis |
Instance |
secretmanager |
Secret, SecretIAMMember |
sourcerepo |
RepositoryIAMMember |
spanner |
Database, DatabaseIAMMember, Instance, InstanceIAMMember |
sql |
DatabaseInstance, User |
storage |
BucketIAMMember, BucketObject |
storagetransfer |
AgentPool |
tpu |
Node (entire CRD deleted — see below) |
vertexai |
Dataset, Featurestore, FeaturestoreEntityType, Tensorboard |
vpcaccess |
Connector |
3. tpu.Node — CRD Completely Deleted
The google_tpu_node resource was dropped from the upstream Terraform Google provider in v7.x. The tpu.Node CRD no longer exists. Any deployed tpu.Node resources will have no managing controller and must be manually cleaned up.
4. apigee.KeystoresAliasesKeyCertFile — Plugin Framework Migration
This resource was migrated to the Terraform Plugin Framework runtime. As a result:
certsInfois now computed-only and has been removed fromspec.forProviderandspec.initProvider.certsInfois now an array instatus.atProvider.
5. bigtable.TableIAMBinding, TableIAMMember, TableIAMPolicy — New API Versions
These resources have new API versions (v1beta3 for cluster-scoped, v1beta2 for namespaced). The field instance has been renamed to instanceName. Conversion webhooks handle the translation automatically, but ensure you are using the latest API version in your manifests.
6. compute.Disk, compute.RegionDisk — Sensitive Field Changes
The following fields became sensitive and were replaced with Secret references:
sourceImageEncryptionKey.rawKey→sourceImageEncryptionKey.rawKeySecretRefsourceSnapshotEncryptionKey.rawKey→sourceSnapshotEncryptionKey.rawKeySecretRef
If you have these fields set directly in spec.forProvider, you must migrate them to reference a Kubernetes Secret.
7. compute.Subnetwork — enableFlowLogs Removed
The enableFlowLogs field has been removed upstream. Use the dedicated logConfig block instead.
8. memorystore.Instance and redis.Cluster — allowFewerZonesDeployment Removed
The allowFewerZonesDeployment field has been removed from both resources upstream.
9. storage.Bucket — Storage Version Bumped to v1beta3, retentionPolicy Type Change
storage.Bucket is now at v1beta3 (cluster-scoped) / v1beta2 (namespaced). The retentionPolicy.retentionPeriod field type changed from a number to a string. Conversion functions handle this automatically across API versions.
10. storage.Notification — Plugin Framework Migration
This resource was migrated to the Terraform Plugin Framework runtime. There are no schema-level changes.
11. cloudfunctions2.Function — serviceConfig.service Becomes Computed-Only
serviceConfig.service is now computed-only and has been removed from spec.forProvider and spec.initProvider.
12. networkservices.Gateway — ports Optional, allPorts Introduced
ports is now optional. A new mutually-exclusive field allPorts has been introduced.
13. compute.VPNTunnel — sharedSecretSecretRef Becomes Optional
Previously required; now optional.
14. Write-Only Fields Removed (*_wo, *_wo_version)
All write-only variant fields (those suffixed with _wo or _wo_version) have been removed from resource schemas across all resources. These fields were never implemented for upjet-based providers and were a security concern as they stored values in plain text. This is a breaking API change for any resource that exposed these fields.
15. deletion_policy Field Suppressed on Most Resources
The upstream Terraform Google provider v7.33.0 introduced a deletion_policy field to many resources. To avoid inadvertent breaking CRD API changes, this field is centrally suppressed for all resources except the 24 resources that already exposed it prior to this bump. If a resource you rely on now has deletion_policy surfaced for the first time, and you are on a resource that was previously suppressing it, contact the maintainers.
New Features
Storage Version Migrator Init Container
Provider binaries now ship with an init subcommand that runs the storage version migration and exits, allowing normal provider startup to proceed without interference. This is orchestrated via a Kubernetes init container using a DeploymentRuntimeConfig. See the mandatory upgrade section above for details.
New Resources
networksecurity.DNSThreatDetector—google_network_security_dns_threat_detectorsupport added.firestore.Database,firestore.Index,firestore.Field— Full Firestore resource support added viagoogle_firestore_database,google_firestore_index,google_firestore_field.
ProviderConfig: userProjectOverride and billingProject
The ProviderConfig now supports two new fields for GCP quota management:
userProjectOverride— enables billing to a different project than where the identity was created.billingProject— specifies the billing project for quota purposes.
See the GCP provider quota management docs for details.
upjet_resource_external_api_calls_total Metric
A new Prometheus metric upjet_resource_external_api_calls_total is now exposed, counting outbound GCP API calls by HTTP operation and GCP service name. Useful for quota monitoring and observability of provider activity.
Conversion Webhook Decoupled from Leader Election
Conversion webhooks are now registered unconditionally before the canSafeStart gate, fixing a race condition where leader election could block conversion webhooks from starting. This resolves issues with multi-replica provider deployments.
GKE DNS Endpoint Kubeconfig Fix
When a GKE cluster is configured with DNS-based control plane endpoints (ipEndpointsConfig disabled), the cluster CA certificate is no longer pinned in the generated kubeconfig. DNS endpoints are served with publicly-trusted certificates; pinning the cluster CA caused TLS validation to fail. Clusters using IP endpoints are unaffected.
New Reference Field for compute.RegionBackendService
A resolver reference for security_policy has been added to compute.RegionBackendService.
compute.Cluster (container) — Additional Fields
The TF provider bump introduces several new fields on container.Cluster:
nodeConfig.sandboxConfignetworkConfig.subnetworkoncontainer.NodePoolmaintenanceExclusion.exclusionOptions.endTimeBehaviorenableK8SCertsViaDnsandenableK8STokensViaDns
sql.User — databaseRoles Field
databaseRoles field is now available on sql.User.
sql.DatabaseInstance — New Status Fields
ipAddress, status, and consumerNetworkStatus are now surfaced in status.atProvider on sql.DatabaseInstance.
compute.SSLCertificate — Write-Only Fields
privateKeySecretRef is now optional and write-only fields have been introduced for this resource.
Dependency Updates
| Dependency | New |
|---|---|
| Terraform Google Provider | v7.39.0 |
| Upjet | v2.4.1-0.20260728... |
| crossplane-runtime | v2.3.3 |
| crossplane/crossplane APIs | v2.3.4 |
Bug Fixes
compute.NetworkFirewallPolicyRule: Fixed aHTTP 400error that prevented creating a global network firewall policy rule when the rule did not already exist. (#909)container.Cluster(GKE DNS kubeconfig): Cluster CA is no longer pinned in the kubeconfig when the DNS endpoint is active, fixing TLS validation failures for clusters with IP endpoints disabled. (#991)
What's Changed
- Bump underlying TF provider version to v7.39.0 by @sergenyalcin in #960
- Decouple conversion webhook registration from leader election by @ulucinar in #961
- Add google_network_security_dns_threat_detector resource and add referencer for RegionBackendService.security_policy by @sergenyalcin in #962
- renovate: fix and refactor configuration by @erhancagirici in #964
- Remove write only fields from resource schemas by @sergenyalcin in #963
- Update actions/cache action to v6 by @renovate[bot] in #968
- Update actions/checkout action to v7 by @renovate[bot] in #969
- Update actions/setup-go action to v7 by @renovate[bot] in #970
- Update docker/setup-qemu-action digest to 96fe6ef by @renovate[bot] in #967
- Update actions/stale digest to 1e223db by @renovate[bot] in #966
- Update fkirc/skip-duplicate-actions action to v5.3.2 by @renovate[bot] in #972
- Update go module directive to v1.26.5 by @renovate[bot] in #973
- Update dependency crossplane/crossplane to v2.3.3 by @renovate[bot] in #971
- Pin crossplane-contrib/provider-workflows action to 451c4dc by @renovate[bot] in #941
- Integrate dynamic storage version migration by @sergenyalcin in #980
- Implement
upjet_resource_external_api_calls_totalmetric by @jonasz-lasut in #958 - Update crossplane-runtime to v2.3.3 by @jonasz-lasut in #984
- Replace --init flag with init subcommand by @sergenyalcin in #983
- Add some firestore resources by @ulrichgiraud in #939
- bump upjet to 4f6e6e10dff2 by @erhancagirici in #986
- Update actions/stale action to v11 by @renovate[bot] in #981
- Update module github.com/crossplane/crossplane/apis/v2 to v2.3.4 by @renovate[bot] in #989
- Update dependency crossplane/crossplane to v2.3.4 by @renovate[bot] in #978
- Support
userProjectOverride/billingProjecton the GCP ProviderConfig by @jonasz-lasut in #987 - fix(container): omit cluster CA from kubeconfig for DNS endpoint by @jonasz-lasut in #991
- fix:
NetworkFirewallPolicyRuleaddr.TerraformResource.Readfunction to handle HTTP 400 by @PhilipEkholm in #909 - Update alpine Docker tag to v3.24.1 by @renovate[bot] in #947
- Update dependency golangci/golangci-lint to v2.12.2 by @renovate[bot] in #975
- fix: external-name configuration for
Contact.essentialcontactsby @jonasz-lasut in #993 - fix(security): remediate CVE vulnerabilities by @ulucinar in #994
New Contributors
- @jonasz-lasut made their first contribution in #958
- @ulrichgiraud made their first contribution in #939
- @PhilipEkholm made their first contribution in #909
Full Changelog: v2.6.0...v3.0.0