Skip to content

K8SPSMDB-1602: support Workload Identity for GCS backup storage#2315

Open
TineoC wants to merge 2 commits intopercona:mainfrom
TineoC:feat/gcs-workload-identity
Open

K8SPSMDB-1602: support Workload Identity for GCS backup storage#2315
TineoC wants to merge 2 commits intopercona:mainfrom
TineoC:feat/gcs-workload-identity

Conversation

@TineoC
Copy link
Copy Markdown

@TineoC TineoC commented Apr 16, 2026

Summary

  • Add credentials.workloadIdentity field to BackupStorageGCSSpec enabling GCS backups via GKE Workload Identity without exported service account keys
  • Modify PBM's newGoogleClient to fall back to Application Default Credentials (ADC) when no explicit credentials are provided
  • Make credentialsSecret optional when workload identity is enabled

Motivation

GKE environments using Workload Identity (Google's recommended approach) currently cannot use GCS backups because:

  1. The operator always reads credentialsSecret and passes clientEmail/privateKey to PBM
  2. PBM's newGoogleClient requires these fields and errors with: "clientEmail and privateKey are required for GCS credentials"
  3. Even when the pod's KSA is federated to a GSA with roles/storage.objectUser, PBM never tries ADC

This is blocking for IL4/FedRAMP environments where exporting service account JSON keys is not permitted.

Closes #2314

Changes

Operator API (pkg/apis/psmdb/v1/psmdb_types.go)

  • Add GCSCredentials struct with WorkloadIdentity bool field
  • Add Credentials *GCSCredentials to BackupStorageGCSSpec
  • Make CredentialsSecret tag omitempty

Operator Backup Logic (pkg/psmdb/backup/pbm.go)

  • When credentials.workloadIdentity: true, skip reading credentialsSecret
  • PBM receives empty credentials, triggering ADC fallback

PBM GCS Client (pbm/storage/gcs/google_client.go)

  • When ClientEmail and PrivateKey are both empty, use storagegcs.NewClient(ctx) (ADC) instead of erroring
  • Preserves backward compatibility: explicit credentials still take priority

Usage

spec:
  backup:
    storages:
      gcs-backup:
        type: gcs
        gcs:
          bucket: my-backup-bucket
          prefix: mongodb-backup
          credentials:
            workloadIdentity: true

Test plan

  • Existing unit tests pass (go test ./pkg/...)
  • GCS backup with explicit credentialsSecret still works (backward compat)
  • GCS backup with credentials.workloadIdentity: true on GKE with WI succeeds
  • GCS backup with no credentials and no WI annotation fails with clear error

🤖 Generated with Claude Code

Add support for GKE Workload Identity Federation when authenticating
with Google Cloud Storage for backups. This eliminates the requirement
for exported service account JSON keys (credentialsSecret).

Changes:
- Add GCSCredentials struct with WorkloadIdentity field to BackupStorageGCSSpec
- Make credentialsSecret optional (omitempty) when workloadIdentity is enabled
- Update GetPBMStorageGCSConfig to skip credential secret loading when WI is enabled
- Patch PBM's newGoogleClient to fall back to Application Default Credentials (ADC)
  when no explicit credentials are provided, enabling transparent GKE WI auth

When credentials.workloadIdentity is true in the CR:
  spec.backup.storages.gcs.credentials.workloadIdentity: true

The operator skips reading credentialsSecret and PBM authenticates via
the pod's Kubernetes Service Account, which is federated to a GCP SA
through GKE Workload Identity.

This aligns with PBM 2.13.0's native WIF support and Google's security
best practice of avoiding exported service account keys, which is
required for IL4/FedRAMP environments.

Closes: percona#2314
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 16, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@pull-request-size pull-request-size Bot added the size/XXL 1000+ lines label Apr 16, 2026
The PBM ADC fallback should be contributed separately to
percona/percona-backup-mongodb. This commit retains only the
operator API type changes (GCSCredentials struct) and the
backup logic to skip credential loading when WI is enabled.
@pull-request-size pull-request-size Bot added size/S 10-29 lines and removed size/XXL 1000+ lines labels Apr 16, 2026
@JNKPercona
Copy link
Copy Markdown
Collaborator

Test Name Result Time
arbiter passed 00:11:38
balancer passed 00:18:50
cross-site-sharded passed 00:19:08
custom-replset-name passed 00:13:03
custom-tls passed 00:14:49
custom-users-roles passed 00:10:44
custom-users-roles-sharded failure 00:10:35
data-at-rest-encryption passed 00:13:32
data-sharded passed 00:24:39
demand-backup passed 00:16:17
demand-backup-eks-credentials-irsa passed 00:00:08
demand-backup-fs passed 00:23:55
demand-backup-if-unhealthy failure 00:54:19
demand-backup-incremental-aws passed 00:12:20
demand-backup-incremental-azure passed 00:13:45
demand-backup-incremental-gcp-native passed 00:12:10
demand-backup-incremental-gcp-s3 passed 00:11:22
demand-backup-incremental-minio passed 00:27:15
demand-backup-incremental-sharded-aws passed 00:18:57
demand-backup-incremental-sharded-azure passed 00:17:43
demand-backup-incremental-sharded-gcp-native passed 00:17:18
demand-backup-incremental-sharded-gcp-s3 passed 00:17:39
demand-backup-incremental-sharded-minio passed 00:28:43
demand-backup-physical-parallel passed 00:09:06
demand-backup-physical-aws passed 00:12:37
demand-backup-physical-azure passed 00:12:18
demand-backup-physical-gcp-s3 passed 00:12:29
demand-backup-physical-gcp-native passed 00:11:53
demand-backup-physical-minio passed 00:21:28
demand-backup-physical-minio-native passed 00:27:05
demand-backup-physical-minio-native-tls passed 00:19:44
demand-backup-physical-sharded-parallel passed 00:11:22
demand-backup-physical-sharded-aws passed 00:21:15
demand-backup-physical-sharded-azure passed 00:18:01
demand-backup-physical-sharded-gcp-native passed 00:17:59
demand-backup-physical-sharded-minio passed 00:18:12
demand-backup-physical-sharded-minio-native passed 00:18:20
demand-backup-sharded passed 00:27:18
disabled-auth passed 00:16:20
expose-sharded passed 00:34:44
finalizer passed 00:10:21
ignore-labels-annotations passed 00:07:46
init-deploy passed 00:13:31
ldap passed 00:09:13
ldap-tls passed 00:13:19
limits passed 00:06:21
liveness passed 00:09:11
mongod-major-upgrade passed 00:13:17
mongod-major-upgrade-sharded passed 00:21:37
monitoring-2-0 passed 00:25:51
monitoring-pmm3 passed 00:26:00
multi-cluster-service passed 00:12:36
multi-storage passed 00:18:57
non-voting-and-hidden passed 00:16:56
one-pod passed 00:08:29
operator-self-healing-chaos passed 00:13:06
pitr passed 00:32:42
pitr-physical passed 01:01:30
pitr-sharded passed 00:23:02
pitr-to-new-cluster passed 00:25:58
pitr-physical-backup-source passed 00:54:25
preinit-updates passed 00:05:35
pvc-auto-resize passed 00:14:01
pvc-resize passed 00:17:22
recover-no-primary passed 00:28:43
replset-overrides failure 01:07:55
replset-remapping failure 00:53:05
replset-remapping-sharded failure 01:07:43
rs-shard-migration passed 00:14:59
scaling passed 00:11:16
scheduled-backup passed 00:18:04
security-context passed 00:07:17
self-healing-chaos passed 00:15:22
service-per-pod passed 00:19:18
serviceless-external-nodes passed 00:07:44
smart-update passed 00:08:50
split-horizon passed 00:14:30
stable-resource-version passed 00:04:50
storage passed 00:08:14
tls-issue-cert-manager passed 00:30:20
unsafe-psa passed 00:08:02
upgrade passed 00:12:54
upgrade-consistency passed 00:08:11
upgrade-consistency-sharded-tls passed 00:57:49
upgrade-sharded passed 00:19:46
upgrade-partial-backup failure 01:07:48
users passed 00:17:17
users-vault passed 00:13:30
version-service passed 00:25:30
Summary Value
Tests Run 89/89
Job Duration 04:13:25
Total Test Time 29:49:45

commit: 83c87ce
image: perconalab/percona-server-mongodb-operator:PR-2315-83c87ceca

Copy link
Copy Markdown
Member

@mayankshah1607 mayankshah1607 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for your PR. I believe we also need to add E2E tests for this

Comment thread pkg/psmdb/backup/pbm.go
Comment on lines +505 to +509
// When WorkloadIdentity is enabled, skip credential secret loading entirely.
// PBM will use Application Default Credentials (ADC) provided by GKE Workload Identity.
useWorkloadIdentity := stg.GCS.Credentials != nil && stg.GCS.Credentials.WorkloadIdentity

if !useWorkloadIdentity && stg.GCS.CredentialsSecret != "" {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add coverage for this in pbm_test.go

// When WorkloadIdentity is true, PBM uses Application Default Credentials (ADC)
// provided by GKE Workload Identity instead of a credentialsSecret.
type GCSCredentials struct {
WorkloadIdentity bool `json:"workloadIdentity,omitempty"`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it need to be embedded inside GCSCredentials object?

@egegunes egegunes changed the title feat(gcs): support Workload Identity for GCS backup storage K8SPSMDB-1602: support Workload Identity for GCS backup storage Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S 10-29 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support GCS Workload Identity in CRD (credentials.workloadIdentity) for backup storage

4 participants