Skip to content

Medusa backup to GCS with customer managed encryption keys (CMEK) enabled fails #1764

Description

@Avi-Walerius

Medusa backups to google cloud storage (GCS) fail when customer managed encryption keys (CMEK) are enabled on the GCS bucket.
ref - https://docs.cloud.google.com/kms/docs/cmek
The problem was identified in a k8ssandra-operator environment.

In the medusa.log, the backup part succeeds to send the files e.g.:

2026-08-04T09:06:35.552052061Z	[2026-08-04 09:06:35,551] INFO: Performing ASYNC backup medusa-04082026 (type=1)
...
2026-08-04T09:44:18.952785183Z	[2026-08-04 09:44:18,952] INFO: Backup done
2026-08-04T09:44:18.952836465Z	[2026-08-04 09:44:18,952] INFO: - Started: 2026-08-04 09:06:35
2026-08-04T09:44:18.952842928Z	                        - Started extracting data: 2026-08-04 09:06:38
2026-08-04T09:44:18.952848232Z	                        - Finished: 2026-08-04 09:44:18
2026-08-04T09:44:18.952854494Z	[2026-08-04 09:44:18,952] INFO: - Real duration: 0:37:40.733003 (excludes time waiting for other nodes)
2026-08-04T09:44:18.956190634Z	[2026-08-04 09:44:18,956] INFO: - 2320 files, 67.54 GB
2026-08-04T09:44:18.956219817Z	[2026-08-04 09:44:18,956] INFO: - 2320 files copied from host (2320 new, 0 reuploaded)

But later, we see this error:

2026-08-04T10:38:59.577719285Z	[2026-08-04 10:38:59,576] ERROR: Unexpected [AttributeError] raised by servicer method [/Medusa/GetBackups]
2026-08-04T10:38:59.577735418Z	Traceback (most recent call last):
  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 480, in __call__
    result = fn(*args, **kwargs)
2026-08-04T10:38:59.577753376Z	             ^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577773179Z	  File "/home/cassandra/medusa/storage/abstract_storage.py", line 82, in list_blobs
2026-08-04T10:38:59.577776340Z	    objects = loop.run_until_complete(self._list_blobs(prefix))
2026-08-04T10:38:59.577779413Z	              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577781727Z	  File "/usr/lib64/python3.12/asyncio/base_events.py", line 691, in run_until_complete
2026-08-04T10:38:59.577784095Z	    return future.result()
2026-08-04T10:38:59.577786395Z	           ^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577788971Z	  File "/home/cassandra/medusa/storage/google_storage.py", line 102, in _list_blobs
2026-08-04T10:38:59.577791471Z	    o['md5Hash'],
2026-08-04T10:38:59.577793737Z	    ~^^^^^^^^^^^
2026-08-04T10:38:59.577796054Z	KeyError: 'md5Hash'

2026-08-04T10:38:59.577800620Z	The above exception was the direct cause of the following exception:
2026-08-04T10:38:59.577802638Z	
2026-08-04T10:38:59.577804812Z	Traceback (most recent call last):
  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 480, in __call__
    result = fn(*args, **kwargs)
2026-08-04T10:38:59.577811801Z	             ^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577814240Z	  File "/home/cassandra/medusa/storage/abstract_storage.py", line 73, in list_objects
2026-08-04T10:38:59.577816493Z	    objects = self.list_blobs(prefix=path)
2026-08-04T10:38:59.577819124Z	              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577824853Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 338, in wrapped_f
2026-08-04T10:38:59.577827773Z	    return copy(f, *args, **kw)
2026-08-04T10:38:59.577830160Z	           ^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577833066Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 477, in __call__
2026-08-04T10:38:59.577835868Z	    do = self.iter(retry_state=retry_state)
2026-08-04T10:38:59.577838204Z	         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577842273Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 378, in iter
2026-08-04T10:38:59.577844874Z	    result = action(retry_state)
2026-08-04T10:38:59.577847078Z	             ^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577849461Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 421, in exc_check
2026-08-04T10:38:59.577851825Z	    raise retry_exc from fut.exception()
2026-08-04T10:38:59.577853999Z	tenacity.RetryError: RetryError[<Future at 0x7a7a78625760 state=finished raised KeyError>]

2026-08-04T10:38:59.577858275Z	The above exception was the direct cause of the following exception:
2026-08-04T10:38:59.577860326Z	
2026-08-04T10:38:59.577868733Z	Traceback (most recent call last):
  File "/home/cassandra/medusa/service/grpc/server.py", line 267, in GetBackups
    backups = get_backups(connected_storage, self.config, True)
2026-08-04T10:38:59.577874178Z	              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577875959Z	  File "/home/cassandra/medusa/listing.py", line 27, in get_backups
2026-08-04T10:38:59.577877648Z	    cluster_backups = sorted(
2026-08-04T10:38:59.577879381Z	                      ^^^^^^^
2026-08-04T10:38:59.577881201Z	  File "/home/cassandra/medusa/storage/__init__.py", line 363, in list_cluster_backups
2026-08-04T10:38:59.577882940Z	    node_backups = sorted(
2026-08-04T10:38:59.577884708Z	                   ^^^^^^^
2026-08-04T10:38:59.577886470Z	  File "/home/cassandra/medusa/storage/__init__.py", line 184, in list_node_backups
2026-08-04T10:38:59.577888457Z	    backup_index_blobs = self.list_backup_index_blobs()
2026-08-04T10:38:59.577890286Z	                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577892088Z	  File "/home/cassandra/medusa/storage/__init__.py", line 275, in list_backup_index_blobs
2026-08-04T10:38:59.577894298Z	    return self.storage_driver.list_objects(path)
2026-08-04T10:38:59.577896042Z	           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577897894Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 338, in wrapped_f
2026-08-04T10:38:59.577899648Z	    return copy(f, *args, **kw)
2026-08-04T10:38:59.577901329Z	           ^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577903103Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 477, in __call__
2026-08-04T10:38:59.577904825Z	    do = self.iter(retry_state=retry_state)
2026-08-04T10:38:59.577906600Z	         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577908495Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 378, in iter
2026-08-04T10:38:59.577911564Z	    result = action(retry_state)
2026-08-04T10:38:59.577913270Z	             ^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577915523Z	  File "/home/cassandra/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 421, in exc_check
2026-08-04T10:38:59.577917335Z	    raise retry_exc from fut.exception()
2026-08-04T10:38:59.577919922Z	tenacity.RetryError: RetryError[<Future at 0x7a7a787ce060 state=finished raised RetryError>]

2026-08-04T10:38:59.577925223Z	During handling of the above exception, another exception occurred:
2026-08-04T10:38:59.577927798Z	
2026-08-04T10:38:59.577930635Z	Traceback (most recent call last):
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 689, in grpc._cython.cygrpc._handle_exceptions
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 831, in _handle_rpc
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 554, in _handle_unary_unary_rpc
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 415, in _finish_handler_with_unary_response
  File "/usr/lib64/python3.12/concurrent/futures/thread.py", line 59, in run
    result = self.fn(*self.args, **self.kwargs)
2026-08-04T10:38:59.577988043Z	             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2026-08-04T10:38:59.577990471Z	  File "/home/cassandra/medusa/service/grpc/server.py", line 276, in GetBackups
2026-08-04T10:38:59.577992703Z	    response.status = medusa_pb2.StatusType.UNKNOWN
2026-08-04T10:38:59.577998639Z	    ^^^^^^^^^^^^^^^
2026-08-04T10:38:59.578000530Z	AttributeError: Protocol message GetBackupsResponse has no "status" field.

K8ssandra-operator log has:

026-08-04T10:38:59.578682002Z	2026-08-04T10:38:59.578Z	ERROR	failed to list backups	{"controller": "medusabackupjob", "controllerGroup": "medusa.k8ssandra.io", "controllerKind": "MedusaBackupJob", "MedusaBackupJob": {"name":"medusa-04082026","namespace":"k8ssandra-operator"}, "namespace": "k8ssandra-operator", "name": "medusa-04082026", "reconcileID": "e4a192bf-8a93-486e-a269-df2d7c862f46", "medusabackupjob": {"name":"medusa-04082026","namespace":"k8ssandra-operator"}, "CassandraPod": "cassandra-dev-dc1-r1-sts-0", "error": "failed to get backups: rpc error: code = Internal desc = Unexpected <class 'AttributeError'>: Protocol message GetBackupsResponse has no \"status\" field."}
2026-08-04T10:38:59.578719710Z	github.com/k8ssandra/k8ssandra-operator/controllers/medusa.(*MedusaBackupJobReconciler).getBackupSummary
2026-08-04T10:38:59.578724388Z		/workspace/controllers/medusa/medusabackupjob_controller.go:246
2026-08-04T10:38:59.578727122Z	github.com/k8ssandra/k8ssandra-operator/controllers/medusa.(*MedusaBackupJobReconciler).Reconcile
2026-08-04T10:38:59.578731352Z		/workspace/controllers/medusa/medusabackupjob_controller.go:191
2026-08-04T10:38:59.578734720Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile
2026-08-04T10:38:59.578737480Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:216
2026-08-04T10:38:59.578759194Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler
2026-08-04T10:38:59.578762132Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:461
2026-08-04T10:38:59.578764657Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem
2026-08-04T10:38:59.578768567Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:421
2026-08-04T10:38:59.578770957Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1.1
2026-08-04T10:38:59.578773521Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:296
2026-08-04T10:38:59.578780154Z	2026-08-04T10:38:59.578Z	ERROR	Failed to get backup summary	{"controller": "medusabackupjob", "controllerGroup": "medusa.k8ssandra.io", "controllerKind": "MedusaBackupJob", "MedusaBackupJob": {"name":"medusa-04082026","namespace":"k8ssandra-operator"}, "namespace": "k8ssandra-operator", "name": "medusa-04082026", "reconcileID": "e4a192bf-8a93-486e-a269-df2d7c862f46", "medusabackupjob": {"name":"medusa-04082026","namespace":"k8ssandra-operator"}, "error": "failed to get backups: rpc error: code = Internal desc = Unexpected <class 'AttributeError'>: Protocol message GetBackupsResponse has no \"status\" field."}
2026-08-04T10:38:59.578782504Z	github.com/k8ssandra/k8ssandra-operator/controllers/medusa.(*MedusaBackupJobReconciler).Reconcile
2026-08-04T10:38:59.578784804Z		/workspace/controllers/medusa/medusabackupjob_controller.go:193
2026-08-04T10:38:59.578787Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile
2026-08-04T10:38:59.578789245Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:216
2026-08-04T10:38:59.578791389Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler
2026-08-04T10:38:59.578793602Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:461
2026-08-04T10:38:59.578795809Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem
2026-08-04T10:38:59.578798047Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:421
2026-08-04T10:38:59.578800262Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1.1
2026-08-04T10:38:59.578813043Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:296
2026-08-04T10:38:59.578817688Z	2026-08-04T10:38:59.578Z	ERROR	Reconciler error	{"controller": "medusabackupjob", "controllerGroup": "medusa.k8ssandra.io", "controllerKind": "MedusaBackupJob", "MedusaBackupJob": {"name":"medusa-04082026","namespace":"k8ssandra-operator"}, "namespace": "k8ssandra-operator", "name": "medusa-04082026", "reconcileID": "e4a192bf-8a93-486e-a269-df2d7c862f46", "error": "failed to get backups: rpc error: code = Internal desc = Unexpected <class 'AttributeError'>: Protocol message GetBackupsResponse has no \"status\" field."}
2026-08-04T10:38:59.578819727Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler
2026-08-04T10:38:59.578821486Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:474
2026-08-04T10:38:59.578823247Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem
2026-08-04T10:38:59.578835266Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:421
2026-08-04T10:38:59.578837553Z	sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1.1
2026-08-04T10:38:59.578839388Z		/go/pkg/mod/sigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:296

According to:
https://docs.cloud.google.com/storage/docs/json_api/v1/objects/list
https://docs.cloud.google.com/storage/docs/json_api/v1/objects#resource

When CMEK is used, GCS api list does not include the md5hash, which I think the cause of the medusa error:
"MD5 hash of the data, encoded using base64. This field is not present for composite objects and objects encrypted with customer-managed encryption keys (CMEK). For more information about using the MD5 hash, see Data validation."

In k8ssandra-operator environment the result is that the medusabackup object is never created, which means the backup is not fully complete from k8ssandra-operator perspective and can not be restored.

Im not sure if this can be fixed only at medusa level or needs something at k8ssandra-operator as well, so opening here for now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions